pub mod edge_kind {
pub const ASSIGNMENT: u32 = 1 << 0;
pub const CALL_ARG: u32 = 1 << 1;
pub const RETURN: u32 = 1 << 2;
pub const PHI: u32 = 1 << 3;
pub const DOMINANCE: u32 = 1 << 4;
pub const ALIAS: u32 = 1 << 5;
pub const MEM_STORE: u32 = 1 << 6;
pub const MEM_LOAD: u32 = 1 << 7;
pub const MUT_REF: u32 = 1 << 8;
pub const CONTROL: u32 = 1 << 9;
pub const INDEX: u32 = 1 << 10;
pub const BASE: u32 = 1 << 11;
pub const INDUCTION_VARIABLE: u32 = 1 << 12;
pub const UPPER_BOUND: u32 = 1 << 13;
pub const FORMAT_STRING_ARG: u32 = 1 << 14;
pub const CALL_ARG_SLOT_BASE: u32 = 1 << 16;
pub const CALL_ARG_0: u32 = CALL_ARG_SLOT_BASE;
pub const CALL_ARG_1: u32 = CALL_ARG_SLOT_BASE << 1;
pub const CALL_ARG_2: u32 = CALL_ARG_SLOT_BASE << 2;
pub const CALL_ARG_3: u32 = CALL_ARG_SLOT_BASE << 3;
pub const CALL_ARG_4: u32 = CALL_ARG_SLOT_BASE << 4;
pub const CALL_ARG_5: u32 = CALL_ARG_SLOT_BASE << 5;
pub const CALL_ARG_6: u32 = CALL_ARG_SLOT_BASE << 6;
pub const CALL_ARG_7: u32 = CALL_ARG_SLOT_BASE << 7;
pub const CALL_ARG_MAX_SLOT: u32 = 7;
pub const SIZE_ARG: u32 = 1 << 24;
pub const BLOCK_MEMBER: u32 = 1 << 25;
#[must_use]
pub const fn call_arg_slot(n: u32) -> u32 {
if n > CALL_ARG_MAX_SLOT {
CALL_ARG
} else {
CALL_ARG_SLOT_BASE << n
}
}
}
pub mod tag_family {
pub const FUNCTION: u32 = 1 << 0;
pub const FILE: u32 = 1 << 1;
pub const PACKAGE: u32 = 1 << 2;
}
pub mod node_kind {
pub const VARIABLE: u32 = 1;
pub const CALL: u32 = 2;
pub const IMPORT: u32 = 3;
pub const LITERAL: u32 = 4;
pub const SSA: u32 = 5;
pub const BASIC_BLOCK: u32 = 6;
pub const BINARY: u32 = 7;
pub const FUNCTION_DECL: u32 = 8;
}
macro_rules! define_tag_family_predicate {
(
$module:ident,
$function:ident,
$op_id:literal,
$family:expr,
$fixture_tags:expr,
$expected_nodeset:expr,
$doc:literal
) => {
#[doc = $doc]
pub mod $module {
use vyre_foundation::ir::Program;
use crate::label::resolve_family::resolve_family;
pub const OP_ID: &str = $op_id;
#[must_use]
pub fn $function(node_tags: &str, nodeset_out: &str, node_count: u32) -> Program {
crate::program_region::tag_program(
OP_ID,
resolve_family(node_tags, nodeset_out, node_count, $family),
)
}
#[must_use]
#[cfg(any(test, feature = "cpu-parity"))]
pub fn cpu_ref(node_tags: &[u32]) -> Vec<u32> {
crate::label::resolve_family::cpu_ref(node_tags, $family)
}
#[cfg(feature = "inventory-registry")]
inventory::submit! {
crate::harness::OpEntry::new(
OP_ID,
|| $function("tags", "nodeset", 4),
Some(|| {
let to_bytes = crate::predicate::inventory_u32_le_bytes;
vec![vec![
to_bytes($fixture_tags),
to_bytes(&[0]),
]]
}),
Some(|| {
let to_bytes = crate::predicate::inventory_u32_le_bytes;
vec![vec![to_bytes($expected_nodeset)]]
}),
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cpu_ref_matches_inventory_fixture() {
assert_eq!(cpu_ref($fixture_tags), $expected_nodeset.to_vec());
}
}
}
};
}
macro_rules! define_fixed_forward_edge_predicate {
(
$module:ident,
$function:ident,
$op_id:literal,
$edge_mask:expr,
$edge_count:expr,
$fixture_edge_offsets:expr,
$fixture_edge_targets:expr,
$fixture_edge_masks:expr,
$expected_nodeset:expr,
$module_doc:literal,
$function_doc:literal,
$region_label:literal
) => {
#[doc = $module_doc]
pub mod $module {
use vyre_foundation::ir::Program;
use crate::graph::program_graph::ProgramGraphShape;
use crate::predicate::traversal::forward_edge_program;
#[cfg(any(test, feature = "cpu-parity"))]
use crate::predicate::traversal::{cpu_ref_forward, cpu_ref_forward_into};
pub const OP_ID: &str = $op_id;
#[doc = $function_doc]
#[must_use]
pub fn $function(
shape: ProgramGraphShape,
frontier_in: &str,
frontier_out: &str,
) -> Program {
forward_edge_program(OP_ID, shape, frontier_in, frontier_out, $edge_mask)
}
#[must_use]
#[cfg(any(test, feature = "cpu-parity"))]
pub fn cpu_ref(
node_count: u32,
edge_offsets: &[u32],
edge_targets: &[u32],
edge_kind_mask: &[u32],
frontier_in: &[u32],
) -> Vec<u32> {
cpu_ref_forward(
node_count,
edge_offsets,
edge_targets,
edge_kind_mask,
frontier_in,
$edge_mask,
)
}
#[cfg(any(test, feature = "cpu-parity"))]
pub fn cpu_ref_into(
node_count: u32,
edge_offsets: &[u32],
edge_targets: &[u32],
edge_kind_mask: &[u32],
frontier_in: &[u32],
out: &mut Vec<u32>,
) {
cpu_ref_forward_into(
node_count,
edge_offsets,
edge_targets,
edge_kind_mask,
frontier_in,
$edge_mask,
out,
);
}
#[cfg(feature = "inventory-registry")]
inventory::submit! {
crate::harness::OpEntry::new(
OP_ID,
|| $function(ProgramGraphShape::new(4, $edge_count), "fin", "fout"),
Some(|| {
let b = crate::predicate::inventory_u32_le_bytes;
vec![vec![
b(&[2, 1, 1, 1]),
b($fixture_edge_offsets),
b($fixture_edge_targets),
b($fixture_edge_masks),
b(&[0, 0, 0, 0]),
b(&[0b0001]),
b(&[0]),
]]
}),
Some(|| {
let b = crate::predicate::inventory_u32_le_bytes;
vec![vec![b($expected_nodeset)]]
}),
)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::predicate::traversal::assert_region_op_id;
#[test]
fn preserves_wrapper_op_id() {
let program = $function(ProgramGraphShape::new(4, $edge_count), "fin", "fout");
assert_region_op_id(&program, OP_ID, $region_label);
}
}
}
};
}
pub mod arg_of;
define_fixed_forward_edge_predicate!(
call_to,
call_to,
"vyre-primitives::predicate::call_to",
crate::predicate::edge_kind::CALL_ARG,
2,
&[0, 1, 2, 2, 2],
&[1, 2],
&[2, 2],
&[0b0010],
"`call_to` - forward-traverse along `CALL_ARG` edges.",
"Build a Program that emits the callee NodeSet reachable via `CallArg` edges from the input frontier.",
"call_to"
);
pub mod edge;
mod traversal;
define_tag_family_predicate!(
in_file,
in_file,
"vyre-primitives::predicate::in_file",
crate::predicate::tag_family::FILE,
&[2, 2, 0, 0],
&[0b0011],
"`in_file` - NodeSet of file-tagged nodes."
);
define_tag_family_predicate!(
in_function,
in_function,
"vyre-primitives::predicate::in_function",
crate::predicate::tag_family::FUNCTION,
&[1, 0, 1, 0],
&[0b0101],
"`in_function` - NodeSet of function-tagged nodes."
);
define_tag_family_predicate!(
in_package,
in_package,
"vyre-primitives::predicate::in_package",
crate::predicate::tag_family::PACKAGE,
&[4, 0, 4, 0],
&[0b0101],
"`in_package` - NodeSet of package-tagged nodes."
);
pub mod literal_of;
pub mod node_kind_eq;
define_fixed_forward_edge_predicate!(
return_value_of,
return_value_of,
"vyre-primitives::predicate::return_value_of",
crate::predicate::edge_kind::RETURN,
1,
&[0, 1, 1, 1, 1],
&[1],
&[4],
&[0b0010],
"`return_value_of` - forward-traverse along `RETURN` edges.",
"Build a Program that emits the NodeSet of return-value bindings reached from the caller frontier via `Return` edges.",
"return_value_of"
);
pub mod size_argument_of;
#[cfg(feature = "inventory-registry")]
pub(crate) fn inventory_u32_le_bytes(words: &[u32]) -> Vec<u8> {
crate::wire::pack_u32_slice(words)
}