1use super::abi::{ifds_csr_dispatch_grid, IFDS_CSR_EMPTY_DISPATCH_GRID};
2use super::layout::{
3 IfdsCsrLayout, IfdsCsrProgramCacheKey, IfdsCsrRuleInputFingerprint, IfdsCsrStaticInputKey,
4};
5use super::program_ir::build_ifds_csr_program;
6use super::validation::validate_ifds_csr_inputs;
7use vyre_foundation::ir::Program;
8
9#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct IfdsCsrDispatchPlan {
16 pub layout: IfdsCsrLayout,
18 pub program_key: IfdsCsrProgramCacheKey,
20 pub grid: [u32; 3],
22 pub intra_field_words: usize,
24 pub inter_field_words: usize,
26 pub gen_field_words: usize,
28 pub kill_field_words: usize,
30 pub row_ptr_words: usize,
32 pub row_cursor_words: usize,
34 pub killed_words: usize,
36 pub col_idx_words: usize,
38 pub col_len_words: usize,
40 pub max_col_count: u32,
42}
43
44impl IfdsCsrDispatchPlan {
45 #[must_use]
47 pub fn program(&self) -> Program {
48 build_ifds_csr_program(
49 self.layout.num_procs,
50 self.layout.blocks_per_proc,
51 self.layout.facts_per_proc,
52 self.layout.intra_count,
53 self.layout.inter_count,
54 self.layout.gen_count,
55 self.layout.kill_count,
56 self.layout.max_col_count,
57 )
58 }
59
60 #[must_use]
62 pub const fn program_cache_key(&self) -> IfdsCsrProgramCacheKey {
63 self.program_key
64 }
65
66 #[must_use]
68 pub const fn static_input_key(
69 &self,
70 rule_fingerprint: IfdsCsrRuleInputFingerprint,
71 ) -> IfdsCsrStaticInputKey {
72 IfdsCsrStaticInputKey {
73 program_key: self.program_key,
74 rule_fingerprint,
75 }
76 }
77}
78pub fn plan_ifds_csr_dispatch(
80 num_procs: u32,
81 blocks_per_proc: u32,
82 facts_per_proc: u32,
83 intra_edges: &[(u32, u32, u32)],
84 inter_edges: &[(u32, u32, u32, u32)],
85 flow_gen: &[(u32, u32, u32)],
86 flow_kill: &[(u32, u32, u32)],
87) -> Result<IfdsCsrDispatchPlan, String> {
88 let layout = validate_ifds_csr_inputs(
89 num_procs,
90 blocks_per_proc,
91 facts_per_proc,
92 intra_edges,
93 inter_edges,
94 flow_gen,
95 flow_kill,
96 )?;
97 Ok(IfdsCsrDispatchPlan {
98 intra_field_words: layout.intra_storage_words,
99 inter_field_words: layout.inter_storage_words,
100 gen_field_words: layout.gen_storage_words,
101 kill_field_words: layout.kill_storage_words,
102 row_ptr_words: layout.row_words,
103 row_cursor_words: layout.row_cursor_words,
104 killed_words: layout.killed_words,
105 col_idx_words: layout.col_buffer_words,
106 col_len_words: 1,
107 max_col_count: layout.max_col_count,
108 program_key: IfdsCsrProgramCacheKey::from_layout(&layout),
109 layout,
110 grid: if layout.empty {
111 IFDS_CSR_EMPTY_DISPATCH_GRID
112 } else {
113 ifds_csr_dispatch_grid(layout.intra_count, layout.total_nodes)
114 },
115 })
116}
117
118#[derive(Debug, Default, Clone, PartialEq, Eq)]
125pub struct IfdsCsrRuleColumns {
126 pub intra_proc: Vec<u32>,
128 pub intra_src_block: Vec<u32>,
130 pub intra_dst_block: Vec<u32>,
132 pub inter_src_proc: Vec<u32>,
134 pub inter_src_block: Vec<u32>,
136 pub inter_dst_proc: Vec<u32>,
138 pub inter_dst_block: Vec<u32>,
140 pub gen_proc: Vec<u32>,
142 pub gen_block: Vec<u32>,
144 pub gen_fact: Vec<u32>,
146 pub kill_proc: Vec<u32>,
148 pub kill_block: Vec<u32>,
150 pub kill_fact: Vec<u32>,
152}
153
154impl IfdsCsrRuleColumns {
155 pub fn prepare(
163 &mut self,
164 intra_edges: &[(u32, u32, u32)],
165 inter_edges: &[(u32, u32, u32, u32)],
166 flow_gen: &[(u32, u32, u32)],
167 flow_kill: &[(u32, u32, u32)],
168 ) -> Result<(), String> {
169 split_ifds_rule_triples_into(
170 intra_edges,
171 &mut self.intra_proc,
172 &mut self.intra_src_block,
173 &mut self.intra_dst_block,
174 "IFDS intra edge columns",
175 )?;
176 split_ifds_rule_quads_into(
177 inter_edges,
178 &mut self.inter_src_proc,
179 &mut self.inter_src_block,
180 &mut self.inter_dst_proc,
181 &mut self.inter_dst_block,
182 "IFDS inter edge columns",
183 )?;
184 split_ifds_rule_triples_into(
185 flow_gen,
186 &mut self.gen_proc,
187 &mut self.gen_block,
188 &mut self.gen_fact,
189 "IFDS GEN columns",
190 )?;
191 split_ifds_rule_triples_into(
192 flow_kill,
193 &mut self.kill_proc,
194 &mut self.kill_block,
195 &mut self.kill_fact,
196 "IFDS KILL columns",
197 )
198 }
199}
200
201fn prepare_ifds_rule_columns(
202 columns: &mut [&mut Vec<u32>],
203 rule_count: usize,
204 context: &str,
205) -> Result<(), String> {
206 for column in columns {
207 column.clear();
208 crate::graph::scratch::reserve_graph_items(
209 column,
210 rule_count,
211 "exploded IFDS primitive",
212 context,
213 )?;
214 }
215 Ok(())
216}
217fn split_ifds_rules_into<const WIDTH: usize, Rule: Copy>(
218 rules: &[Rule],
219 mut columns: [&mut Vec<u32>; WIDTH],
220 fields: impl Fn(Rule) -> [u32; WIDTH],
221 context: &str,
222) -> Result<(), String> {
223 prepare_ifds_rule_columns(&mut columns, rules.len(), context)?;
224 for &rule in rules {
225 for (column, value) in columns.iter_mut().zip(fields(rule)) {
226 column.push(value);
227 }
228 }
229 Ok(())
230}
231
232pub fn split_ifds_rule_triples_into(
242 triples: &[(u32, u32, u32)],
243 first: &mut Vec<u32>,
244 second: &mut Vec<u32>,
245 third: &mut Vec<u32>,
246 context: &str,
247) -> Result<(), String> {
248 split_ifds_rules_into(
249 triples,
250 [first, second, third],
251 |(a, b, c)| [a, b, c],
252 context,
253 )
254}
255
256pub fn split_ifds_rule_quads_into(
263 quads: &[(u32, u32, u32, u32)],
264 first: &mut Vec<u32>,
265 second: &mut Vec<u32>,
266 third: &mut Vec<u32>,
267 fourth: &mut Vec<u32>,
268 context: &str,
269) -> Result<(), String> {
270 split_ifds_rules_into(
271 quads,
272 [first, second, third, fourth],
273 |(a, b, c, d)| [a, b, c, d],
274 context,
275 )
276}