use vyre_foundation::ir::{Expr, Node};
pub const MAX_CACHED_POSITIONS: u32 = 256;
pub const MAX_DEPTH: u32 = 12;
fn packed_load(buffer: &str, id: Expr, index: Expr) -> Expr {
Expr::load(
buffer,
Expr::add(Expr::mul(id, Expr::u32(MAX_CACHED_POSITIONS)), index),
)
}
#[must_use]
pub fn match_order(left_id: Expr, right_id: Expr, res_name: &str) -> (Vec<Node>, Expr) {
let mut block = Vec::new();
let limit_a = Expr::load("counts", left_id.clone());
let clamped_limit_a = Expr::select(
Expr::gt(limit_a.clone(), Expr::u32(MAX_CACHED_POSITIONS)),
Expr::u32(MAX_CACHED_POSITIONS),
limit_a,
);
let limit_b = Expr::load("counts", right_id.clone());
let clamped_limit_b = Expr::select(
Expr::gt(limit_b.clone(), Expr::u32(MAX_CACHED_POSITIONS)),
Expr::u32(MAX_CACHED_POSITIONS),
limit_b,
);
block.push(Node::let_bind(format!("{res_name}_len_a"), clamped_limit_a));
block.push(Node::let_bind(format!("{res_name}_len_b"), clamped_limit_b));
block.push(Node::let_bind(
format!("{res_name}_min_a_end"),
Expr::u32(u32::MAX),
));
let scan_a_loop = Node::loop_for(
"i",
Expr::u32(0),
Expr::var(format!("{res_name}_len_a").as_str()),
vec![
Node::let_bind(
"a_start",
packed_load("offsets", left_id.clone(), Expr::var("i")),
),
Node::let_bind(
"a_len",
packed_load("lengths", left_id.clone(), Expr::var("i")),
),
Node::let_bind("a_end", Expr::add(Expr::var("a_start"), Expr::var("a_len"))),
Node::assign(
format!("{res_name}_min_a_end"),
Expr::select(
Expr::lt(
Expr::var("a_end"),
Expr::var(format!("{res_name}_min_a_end")),
),
Expr::var("a_end"),
Expr::var(format!("{res_name}_min_a_end")),
),
),
],
);
block.push(scan_a_loop);
let max_b_start = Expr::select(
Expr::gt(
Expr::var(format!("{res_name}_len_b").as_str()),
Expr::u32(0),
),
packed_load(
"offsets",
right_id.clone(),
Expr::sub(
Expr::var(format!("{res_name}_len_b").as_str()),
Expr::u32(1),
),
),
Expr::u32(0),
);
block.push(Node::let_bind(
format!("{res_name}_max_b_start"),
max_b_start,
));
let both_non_empty = Expr::and(
Expr::gt(
Expr::var(format!("{res_name}_len_a").as_str()),
Expr::u32(0),
),
Expr::gt(
Expr::var(format!("{res_name}_len_b").as_str()),
Expr::u32(0),
),
);
block.push(Node::let_bind(
format!("{res_name}_found"),
Expr::select(
both_non_empty,
Expr::select(
Expr::le(
Expr::var(format!("{res_name}_min_a_end").as_str()),
Expr::var(format!("{res_name}_max_b_start").as_str()),
),
Expr::u32(1),
Expr::u32(0),
),
Expr::u32(0),
),
));
(block, Expr::var(format!("{res_name}_found")))
}