use vyre_foundation::ir::{BufferDecl, Expr, Node, Program};
use crate::region::wrap;
pub(crate) struct ReducePhase {
pub(crate) accumulate: Node,
pub(crate) reductions: Vec<Node>,
pub(crate) publish: Vec<Node>,
}
pub(crate) struct TiledReduceProgram {
pub(crate) generator: &'static str,
pub(crate) buffers: Vec<BufferDecl>,
pub(crate) workgroup: [u32; 3],
pub(crate) phases: Vec<ReducePhase>,
pub(crate) writeback: Node,
}
pub(crate) fn tiled_reduce_program(spec: TiledReduceProgram) -> Program {
let TiledReduceProgram {
generator,
buffers,
workgroup,
phases,
writeback,
} = spec;
let mut body = vec![Node::let_bind("local", Expr::LocalId { axis: 0 })];
for phase in phases {
body.push(phase.accumulate);
body.push(Node::barrier());
body.extend(phase.reductions);
if !phase.publish.is_empty() {
body.push(Node::if_then(
Expr::and(
Expr::is_first_workgroup(),
Expr::eq(Expr::var("local"), Expr::u32(0)),
),
phase.publish,
));
body.push(Node::barrier());
}
}
body.push(writeback);
Program::wrapped(buffers, workgroup, vec![wrap(generator, body, None)])
}