mir: extract CSE into passes::cse and wire it in optimizer. Behavior preserved (count-only, no SSA rewrites). Build + PyVM Stage-2 smokes PASS.
This commit is contained in:
@ -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));
|
||||
|
||||
56
src/mir/passes/cse.rs
Normal file
56
src/mir/passes/cse.rs
Normal file
@ -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<String, ValueId> = 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::<Vec<_>>().join(",");
|
||||
format!("call_{}_{}", func.as_u32(), args_str)
|
||||
}
|
||||
other => format!("other_{:?}", other),
|
||||
}
|
||||
}
|
||||
|
||||
@ -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.
|
||||
|
||||
Reference in New Issue
Block a user