Skip to main content

weir/loop_sum/
dispatch.rs

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
24/// GPU loop summarization using borrowed dispatch inputs.
25///
26/// Prefer this allocation-aware entrypoint when the caller can provide a
27/// borrowed-dispatch backend adapter.
28pub 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
41/// GPU loop summarization using borrowed dispatch inputs and caller-owned
42/// staging/output scratch.
43pub 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
68/// GPU loop summarization using caller-owned staging/output scratch and
69/// caller-owned decoded result storage.
70pub 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
98/// GPU loop summarization using borrowed dispatch inputs and caller-owned
99/// output storage.
100pub 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}