use vyre_foundation::ir::{Expr, Node};
use crate::graph::program_graph::{
ProgramGraphShape, NAME_EDGE_KIND_MASK, NAME_EDGE_OFFSETS, NAME_EDGE_TARGETS,
};
fn local_name(prefix: &str, n: &str) -> String {
if prefix.is_empty() {
n.to_string()
} else {
format!("{prefix}_{n}")
}
}
#[must_use]
pub(in crate::graph) fn csr_edge_expand_nodes(
shape: ProgramGraphShape,
frontier_out: &str,
src: Expr,
frontier_index: impl Fn(Expr) -> Expr,
on_new_bit: impl Fn() -> Vec<Node>,
edge_kind_mask: u32,
prefix: &str,
) -> Vec<Node> {
let name = |n: &str| local_name(prefix, n);
let edge_start = name("edge_start");
let edge_end = name("edge_end");
let edge_iter = name("e");
let kind_mask = name("kind_mask");
let dst = name("dst");
let dst_word_idx = name("dst_word_idx");
let dst_bit = name("dst_bit");
let old = name("old");
vec![
Node::let_bind(
edge_start.as_str(),
Expr::load(NAME_EDGE_OFFSETS, src.clone()),
),
Node::let_bind(
edge_end.as_str(),
Expr::load(NAME_EDGE_OFFSETS, Expr::add(src.clone(), Expr::u32(1))),
),
Node::loop_for(
edge_iter.as_str(),
Expr::var(edge_start.as_str()),
Expr::var(edge_end.as_str()),
vec![
Node::let_bind(
kind_mask.as_str(),
Expr::load(NAME_EDGE_KIND_MASK, Expr::var(edge_iter.as_str())),
),
Node::if_then(
Expr::ne(
Expr::bitand(Expr::var(kind_mask.as_str()), Expr::u32(edge_kind_mask)),
Expr::u32(0),
),
vec![
Node::let_bind(
dst.as_str(),
Expr::load(NAME_EDGE_TARGETS, Expr::var(edge_iter.as_str())),
),
Node::if_then(
Expr::lt(Expr::var(dst.as_str()), Expr::u32(shape.node_count)),
vec![
Node::let_bind(
dst_word_idx.as_str(),
frontier_index(Expr::shr(
Expr::var(dst.as_str()),
Expr::u32(5),
)),
),
Node::let_bind(
dst_bit.as_str(),
Expr::shl(
Expr::u32(1),
Expr::bitand(Expr::var(dst.as_str()), Expr::u32(31)),
),
),
Node::let_bind(
old.as_str(),
Expr::atomic_or(
frontier_out,
Expr::var(dst_word_idx.as_str()),
Expr::var(dst_bit.as_str()),
),
),
Node::if_then(
Expr::eq(
Expr::bitand(
Expr::var(old.as_str()),
Expr::var(dst_bit.as_str()),
),
Expr::u32(0),
),
on_new_bit(),
),
],
),
],
),
],
),
]
}
#[must_use]
pub(in crate::graph) fn csr_edge_scan_nodes(
shape: ProgramGraphShape,
frontier_out: &str,
src: Expr,
frontier_index: impl Fn(Expr) -> Expr,
on_new_bit: impl Fn() -> Vec<Node>,
edge_kind_mask: u32,
prefix: &str,
) -> Vec<Node> {
let name = |n: &str| local_name(prefix, n);
let word_idx = name("word_idx");
let bit_mask = name("bit_mask");
let src_word = name("src_word");
vec![
Node::let_bind(
word_idx.as_str(),
frontier_index(Expr::shr(src.clone(), Expr::u32(5))),
),
Node::let_bind(
bit_mask.as_str(),
Expr::shl(Expr::u32(1), Expr::bitand(src.clone(), Expr::u32(31))),
),
Node::let_bind(
src_word.as_str(),
Expr::load(frontier_out, Expr::var(word_idx.as_str())),
),
Node::if_then(
Expr::ne(
Expr::bitand(Expr::var(src_word.as_str()), Expr::var(bit_mask.as_str())),
Expr::u32(0),
),
csr_edge_expand_nodes(
shape,
frontier_out,
src,
frontier_index,
on_new_bit,
edge_kind_mask,
prefix,
),
),
]
}