1#![allow(clippy::too_many_arguments)]
2
3use super::{try_loop_summarize_with_count, LoopSummarizeScratch};
4use crate::dispatch_input_cache::OwnedDispatchInputs;
5
6pub fn loop_summarize_via<F>(
7 dispatch: &F,
8 cfg_in: &[u32],
9 ranges_in: &[u32],
10 var_count: u32,
11) -> Result<Vec<u32>, String>
12where
13 F: Fn(&vyre::ir::Program, &[Vec<u8>], Option<[u32; 3]>) -> Result<Vec<Vec<u8>>, String>,
14{
15 let owned_inputs = OwnedDispatchInputs::new();
16 loop_summarize_borrowed_via(
17 &|program, inputs, grid| owned_inputs.dispatch(program, inputs, grid, dispatch),
18 cfg_in,
19 ranges_in,
20 var_count,
21 )
22}
23
24pub fn loop_summarize_borrowed_via<F>(
29 dispatch: &F,
30 cfg_in: &[u32],
31 ranges_in: &[u32],
32 var_count: u32,
33) -> Result<Vec<u32>, String>
34where
35 F: Fn(&vyre::ir::Program, &[&[u8]], Option<[u32; 3]>) -> Result<Vec<Vec<u8>>, String>,
36{
37 let mut scratch = LoopSummarizeScratch::default();
38 loop_summarize_borrowed_with_scratch_via(dispatch, cfg_in, ranges_in, var_count, &mut scratch)
39}
40
41pub fn loop_summarize_borrowed_with_scratch_via<F>(
44 dispatch: &F,
45 cfg_in: &[u32],
46 ranges_in: &[u32],
47 var_count: u32,
48 scratch: &mut LoopSummarizeScratch,
49) -> Result<Vec<u32>, String>
50where
51 F: Fn(&vyre::ir::Program, &[&[u8]], Option<[u32; 3]>) -> Result<Vec<Vec<u8>>, String>,
52{
53 let mut result = crate::staging_reserve::reserved_vec(
54 loop_summary_slots(var_count)?,
55 "loop summary result slot",
56 )?;
57 loop_summarize_borrowed_into_result_with_scratch_via(
58 dispatch,
59 cfg_in,
60 ranges_in,
61 var_count,
62 scratch,
63 &mut result,
64 )?;
65 Ok(result)
66}
67
68pub fn loop_summarize_borrowed_into_result_with_scratch_via<F>(
71 dispatch: &F,
72 cfg_in: &[u32],
73 ranges_in: &[u32],
74 var_count: u32,
75 scratch: &mut LoopSummarizeScratch,
76 result: &mut Vec<u32>,
77) -> Result<(), String>
78where
79 F: Fn(&vyre::ir::Program, &[&[u8]], Option<[u32; 3]>) -> Result<Vec<Vec<u8>>, String>,
80{
81 loop_summarize_staged_into_result_via(
82 &|program, inputs, grid, outputs| {
83 let result = dispatch(program, inputs, grid)?;
84 crate::output_scratch::replace_outputs_preserving_slots(outputs, result);
85 Ok(())
86 },
87 cfg_in,
88 ranges_in,
89 var_count,
90 &mut scratch.outputs,
91 &mut scratch.cfg_bytes,
92 &mut scratch.ranges_bytes,
93 &mut scratch.summary_bytes,
94 result,
95 )
96}
97
98pub fn loop_summarize_borrowed_into_via<F>(
101 dispatch: &F,
102 cfg_in: &[u32],
103 ranges_in: &[u32],
104 var_count: u32,
105 outputs: &mut Vec<Vec<u8>>,
106) -> Result<Vec<u32>, String>
107where
108 F: Fn(&vyre::ir::Program, &[&[u8]], Option<[u32; 3]>, &mut Vec<Vec<u8>>) -> Result<(), String>,
109{
110 let slots = loop_summary_slots(var_count)?;
111 let byte_len = slots.checked_mul(4).ok_or_else(|| {
112 "loop_summarize output byte length overflows host usize. Fix: shard loop summarization before GPU dispatch.".to_string()
113 })?;
114 let mut cfg_bytes = crate::staging_reserve::reserved_vec(byte_len, "loop summary CFG byte")?;
115 let mut ranges_bytes =
116 crate::staging_reserve::reserved_vec(byte_len, "loop summary range byte")?;
117 let mut summary_bytes =
118 crate::staging_reserve::reserved_vec(byte_len, "loop summary output byte")?;
119 let mut result = crate::staging_reserve::reserved_vec(slots, "loop summary result slot")?;
120 loop_summarize_staged_into_result_via(
121 dispatch,
122 cfg_in,
123 ranges_in,
124 var_count,
125 outputs,
126 &mut cfg_bytes,
127 &mut ranges_bytes,
128 &mut summary_bytes,
129 &mut result,
130 )?;
131 Ok(result)
132}
133
134fn loop_summary_slots(var_count: u32) -> Result<usize, String> {
135 crate::dispatch_decode::u32_to_usize(var_count, "loop_summarize variable count")?
136 .checked_mul(2)
137 .ok_or_else(|| {
138 format!(
139 "loop_summarize var_count={var_count} overflows host slot indexing. Fix: shard loop summarization before GPU dispatch."
140 )
141 })
142}
143
144fn loop_summarize_staged_into_result_via<F>(
145 dispatch: &F,
146 cfg_in: &[u32],
147 ranges_in: &[u32],
148 var_count: u32,
149 outputs: &mut Vec<Vec<u8>>,
150 cfg_bytes: &mut Vec<u8>,
151 ranges_bytes: &mut Vec<u8>,
152 summary_bytes: &mut Vec<u8>,
153 result: &mut Vec<u32>,
154) -> Result<(), String>
155where
156 F: Fn(&vyre::ir::Program, &[&[u8]], Option<[u32; 3]>, &mut Vec<Vec<u8>>) -> Result<(), String>,
157{
158 let slots = loop_summary_slots(var_count)?;
159 let program = try_loop_summarize_with_count("cfg", "ranges", "summary", var_count)?;
160 crate::dispatch_decode::pack_exact_u32_slots_into(
161 cfg_in,
162 slots,
163 "loop_summarize cfg",
164 cfg_bytes,
165 )?;
166 crate::dispatch_decode::pack_exact_u32_slots_into(
167 ranges_in,
168 slots,
169 "loop_summarize ranges",
170 ranges_bytes,
171 )?;
172 let summary_byte_len = slots.checked_mul(4).ok_or_else(|| {
173 "loop_summarize output byte length overflows host usize. Fix: shard loop summarization before GPU dispatch.".to_string()
174 })?;
175 crate::dispatch_decode::try_write_zero_bytes(
176 summary_bytes,
177 summary_byte_len,
178 "loop_summarize output zero staging",
179 )?;
180 let inputs = [
181 cfg_bytes.as_slice(),
182 ranges_bytes.as_slice(),
183 summary_bytes.as_slice(),
184 ];
185 dispatch(&program, &inputs, Some([var_count.max(1), 1, 1]), outputs)?;
186 crate::dispatch_decode::unpack_only_exact_u32_into(
187 outputs,
188 "loop_summarize",
189 "summary",
190 slots,
191 result,
192 )
193}