use super::gpu_directive_parse_shared::{
directive_program_from_parse, push_bounded_byte_scan_until, push_directive_row_bounds,
push_hash_and_keyword_start, push_keyword_end, push_ws_skip_from_expr,
safe_source_byte_expr as safe_load, DirectiveOutputColumn, DirectiveThreadLayout,
};
use crate::parsing::c::lex::tokens::{TOK_PP_INCLUDE, TOK_PP_INCLUDE_NEXT};
use vyre::ir::{Expr, Node, Program};
pub const OP_ID: &str = "vyre-libs::parsing::c::preprocess::gpu_include_parse_v2";
pub const BINDING_TOK_STARTS: u32 = 0;
pub const BINDING_TOK_LENS: u32 = 1;
pub const BINDING_DIRECTIVE_KINDS: u32 = 2;
pub const BINDING_SOURCE: u32 = 3;
pub const BINDING_PATH_START_OUT: u32 = 4;
pub const BINDING_PATH_LEN_OUT: u32 = 5;
pub const BINDING_IS_SYSTEM_OUT: u32 = 6;
const OUTPUT_COLUMNS: [DirectiveOutputColumn; 3] = [
DirectiveOutputColumn {
name: "path_start_out",
binding: BINDING_PATH_START_OUT,
},
DirectiveOutputColumn {
name: "path_len_out",
binding: BINDING_PATH_LEN_OUT,
},
DirectiveOutputColumn {
name: "is_system_out",
binding: BINDING_IS_SYSTEM_OUT,
},
];
#[must_use]
pub fn gpu_include_parse(num_tokens: u32, source_len: u32) -> Program {
let t = Expr::var("t");
let mut parse: Vec<Node> = Vec::new();
push_directive_row_bounds(&mut parse);
push_hash_and_keyword_start(&mut parse);
parse.push(Node::let_bind(
"kw_len_skip",
Expr::select(
Expr::eq(Expr::var("kind"), Expr::u32(TOK_PP_INCLUDE_NEXT)),
Expr::u32(12),
Expr::u32(7),
),
));
push_keyword_end(&mut parse, Expr::var("kw_len_skip"));
push_ws_skip_from_expr(
&mut parse,
"dp",
Expr::var("post_kw"),
"delim_skip",
"delim_pos",
);
parse.push(Node::let_bind(
"delim_byte",
safe_load(Expr::var("delim_pos")),
));
parse.push(Node::let_bind(
"is_angle",
Expr::select(
Expr::eq(Expr::var("delim_byte"), Expr::u32(b'<' as u32)),
Expr::u32(1),
Expr::u32(0),
),
));
parse.push(Node::let_bind(
"is_quote",
Expr::select(
Expr::eq(Expr::var("delim_byte"), Expr::u32(b'"' as u32)),
Expr::u32(1),
Expr::u32(0),
),
));
parse.push(Node::let_bind(
"valid_delim",
Expr::select(
Expr::or(
Expr::eq(Expr::var("is_angle"), Expr::u32(1)),
Expr::eq(Expr::var("is_quote"), Expr::u32(1)),
),
Expr::u32(1),
Expr::u32(0),
),
));
parse.push(Node::let_bind(
"close_byte",
Expr::select(
Expr::eq(Expr::var("is_angle"), Expr::u32(1)),
Expr::u32(b'>' as u32),
Expr::u32(b'"' as u32),
),
));
parse.push(Node::let_bind(
"path_start_val",
Expr::add(Expr::var("delim_pos"), Expr::u32(1)),
));
push_bounded_byte_scan_until(
&mut parse,
"path_i",
"path_start_val",
"path_scan_limit",
"path_byte",
"path_len_val",
"path_done",
Expr::var("close_byte"),
Expr::eq(Expr::u32(1), Expr::u32(1)),
);
parse.push(Node::if_then(
Expr::eq(
Expr::bitand(
Expr::bitand(Expr::var("found_hash"), Expr::var("valid_delim")),
Expr::var("path_done"),
),
Expr::u32(1),
),
vec![
Node::store("path_start_out", t.clone(), Expr::var("path_start_val")),
Node::store("path_len_out", t.clone(), Expr::var("path_len_val")),
Node::store("is_system_out", t.clone(), Expr::var("is_angle")),
],
));
directive_program_from_parse(
OP_ID,
num_tokens,
source_len,
&OUTPUT_COLUMNS,
DirectiveThreadLayout::WorkgroupLinear,
Expr::or(
Expr::eq(Expr::var("kind"), Expr::u32(TOK_PP_INCLUDE)),
Expr::eq(Expr::var("kind"), Expr::u32(TOK_PP_INCLUDE_NEXT)),
),
parse,
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn op_id_is_canonical_and_stable() {
assert_eq!(
OP_ID,
"vyre-libs::parsing::c::preprocess::gpu_include_parse_v2"
);
}
#[test]
fn build_program_returns_well_formed_program() {
let p = gpu_include_parse(8, 64);
assert_eq!(p.buffers().len(), 7);
assert_eq!(p.workgroup_size(), [256, 1, 1]);
}
}