diff --git a/src/mir/optimizer.rs b/src/mir/optimizer.rs index 49f686ae..5fb238c4 100644 --- a/src/mir/optimizer.rs +++ b/src/mir/optimizer.rs @@ -68,8 +68,11 @@ impl MirOptimizer { stats.dead_code_eliminated += eliminated; } - // Pass 2: Pure instruction CSE (Common Subexpression Elimination) - stats.merge(self.common_subexpression_elimination(module)); + // Pass 2: Pure instruction CSE (modularized) + { + let eliminated = crate::mir::passes::cse::eliminate_common_subexpressions(module); + stats.cse_eliminated += eliminated; + } // Pass 3: Pure instruction reordering for better locality stats.merge(self.reorder_pure_instructions(module)); diff --git a/src/mir/passes/cse.rs b/src/mir/passes/cse.rs new file mode 100644 index 00000000..9d035785 --- /dev/null +++ b/src/mir/passes/cse.rs @@ -0,0 +1,56 @@ +//! Common Subexpression Elimination (CSE) for pure MIR instructions. +//! +//! Note: Current implementation mirrors the prior monolithic behavior and +//! counts eliminations without rewriting uses (SSA update is TODO). This keeps +//! behavior identical while modularizing the pass for future enhancement. + +use crate::mir::{MirInstruction, MirModule, MirFunction, ValueId}; +use std::collections::HashMap; + +/// Run CSE across the module. Returns the number of eliminated expressions. +pub fn eliminate_common_subexpressions(module: &mut MirModule) -> usize { + let mut eliminated = 0usize; + for (_name, func) in module.functions.iter_mut() { + eliminated += cse_in_function(func); + } + eliminated +} + +fn cse_in_function(function: &mut MirFunction) -> usize { + let mut expression_map: HashMap = HashMap::new(); + let mut eliminated = 0usize; + + for (_bid, block) in &mut function.blocks { + for inst in &mut block.instructions { + if inst.effects().is_pure() { + let key = instruction_key(inst); + if let Some(&existing) = expression_map.get(&key) { + if let Some(dst) = inst.dst_value() { + // Count as eliminated; rewriting uses is a future improvement. + let _ = (existing, dst); // keep variables referenced + eliminated += 1; + } + } else if let Some(dst) = inst.dst_value() { + expression_map.insert(key, dst); + } + } + } + } + eliminated +} + +fn instruction_key(i: &MirInstruction) -> String { + match i { + MirInstruction::Const { value, .. } => format!("const_{:?}", value), + MirInstruction::BinOp { op, lhs, rhs, .. } => + format!("binop_{:?}_{}_{}", op, lhs.as_u32(), rhs.as_u32()), + MirInstruction::Compare { op, lhs, rhs, .. } => + format!("cmp_{:?}_{}_{}", op, lhs.as_u32(), rhs.as_u32()), + MirInstruction::Call { func, args, .. } => { + let args_str = args.iter().map(|v| v.as_u32().to_string()).collect::>().join(","); + format!("call_{}_{}", func.as_u32(), args_str) + } + other => format!("other_{:?}", other), + } +} + diff --git a/src/mir/passes/mod.rs b/src/mir/passes/mod.rs index ac9a711e..6ca30641 100644 --- a/src/mir/passes/mod.rs +++ b/src/mir/passes/mod.rs @@ -5,6 +5,7 @@ pub mod type_hints; pub mod escape; pub mod method_id_inject; pub mod dce; +pub mod cse; /// Minimal pass trait for future expansion. Currently unused by the main /// optimizer pipeline but provided to guide modularization.