use crate::analysis::{def_use, reaching_definitions};
use crate::il;
use crate::Error;
use std::collections::HashSet;
#[allow(dead_code)]
pub fn dead_code_elimination(function: &il::Function) -> Result<il::Function, Error> {
let rd = reaching_definitions::reaching_definitions(function)?;
let mut live: HashSet<il::FunctionLocation> = HashSet::new();
function
.blocks()
.into_iter()
.filter(|block| {
function
.control_flow_graph()
.edges_out(block.index())
.unwrap()
.is_empty()
})
.for_each(|block| {
let rfl = if let Some(instruction) = block.instructions().last() {
il::RefFunctionLocation::Instruction(block, instruction)
} else {
il::RefFunctionLocation::EmptyBlock(block)
};
let rpl = il::RefProgramLocation::new(function, rfl);
rd.get(&rpl.into())
.unwrap()
.locations()
.iter()
.for_each(|location| {
live.insert(location.function_location().clone());
});
});
for block in function.blocks() {
for instruction in block.instructions() {
match *instruction.operation() {
il::Operation::Branch { .. } | il::Operation::Intrinsic { .. } => {
let rpl = il::RefProgramLocation::new(
function,
il::RefFunctionLocation::Instruction(block, instruction),
);
rd[&rpl.into()].locations().iter().for_each(|location| {
live.insert(location.function_location().clone());
});
}
_ => {}
}
}
}
let du = def_use(function)?;
let kill = function
.locations()
.into_iter()
.filter(|location| {
location
.instruction()
.map(|instruction| {
!instruction
.scalars_written()
.map(|scalars_written| scalars_written.is_empty())
.unwrap_or(false)
})
.unwrap_or(false)
})
.filter(|location| !live.contains(&location.clone().into()))
.filter(|location| du[&location.clone().program_location(function).into()].is_empty())
.map(|l| l.into())
.collect::<Vec<il::FunctionLocation>>();
let mut dce_function = function.clone();
for k in kill {
let instruction_index = k.instruction_index().unwrap();
let block_index = k.block_index().unwrap();
let block = dce_function.block_mut(block_index).unwrap();
*block
.instruction_mut(instruction_index)
.ok_or("Failed to find instruction")?
.operation_mut() = il::Operation::nop();
}
Ok(dce_function)
}