use super::abi::{ifds_csr_dispatch_grid, IFDS_CSR_EMPTY_DISPATCH_GRID};
use super::layout::{
IfdsCsrLayout, IfdsCsrProgramCacheKey, IfdsCsrRuleInputFingerprint, IfdsCsrStaticInputKey,
};
use super::program_ir::build_ifds_csr_program;
use super::validation::validate_ifds_csr_inputs;
use vyre_foundation::ir::Program;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IfdsCsrDispatchPlan {
pub layout: IfdsCsrLayout,
pub program_key: IfdsCsrProgramCacheKey,
pub grid: [u32; 3],
pub intra_field_words: usize,
pub inter_field_words: usize,
pub gen_field_words: usize,
pub kill_field_words: usize,
pub row_ptr_words: usize,
pub row_cursor_words: usize,
pub killed_words: usize,
pub col_idx_words: usize,
pub col_len_words: usize,
pub max_col_count: u32,
}
impl IfdsCsrDispatchPlan {
#[must_use]
pub fn program(&self) -> Program {
build_ifds_csr_program(
self.layout.num_procs,
self.layout.blocks_per_proc,
self.layout.facts_per_proc,
self.layout.intra_count,
self.layout.inter_count,
self.layout.gen_count,
self.layout.kill_count,
self.layout.max_col_count,
)
}
#[must_use]
pub const fn program_cache_key(&self) -> IfdsCsrProgramCacheKey {
self.program_key
}
#[must_use]
pub const fn static_input_key(
&self,
rule_fingerprint: IfdsCsrRuleInputFingerprint,
) -> IfdsCsrStaticInputKey {
IfdsCsrStaticInputKey {
program_key: self.program_key,
rule_fingerprint,
}
}
}
pub fn plan_ifds_csr_dispatch(
num_procs: u32,
blocks_per_proc: u32,
facts_per_proc: u32,
intra_edges: &[(u32, u32, u32)],
inter_edges: &[(u32, u32, u32, u32)],
flow_gen: &[(u32, u32, u32)],
flow_kill: &[(u32, u32, u32)],
) -> Result<IfdsCsrDispatchPlan, String> {
let layout = validate_ifds_csr_inputs(
num_procs,
blocks_per_proc,
facts_per_proc,
intra_edges,
inter_edges,
flow_gen,
flow_kill,
)?;
Ok(IfdsCsrDispatchPlan {
intra_field_words: layout.intra_storage_words,
inter_field_words: layout.inter_storage_words,
gen_field_words: layout.gen_storage_words,
kill_field_words: layout.kill_storage_words,
row_ptr_words: layout.row_words,
row_cursor_words: layout.row_cursor_words,
killed_words: layout.killed_words,
col_idx_words: layout.col_buffer_words,
col_len_words: 1,
max_col_count: layout.max_col_count,
program_key: IfdsCsrProgramCacheKey::from_layout(&layout),
layout,
grid: if layout.empty {
IFDS_CSR_EMPTY_DISPATCH_GRID
} else {
ifds_csr_dispatch_grid(layout.intra_count, layout.total_nodes)
},
})
}
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct IfdsCsrRuleColumns {
pub intra_proc: Vec<u32>,
pub intra_src_block: Vec<u32>,
pub intra_dst_block: Vec<u32>,
pub inter_src_proc: Vec<u32>,
pub inter_src_block: Vec<u32>,
pub inter_dst_proc: Vec<u32>,
pub inter_dst_block: Vec<u32>,
pub gen_proc: Vec<u32>,
pub gen_block: Vec<u32>,
pub gen_fact: Vec<u32>,
pub kill_proc: Vec<u32>,
pub kill_block: Vec<u32>,
pub kill_fact: Vec<u32>,
}
impl IfdsCsrRuleColumns {
pub fn prepare(
&mut self,
intra_edges: &[(u32, u32, u32)],
inter_edges: &[(u32, u32, u32, u32)],
flow_gen: &[(u32, u32, u32)],
flow_kill: &[(u32, u32, u32)],
) -> Result<(), String> {
split_ifds_rule_triples_into(
intra_edges,
&mut self.intra_proc,
&mut self.intra_src_block,
&mut self.intra_dst_block,
"IFDS intra edge columns",
)?;
split_ifds_rule_quads_into(
inter_edges,
&mut self.inter_src_proc,
&mut self.inter_src_block,
&mut self.inter_dst_proc,
&mut self.inter_dst_block,
"IFDS inter edge columns",
)?;
split_ifds_rule_triples_into(
flow_gen,
&mut self.gen_proc,
&mut self.gen_block,
&mut self.gen_fact,
"IFDS GEN columns",
)?;
split_ifds_rule_triples_into(
flow_kill,
&mut self.kill_proc,
&mut self.kill_block,
&mut self.kill_fact,
"IFDS KILL columns",
)
}
}
pub fn split_ifds_rule_triples_into(
triples: &[(u32, u32, u32)],
first: &mut Vec<u32>,
second: &mut Vec<u32>,
third: &mut Vec<u32>,
context: &str,
) -> Result<(), String> {
first.clear();
second.clear();
third.clear();
crate::graph::scratch::reserve_graph_items(
first,
triples.len(),
"exploded IFDS primitive",
context,
)?;
crate::graph::scratch::reserve_graph_items(
second,
triples.len(),
"exploded IFDS primitive",
context,
)?;
crate::graph::scratch::reserve_graph_items(
third,
triples.len(),
"exploded IFDS primitive",
context,
)?;
for &(a, b, c) in triples {
first.push(a);
second.push(b);
third.push(c);
}
Ok(())
}
pub fn split_ifds_rule_quads_into(
quads: &[(u32, u32, u32, u32)],
first: &mut Vec<u32>,
second: &mut Vec<u32>,
third: &mut Vec<u32>,
fourth: &mut Vec<u32>,
context: &str,
) -> Result<(), String> {
first.clear();
second.clear();
third.clear();
fourth.clear();
crate::graph::scratch::reserve_graph_items(
first,
quads.len(),
"exploded IFDS primitive",
context,
)?;
crate::graph::scratch::reserve_graph_items(
second,
quads.len(),
"exploded IFDS primitive",
context,
)?;
crate::graph::scratch::reserve_graph_items(
third,
quads.len(),
"exploded IFDS primitive",
context,
)?;
crate::graph::scratch::reserve_graph_items(
fourth,
quads.len(),
"exploded IFDS primitive",
context,
)?;
for &(a, b, c, d) in quads {
first.push(a);
second.push(b);
third.push(c);
fourth.push(d);
}
Ok(())
}