1use std::sync::Arc;
2
3use super::OP_ID;
4use vyre::ir::{BufferAccess, BufferDecl, DataType, Expr, Ident, Node, Program};
5
6#[must_use]
11pub fn loop_summarize(cfg_in: &str, ranges_in: &str, summary_out: &str) -> Program {
12 loop_summarize_with_slots(cfg_in, ranges_in, summary_out, 4, 8)
13}
14
15pub fn try_loop_summarize_with_count(
22 cfg_in: &str,
23 ranges_in: &str,
24 summary_out: &str,
25 var_count: u32,
26) -> Result<Program, String> {
27 let slots = var_count.checked_mul(2).ok_or_else(|| {
28 format!(
29 "loop_summarize var_count={var_count} overflows u32 buffer slots. Fix: shard loop summarization before building the GPU Program."
30 )
31 })?.max(1);
32 Ok(loop_summarize_with_slots(
33 cfg_in,
34 ranges_in,
35 summary_out,
36 var_count,
37 slots,
38 ))
39}
40
41#[must_use]
43#[cfg(any(test, feature = "legacy-infallible"))]
44pub fn loop_summarize_with_count(
45 cfg_in: &str,
46 ranges_in: &str,
47 summary_out: &str,
48 var_count: u32,
49) -> Program {
50 let slots = var_count.checked_mul(2).unwrap_or_else(|| {
51 panic!(
52 "loop_summarize var_count={var_count} overflows u32 buffer slots. Fix: call try_loop_summarize_with_count and shard loop summarization before building the GPU Program."
53 )
54 }).max(1);
55 loop_summarize_with_slots(cfg_in, ranges_in, summary_out, var_count, slots)
56}
57
58fn loop_summarize_with_slots(
59 cfg_in: &str,
60 ranges_in: &str,
61 summary_out: &str,
62 var_count: u32,
63 slots: u32,
64) -> Program {
65 let v = Expr::InvocationId { axis: 0 };
66 const NEG_INF: u32 = 0;
67 const POS_INF: u32 = u32::MAX;
68
69 let body = vec![
70 Node::let_bind("lo_idx", Expr::mul(v.clone(), Expr::u32(2))),
71 Node::let_bind("hi_idx", Expr::add(Expr::var("lo_idx"), Expr::u32(1))),
72 Node::let_bind("prev_lo", Expr::load(cfg_in, Expr::var("lo_idx"))),
73 Node::let_bind("prev_hi", Expr::load(cfg_in, Expr::var("hi_idx"))),
74 Node::let_bind("new_lo", Expr::load(ranges_in, Expr::var("lo_idx"))),
75 Node::let_bind("new_hi", Expr::load(ranges_in, Expr::var("hi_idx"))),
76 Node::let_bind(
79 "wide_lo",
80 Expr::select(
81 Expr::lt(Expr::var("new_lo"), Expr::var("prev_lo")),
82 Expr::u32(NEG_INF),
83 Expr::var("prev_lo"),
84 ),
85 ),
86 Node::let_bind(
89 "wide_hi",
90 Expr::select(
91 Expr::lt(Expr::var("prev_hi"), Expr::var("new_hi")),
92 Expr::u32(POS_INF),
93 Expr::var("prev_hi"),
94 ),
95 ),
96 Node::store(summary_out, Expr::var("lo_idx"), Expr::var("wide_lo")),
97 Node::store(summary_out, Expr::var("hi_idx"), Expr::var("wide_hi")),
98 ];
99
100 let buffers = vec![
101 BufferDecl::storage(cfg_in, 0, BufferAccess::ReadOnly, DataType::U32).with_count(slots),
102 BufferDecl::storage(ranges_in, 1, BufferAccess::ReadOnly, DataType::U32).with_count(slots),
103 BufferDecl::storage(summary_out, 2, BufferAccess::ReadWrite, DataType::U32)
104 .with_count(slots),
105 ];
106
107 Program::wrapped(
108 buffers,
109 [256, 1, 1],
110 vec![Node::Region {
111 generator: Ident::from(OP_ID),
112 source_region: None,
113 body: Arc::new(vec![Node::if_then(
114 Expr::lt(v.clone(), Expr::u32(var_count)),
115 body,
116 )]),
117 }],
118 )
119}