diff --git a/rust_compiler/libs/optimizer/src/dead_store_elimination.rs b/rust_compiler/libs/optimizer/src/dead_store_elimination.rs index 8273a86..f16a034 100644 --- a/rust_compiler/libs/optimizer/src/dead_store_elimination.rs +++ b/rust_compiler/libs/optimizer/src/dead_store_elimination.rs @@ -1,5 +1,5 @@ use crate::helpers::get_destination_reg; -use il::{Instruction, InstructionNode, Operand}; +use il::{Instruction, InstructionNode}; use std::collections::HashMap; /// Pass: Dead Store Elimination @@ -93,114 +93,6 @@ fn eliminate_overwritten_stores<'a>( } } -/// Backward pass: Remove stores that are never read before function return -fn eliminate_unread_stores<'a>( - input: Vec>, -) -> (Vec>, bool) { - use std::collections::HashSet; - let mut changed = false; - let mut to_remove = Vec::new(); - - // Find function boundaries by matching push/pop pairs of sp (register 17) - let mut function_ranges = Vec::new(); - let mut stack = Vec::new(); - - for (i, node) in input.iter().enumerate() { - match &node.instruction { - Instruction::Push(Operand::Register(17)) => { - stack.push(i); - } - Instruction::Pop(Operand::Register(17)) => { - if let Some(start) = stack.pop() { - // Find the j ra after the pop sp - let mut end = i; - for j in (i + 1)..input.len() { - if matches!(input[j].instruction, Instruction::Jump(Operand::Register(16))) { - end = j; - break; - } - } - function_ranges.push((start, end)); - } - } - _ => {} - } - } - - // Process each function independently - for (func_start, func_end) in function_ranges { - // Process this function backward - let mut live_registers: HashSet = HashSet::new(); - - // First pass: find which registers are actually read in the function - for i in func_start..=func_end { - let node = &input[i]; - for reg in 0..16 { - if crate::helpers::reg_is_read(&node.instruction, reg) { - live_registers.insert(reg); - } - } - } - - // Clear live registers - we'll rebuild it as we go backward - live_registers.clear(); - - // Start from the end of the function, working backward - for i in (func_start..=func_end).rev() { - let node = &input[i]; - - // Skip stack management instructions - if matches!(node.instruction, Instruction::Push(_) | Instruction::Pop(_)) { - continue; - } - - // If instruction writes to a register (assignment/computation) - if let Some(dest_reg) = get_destination_reg(&node.instruction) { - // If the register isn't live (not read after this write), this write is dead - if !live_registers.contains(&dest_reg) { - to_remove.push(i); - changed = true; - // Don't process the reads of this dead instruction - continue; - } else { - // This instruction is live. Check what it reads and marks as live. - for reg in 0..16 { - if crate::helpers::reg_is_read(&node.instruction, reg) { - live_registers.insert(reg); - } - } - // This instruction defines the register, so remove it from live set - live_registers.remove(&dest_reg); - } - } else { - // Instruction doesn't write - just track reads - for reg in 0..16 { - if crate::helpers::reg_is_read(&node.instruction, reg) { - live_registers.insert(reg); - } - } - } - } - } - - if !to_remove.is_empty() { - let output = input - .into_iter() - .enumerate() - .filter_map(|(i, node)| { - if to_remove.contains(&i) { - None - } else { - Some(node) - } - }) - .collect(); - (output, true) - } else { - (input, changed) - } -} - /// Simplified check: Does this instruction read the register? fn reg_is_read_or_affects_control(instr: &Instruction, reg: u8) -> bool { use crate::helpers::reg_is_read; @@ -231,31 +123,4 @@ mod tests { assert!(changed); assert_eq!(output.len(), 1); } - - #[test] - fn test_dead_store_in_function() { - // Test that dead stores inside functions are removed - // Function structure: push sp, push ra, code, pop ra, pop sp, j ra - let input = vec![ - InstructionNode::new(Instruction::Push(Operand::Register(17)), None), - InstructionNode::new(Instruction::Push(Operand::Register(16)), None), - InstructionNode::new( - Instruction::Move(Operand::Register(1), Operand::Number(5.into())), - None, - ), - // r1 is never read, so the move above should be dead - InstructionNode::new( - Instruction::Move(Operand::Register(15), Operand::Number(42.into())), - None, - ), - InstructionNode::new(Instruction::Pop(Operand::Register(16)), None), - InstructionNode::new(Instruction::Pop(Operand::Register(17)), None), - InstructionNode::new(Instruction::Jump(Operand::Register(16)), None), - ]; - - let (output, changed) = dead_store_elimination(input); - assert!(changed, "Dead store should be detected"); - // Should remove the move r1 5 (index 2) and move r15 42 (index 3) since neither is read - assert_eq!(output.len(), 5); - } }