This commit is contained in:
static
2025-06-01 16:58:10 +00:00
parent 1ab35c5367
commit 603af88803

View File

@@ -1,5 +1,6 @@
use core::ops::Deref; use core::ops::Deref;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::ops::DerefMut;
use crate::ir::*; use crate::ir::*;
use crate::opt::opt_utils::*; use crate::opt::opt_utils::*;
@@ -12,6 +13,190 @@ pub struct DeadcodeInner {}
impl Optimize<FunctionDefinition> for DeadcodeInner { impl Optimize<FunctionDefinition> for DeadcodeInner {
fn optimize(&mut self, code: &mut FunctionDefinition) -> bool { fn optimize(&mut self, code: &mut FunctionDefinition) -> bool {
todo!() let mut used_allocations = HashSet::new();
let mut used_registers = HashSet::new();
for (bid, block) in &code.blocks {
for (i, inst) in block.instructions.iter().enumerate() {
match inst.deref() {
Instruction::BinOp { lhs, rhs, .. } => {
mark_as_used(lhs, &mut used_allocations, &mut used_registers);
mark_as_used(rhs, &mut used_allocations, &mut used_registers);
}
Instruction::UnaryOp { operand, .. } => {
mark_as_used(operand, &mut used_allocations, &mut used_registers)
}
Instruction::Store { ptr, value } => {
mark_as_used(ptr, &mut used_allocations, &mut used_registers);
mark_as_used(value, &mut used_allocations, &mut used_registers);
// mark_as_used(
// &Operand::register(RegisterId::temp(*bid, i), inst.dtype()),
// &mut used_allocations,
// &mut used_registers,
// );
}
Instruction::Load { ptr } => {
mark_as_used(ptr, &mut used_allocations, &mut used_registers)
}
Instruction::Call { callee, args, .. } => {
mark_as_used(callee, &mut used_allocations, &mut used_registers);
for arg in args {
mark_as_used(arg, &mut used_allocations, &mut used_registers);
}
// mark_as_used(
// &Operand::register(RegisterId::temp(*bid, i), inst.dtype()),
// &mut used_allocations,
// &mut used_registers,
// );
}
Instruction::TypeCast { value, .. } => {
mark_as_used(value, &mut used_allocations, &mut used_registers)
}
Instruction::GetElementPtr { ptr, offset, .. } => {
mark_as_used(ptr, &mut used_allocations, &mut used_registers);
mark_as_used(offset, &mut used_allocations, &mut used_registers);
}
_ => (),
}
}
match &block.exit {
BlockExit::Jump { arg } => {
mark_jump_args_as_used(arg, &mut used_allocations, &mut used_registers);
}
BlockExit::ConditionalJump {
condition,
arg_then,
arg_else,
} => {
mark_as_used(condition, &mut used_allocations, &mut used_registers);
mark_jump_args_as_used(arg_then, &mut used_allocations, &mut used_registers);
mark_jump_args_as_used(arg_else, &mut used_allocations, &mut used_registers);
}
BlockExit::Switch {
value,
default,
cases,
} => {
mark_as_used(value, &mut used_allocations, &mut used_registers);
mark_jump_args_as_used(default, &mut used_allocations, &mut used_registers);
for (_, arg) in cases {
mark_jump_args_as_used(arg, &mut used_allocations, &mut used_registers);
}
}
BlockExit::Return { value } => {
mark_as_used(value, &mut used_allocations, &mut used_registers);
}
_ => (),
}
}
println!("{used_allocations:?} /// {used_registers:?}");
let mut replaces = HashMap::new();
let survived_allocations = code
.allocations
.iter()
.enumerate()
.filter(|(aid, _)| used_allocations.contains(aid))
.collect::<Vec<_>>();
if survived_allocations.len() != code.allocations.len() {
for (new_aid, (old_aid, dtype)) in survived_allocations.iter().enumerate() {
let _unused = replaces.insert(
RegisterId::local(*old_aid),
Operand::register(
RegisterId::local(new_aid),
Dtype::pointer((*dtype).deref().clone()),
),
);
}
code.allocations = survived_allocations
.into_iter()
.map(|(_, dtype)| dtype.clone())
.collect();
}
for (bid, block) in &mut code.blocks {
let nop_instructions = block
.instructions
.iter()
.enumerate()
.filter_map(|(iid, inst)| match (*inst).deref() {
Instruction::Nop => Some(iid),
_ => None,
})
.collect::<HashSet<_>>();
let survived_instructions = block
.instructions
.iter()
.enumerate()
.filter(|(iid, inst)| {
(used_registers.contains(&RegisterId::temp(*bid, *iid))
&& !nop_instructions.contains(iid))
|| !inst.has_no_side_effects()
})
.collect::<Vec<_>>();
if survived_instructions.len() != block.instructions.len() {
for (new_iid, (old_iid, inst)) in survived_instructions.iter().enumerate() {
let _unused = replaces.insert(
RegisterId::temp(*bid, *old_iid),
Operand::register(RegisterId::temp(*bid, new_iid), inst.dtype()),
);
}
for iid_nop in &nop_instructions {
let _unused = replaces.insert(
RegisterId::temp(*bid, *iid_nop),
Operand::constant(Constant::unit()),
);
}
block.instructions = survived_instructions
.into_iter()
.map(|(_, inst)| inst.clone())
.collect();
}
}
for (bid, block) in code.blocks.iter_mut() {
let mut changed = false;
for inst in block.instructions.iter_mut() {
changed = replace_instruction_operands(inst, &replaces) || changed;
}
changed = replace_exit_operands(&mut block.exit, &replaces) || changed;
}
!replaces.is_empty()
}
}
fn mark_as_used(
operand: &Operand,
used_allocations: &mut HashSet<usize>,
used_registers: &mut HashSet<RegisterId>,
) {
match operand {
Operand::Register { rid, .. } => match rid {
RegisterId::Local { aid } => {
let _ = used_allocations.insert(*aid);
}
_ => {
let _ = used_registers.insert(*rid);
}
},
_ => (),
}
}
fn mark_jump_args_as_used(
arg: &JumpArg,
used_allocations: &mut HashSet<usize>,
used_registers: &mut HashSet<RegisterId>,
) {
for arg in &arg.args {
mark_as_used(arg, used_allocations, used_registers);
} }
} }