pub mod aos_to_soa_promote;
pub mod bank_conflict_pad;
pub mod branch_collapse;
pub mod canonicalize;
pub mod const_buffer_promote;
pub mod dead_store;
pub mod descriptor_const_fold;
pub mod descriptor_cse;
pub mod descriptor_dce;
pub mod drop_unused_bindings;
pub mod drop_unused_child_bodies;
pub mod drop_unused_literals;
pub mod identity_elim;
pub mod licm;
pub mod load_forwarding;
pub mod loop_unroll;
pub mod matmul_promote;
pub mod shared_mem_promote;
pub mod strength_reduce;
pub mod tail_mask;
pub use aos_to_soa_promote::{promote as aos_to_soa_promote, LayoutHint as AosSoaLayoutHint};
pub use bank_conflict_pad::bank_conflict_pad;
pub use branch_collapse::branch_collapse;
pub use canonicalize::canonicalize;
pub use const_buffer_promote::const_buffer_promote;
pub use dead_store::dead_store;
pub use descriptor_const_fold::descriptor_const_fold;
pub use descriptor_cse::descriptor_cse;
pub use descriptor_dce::descriptor_dce;
pub use drop_unused_bindings::drop_unused_bindings;
pub use drop_unused_child_bodies::drop_unused_child_bodies;
pub use drop_unused_literals::drop_unused_literals;
pub use identity_elim::identity_elim;
pub use licm::licm;
pub use load_forwarding::load_forwarding;
pub use loop_unroll::loop_unroll;
pub use matmul_promote::{infer_matmul_tile_loops, matmul_promote, MatmulTileLoopPlan};
pub use shared_mem_promote::shared_mem_promote;
pub use strength_reduce::strength_reduce;
pub use tail_mask::apply_tail_mask;
#[must_use]
pub fn run_all_once(desc: &crate::KernelDescriptor) -> crate::KernelDescriptor {
let reduced = strength_reduce(desc);
let shared_promoted = shared_mem_promote(&reduced);
let padded = bank_conflict_pad(&shared_promoted);
let const_promoted = const_buffer_promote(&padded);
let folded = descriptor_const_fold(&const_promoted);
let identified = identity_elim(&folded);
let collapsed = branch_collapse(&identified);
let unrolled = loop_unroll(&collapsed);
let hoisted = licm(&unrolled);
let forwarded = load_forwarding(&hoisted);
let cleaned = descriptor_dce(&forwarded);
let dse_done = dead_store(&cleaned);
let dced = descriptor_dce(&dse_done);
let canon = canonicalize(&dced);
let merged = descriptor_cse(&canon);
let pruned_bindings = drop_unused_bindings(&merged);
let pruned_literals = drop_unused_literals(&pruned_bindings);
drop_unused_child_bodies(&pruned_literals)
}
pub const RUN_ALL_MAX_ITERS: usize = 4;
#[must_use]
pub fn run_all(desc: &crate::KernelDescriptor) -> crate::KernelDescriptor {
run_all_with_stats(desc).0
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct OptimizationStats {
pub ops_before: usize,
pub ops_after: usize,
pub bindings_before: usize,
pub bindings_after: usize,
pub literals_before: usize,
pub literals_after: usize,
pub iterations: usize,
pub converged: bool,
}
impl OptimizationStats {
pub fn ops_eliminated(&self) -> usize {
self.ops_before.saturating_sub(self.ops_after)
}
pub fn bindings_dropped(&self) -> usize {
self.bindings_before.saturating_sub(self.bindings_after)
}
pub fn is_no_op(&self) -> bool {
self.ops_before == self.ops_after
&& self.bindings_before == self.bindings_after
&& self.literals_before == self.literals_after
}
pub fn off_graph_dropped(&self) -> usize {
self.bindings_dropped() + self.literals_before.saturating_sub(self.literals_after)
}
pub fn merge(&mut self, other: OptimizationStats) {
self.ops_before = self.ops_before.saturating_add(other.ops_before);
self.ops_after = self.ops_after.saturating_add(other.ops_after);
self.bindings_before = self.bindings_before.saturating_add(other.bindings_before);
self.bindings_after = self.bindings_after.saturating_add(other.bindings_after);
self.literals_before = self.literals_before.saturating_add(other.literals_before);
self.literals_after = self.literals_after.saturating_add(other.literals_after);
self.iterations = self.iterations.saturating_add(other.iterations);
self.converged = self.converged && other.converged;
}
pub fn zero() -> Self {
OptimizationStats {
ops_before: 0,
ops_after: 0,
bindings_before: 0,
bindings_after: 0,
literals_before: 0,
literals_after: 0,
iterations: 0,
converged: true,
}
}
pub fn format_short(&self) -> String {
format!(
"ops {}→{} (-{}), bindings {}→{} (-{}), iters {} ({})",
self.ops_before,
self.ops_after,
self.ops_eliminated(),
self.bindings_before,
self.bindings_after,
self.bindings_dropped(),
self.iterations,
if self.converged {
"converged"
} else {
"stopped"
},
)
}
}
impl std::fmt::Display for OptimizationStats {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.format_short())
}
}
#[must_use]
pub fn run_all_with_stats(
desc: &crate::KernelDescriptor,
) -> (crate::KernelDescriptor, OptimizationStats) {
let ops_before = desc.body.ops.len();
let bindings_before = desc.bindings.slots.len();
let literals_before = desc.body.literals.len();
let mut current = run_all_once(desc);
let mut iterations = 1usize;
let mut converged = current == *desc;
while !converged && iterations < RUN_ALL_MAX_ITERS {
let next = run_all_once(¤t);
iterations += 1;
converged = next == current;
current = next;
}
let stats = OptimizationStats {
ops_before,
ops_after: current.body.ops.len(),
bindings_before,
bindings_after: current.bindings.slots.len(),
literals_before,
literals_after: current.body.literals.len(),
iterations,
converged,
};
(current, stats)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
BindingLayout, Dispatch, KernelBody, KernelDescriptor, KernelOp, KernelOpKind, LiteralValue,
};
#[test]
fn run_all_on_empty_kernel_returns_empty() {
let desc = KernelDescriptor {
id: "k".into(),
bindings: BindingLayout { slots: vec![] },
dispatch: Dispatch::new(1, 1, 1),
body: KernelBody {
ops: vec![],
child_bodies: vec![],
literals: vec![],
},
};
let out = run_all(&desc);
assert!(out.body.ops.is_empty());
}
#[test]
fn run_all_is_idempotent() {
let desc = KernelDescriptor {
id: "k".into(),
bindings: BindingLayout { slots: vec![] },
dispatch: Dispatch::new(1, 1, 1),
body: KernelBody {
ops: vec![
KernelOp {
kind: KernelOpKind::Literal,
operands: vec![0],
result: Some(0),
},
KernelOp {
kind: KernelOpKind::Literal,
operands: vec![0],
result: Some(1),
}, KernelOp {
kind: KernelOpKind::Literal,
operands: vec![1],
result: Some(2),
}, ],
child_bodies: vec![],
literals: vec![LiteralValue::U32(5), LiteralValue::U32(99)],
},
};
let once = run_all(&desc);
let twice = run_all(&once);
assert_eq!(once.body.ops.len(), twice.body.ops.len());
assert_eq!(once.body.literals, twice.body.literals);
}
#[test]
fn run_all_collapses_kitchen_sink_kernel() {
let desc = KernelDescriptor {
id: "kitchen_sink".into(),
bindings: BindingLayout {
slots: vec![crate::BindingSlot {
slot: 0,
element_type: vyre_foundation::ir::DataType::U32,
element_count: None,
memory_class: crate::MemoryClass::Global,
visibility: crate::BindingVisibility::ReadWrite,
name: "buf".into(),
}],
},
dispatch: Dispatch::new(1, 1, 1),
body: KernelBody {
ops: vec![
KernelOp {
kind: KernelOpKind::Literal,
operands: vec![0],
result: Some(0),
},
KernelOp {
kind: KernelOpKind::Literal,
operands: vec![1],
result: Some(1),
},
KernelOp {
kind: KernelOpKind::Literal,
operands: vec![2],
result: Some(2),
},
KernelOp {
kind: KernelOpKind::Literal,
operands: vec![3],
result: Some(3),
},
KernelOp {
kind: KernelOpKind::Literal,
operands: vec![0],
result: Some(4),
},
KernelOp {
kind: KernelOpKind::BinOpKind(vyre_foundation::ir::BinOp::Add),
operands: vec![3, 0],
result: Some(5),
},
KernelOp {
kind: KernelOpKind::BinOpKind(vyre_foundation::ir::BinOp::Mul),
operands: vec![3, 2],
result: Some(6),
},
KernelOp {
kind: KernelOpKind::BinOpKind(vyre_foundation::ir::BinOp::Mul),
operands: vec![3, 1],
result: Some(7),
},
KernelOp {
kind: KernelOpKind::BinOpKind(vyre_foundation::ir::BinOp::Mul),
operands: vec![3, 0],
result: Some(8),
},
KernelOp {
kind: KernelOpKind::StoreGlobal,
operands: vec![0, 0, 5],
result: None,
},
KernelOp {
kind: KernelOpKind::StoreGlobal,
operands: vec![0, 0, 6],
result: None,
},
],
child_bodies: vec![],
literals: vec![
LiteralValue::U32(0),
LiteralValue::U32(1),
LiteralValue::U32(8),
LiteralValue::U32(7),
],
},
};
let before_op_count = desc.body.ops.len();
let out = run_all(&desc);
let store_count = out
.body
.ops
.iter()
.filter(|o| matches!(o.kind, KernelOpKind::StoreGlobal))
.count();
assert_eq!(store_count, 1, "dead_store must drop the overwritten store");
let mul_count = out
.body
.ops
.iter()
.filter(|o| {
matches!(
o.kind,
KernelOpKind::BinOpKind(vyre_foundation::ir::BinOp::Mul)
)
})
.count();
assert_eq!(mul_count, 0, "all 3 Mul ops should be eliminated");
let add_count = out
.body
.ops
.iter()
.filter(|o| {
matches!(
o.kind,
KernelOpKind::BinOpKind(vyre_foundation::ir::BinOp::Add)
)
})
.count();
assert_eq!(add_count, 0, "Add(r3, 0) → r3 should be eliminated");
assert!(
out.body.ops.len() <= before_op_count - 5,
"expected op count to drop by ≥5 (was {before_op_count}, now {})",
out.body.ops.len()
);
let twice = run_all(&out);
assert_eq!(out.body.ops.len(), twice.body.ops.len());
}
#[test]
fn run_all_forwards_then_drops_redundant_load() {
let desc = KernelDescriptor {
id: "stl".into(),
bindings: BindingLayout {
slots: vec![crate::BindingSlot {
slot: 0,
element_type: vyre_foundation::ir::DataType::U32,
element_count: None,
memory_class: crate::MemoryClass::Global,
visibility: crate::BindingVisibility::ReadWrite,
name: "buf".into(),
}],
},
dispatch: Dispatch::new(1, 1, 1),
body: KernelBody {
ops: vec![
KernelOp {
kind: KernelOpKind::Literal,
operands: vec![0],
result: Some(0),
}, KernelOp {
kind: KernelOpKind::Literal,
operands: vec![1],
result: Some(1),
}, KernelOp {
kind: KernelOpKind::StoreGlobal,
operands: vec![0, 0, 1],
result: None,
},
KernelOp {
kind: KernelOpKind::LoadGlobal,
operands: vec![0, 0],
result: Some(2),
},
KernelOp {
kind: KernelOpKind::StoreGlobal,
operands: vec![0, 0, 2],
result: None,
},
],
child_bodies: vec![],
literals: vec![LiteralValue::U32(0), LiteralValue::U32(7)],
},
};
let out = run_all(&desc);
let store_count = out
.body
.ops
.iter()
.filter(|o| matches!(o.kind, KernelOpKind::StoreGlobal))
.count();
assert_eq!(
store_count, 1,
"dead_store must drop the redundant first store"
);
let load_count = out
.body
.ops
.iter()
.filter(|o| matches!(o.kind, KernelOpKind::LoadGlobal))
.count();
assert_eq!(load_count, 0, "descriptor_dce must drop the redundant load");
}
#[test]
fn run_all_unrolls_then_simplifies() {
let desc = KernelDescriptor {
id: "loop_then_dse".into(),
bindings: BindingLayout {
slots: vec![crate::BindingSlot {
slot: 0,
element_type: vyre_foundation::ir::DataType::U32,
element_count: None,
memory_class: crate::MemoryClass::Global,
visibility: crate::BindingVisibility::ReadWrite,
name: "buf".into(),
}],
},
dispatch: Dispatch::new(1, 1, 1),
body: KernelBody {
ops: vec![
KernelOp {
kind: KernelOpKind::Literal,
operands: vec![0],
result: Some(0),
},
KernelOp {
kind: KernelOpKind::Literal,
operands: vec![1],
result: Some(1),
},
KernelOp {
kind: KernelOpKind::Literal,
operands: vec![0],
result: Some(2),
},
KernelOp {
kind: KernelOpKind::StructuredForLoop {
loop_var: std::sync::Arc::from("i"),
},
operands: vec![0, 1, 0],
result: None,
},
],
child_bodies: vec![KernelBody {
ops: vec![
KernelOp {
kind: KernelOpKind::Literal,
operands: vec![0],
result: Some(0),
},
KernelOp {
kind: KernelOpKind::Literal,
operands: vec![1],
result: Some(1),
},
KernelOp {
kind: KernelOpKind::StoreGlobal,
operands: vec![0, 0, 1],
result: None,
},
],
child_bodies: vec![],
literals: vec![LiteralValue::U32(0), LiteralValue::U32(7)],
}],
literals: vec![LiteralValue::U32(0), LiteralValue::U32(2)],
},
};
let out = run_all(&desc);
let loop_count = out
.body
.ops
.iter()
.filter(|o| matches!(o.kind, KernelOpKind::StructuredForLoop { .. }))
.count();
assert_eq!(loop_count, 0, "loop should be unrolled");
let store_count = out
.body
.ops
.iter()
.filter(|o| matches!(o.kind, KernelOpKind::StoreGlobal))
.count();
assert!(
store_count >= 1,
"at least one store from the unrolled body should survive"
);
}
#[test]
fn run_all_with_stats_reports_op_reduction() {
let desc = KernelDescriptor {
id: "stats".into(),
bindings: BindingLayout {
slots: vec![crate::BindingSlot {
slot: 0,
element_type: vyre_foundation::ir::DataType::U32,
element_count: None,
memory_class: crate::MemoryClass::Global,
visibility: crate::BindingVisibility::ReadWrite,
name: "buf".into(),
}],
},
dispatch: Dispatch::new(1, 1, 1),
body: KernelBody {
ops: vec![
KernelOp {
kind: KernelOpKind::Literal,
operands: vec![0],
result: Some(0),
},
KernelOp {
kind: KernelOpKind::Literal,
operands: vec![1],
result: Some(1),
},
KernelOp {
kind: KernelOpKind::BinOpKind(vyre_foundation::ir::BinOp::Add),
operands: vec![1, 0],
result: Some(2),
}, KernelOp {
kind: KernelOpKind::BinOpKind(vyre_foundation::ir::BinOp::Mul),
operands: vec![1, 0],
result: Some(3),
}, KernelOp {
kind: KernelOpKind::StoreGlobal,
operands: vec![0, 0, 1],
result: None,
},
],
child_bodies: vec![],
literals: vec![LiteralValue::U32(0), LiteralValue::U32(99)],
},
};
let (_out, stats) = run_all_with_stats(&desc);
assert!(
stats.ops_eliminated() >= 2,
"expected ≥2 ops eliminated, got {} ({} → {})",
stats.ops_eliminated(),
stats.ops_before,
stats.ops_after
);
assert!(stats.iterations >= 1);
assert!(stats.iterations <= RUN_ALL_MAX_ITERS);
assert!(stats.converged, "pipeline must converge");
}
#[test]
fn optimization_stats_format_short_includes_all_fields() {
let s = OptimizationStats {
ops_before: 11,
ops_after: 3,
bindings_before: 3,
bindings_after: 1,
literals_before: 4,
literals_after: 2,
iterations: 2,
converged: true,
};
let f = s.format_short();
assert!(f.contains("ops 11→3 (-8)"));
assert!(f.contains("bindings 3→1 (-2)"));
assert!(f.contains("iters 2"));
assert!(f.contains("converged"));
}
#[test]
fn optimization_stats_merge_is_associative() {
let a = OptimizationStats {
ops_before: 10,
ops_after: 3,
bindings_before: 2,
bindings_after: 1,
literals_before: 5,
literals_after: 2,
iterations: 2,
converged: true,
};
let b = OptimizationStats {
ops_before: 7,
ops_after: 4,
bindings_before: 1,
bindings_after: 1,
literals_before: 3,
literals_after: 3,
iterations: 1,
converged: true,
};
let c = OptimizationStats {
ops_before: 5,
ops_after: 2,
bindings_before: 1,
bindings_after: 0,
literals_before: 2,
literals_after: 1,
iterations: 1,
converged: true,
};
let mut left = a;
left.merge(b);
left.merge(c);
let mut bc = b;
bc.merge(c);
let mut right = a;
right.merge(bc);
assert_eq!(left, right);
}
#[test]
fn optimization_stats_merge_aggregates() {
let mut acc = OptimizationStats::zero();
acc.merge(OptimizationStats {
ops_before: 10,
ops_after: 3,
bindings_before: 2,
bindings_after: 1,
literals_before: 5,
literals_after: 2,
iterations: 2,
converged: true,
});
acc.merge(OptimizationStats {
ops_before: 7,
ops_after: 4,
bindings_before: 1,
bindings_after: 1,
literals_before: 3,
literals_after: 3,
iterations: 1,
converged: false,
});
assert_eq!(acc.ops_before, 17);
assert_eq!(acc.ops_after, 7);
assert_eq!(acc.iterations, 3);
assert!(!acc.converged); }
#[test]
fn optimization_stats_zero_is_identity() {
let s = OptimizationStats {
ops_before: 5,
ops_after: 3,
bindings_before: 1,
bindings_after: 1,
literals_before: 2,
literals_after: 1,
iterations: 2,
converged: true,
};
let mut acc = OptimizationStats::zero();
acc.merge(s);
assert_eq!(acc, s);
}
#[test]
fn optimization_stats_format_short_marks_stopped() {
let s = OptimizationStats {
ops_before: 5,
ops_after: 5,
bindings_before: 1,
bindings_after: 1,
literals_before: 1,
literals_after: 1,
iterations: 4,
converged: false,
};
assert!(s.format_short().contains("stopped"));
}
#[test]
fn run_all_with_stats_reports_no_change_when_already_optimal() {
let desc = KernelDescriptor {
id: "minimal".into(),
bindings: BindingLayout {
slots: vec![crate::BindingSlot {
slot: 0,
element_type: vyre_foundation::ir::DataType::U32,
element_count: None,
memory_class: crate::MemoryClass::Global,
visibility: crate::BindingVisibility::ReadWrite,
name: "buf".into(),
}],
},
dispatch: Dispatch::new(1, 1, 1),
body: KernelBody {
ops: vec![
KernelOp {
kind: KernelOpKind::Literal,
operands: vec![0],
result: Some(0),
},
KernelOp {
kind: KernelOpKind::Literal,
operands: vec![1],
result: Some(1),
},
KernelOp {
kind: KernelOpKind::StoreGlobal,
operands: vec![0, 0, 1],
result: None,
},
],
child_bodies: vec![],
literals: vec![LiteralValue::U32(0), LiteralValue::U32(7)],
},
};
let (_out, stats) = run_all_with_stats(&desc);
assert_eq!(stats.ops_before, stats.ops_after);
assert_eq!(stats.bindings_before, stats.bindings_after);
assert_eq!(stats.iterations, 1);
assert!(stats.converged);
}
#[test]
fn run_all_with_stats_reports_dropped_bindings() {
let desc = KernelDescriptor {
id: "with_unused".into(),
bindings: BindingLayout {
slots: vec![
crate::BindingSlot {
slot: 0,
element_type: vyre_foundation::ir::DataType::U32,
element_count: None,
memory_class: crate::MemoryClass::Global,
visibility: crate::BindingVisibility::ReadWrite,
name: "used".into(),
},
crate::BindingSlot {
slot: 9,
element_type: vyre_foundation::ir::DataType::U32,
element_count: None,
memory_class: crate::MemoryClass::Global,
visibility: crate::BindingVisibility::ReadOnly,
name: "unused".into(),
},
],
},
dispatch: Dispatch::new(1, 1, 1),
body: KernelBody {
ops: vec![
KernelOp {
kind: KernelOpKind::Literal,
operands: vec![0],
result: Some(0),
},
KernelOp {
kind: KernelOpKind::Literal,
operands: vec![1],
result: Some(1),
},
KernelOp {
kind: KernelOpKind::StoreGlobal,
operands: vec![0, 0, 1],
result: None,
},
],
child_bodies: vec![],
literals: vec![LiteralValue::U32(0), LiteralValue::U32(7)],
},
};
let (_out, stats) = run_all_with_stats(&desc);
assert_eq!(stats.bindings_before, 2);
assert_eq!(stats.bindings_after, 2);
assert_eq!(stats.bindings_dropped(), 0);
}
}