fn prune_after_terminator(block: &mut ir::BasicBlock, live_labels: &std::collections::HashSet<usize>) {
let mut trimmed = Vec::with_capacity(block.instructions.len());
let mut terminated = false;
for instr in block.instructions.drain(..) {
if terminated {
if let ir::Instruction::Label(id) = instr {
if live_labels.contains(&id) {
trimmed.push(ir::Instruction::Label(id));
terminated = false;
}
}
continue;
}
match instr {
ir::Instruction::Return
| ir::Instruction::ReturnVoid
| ir::Instruction::ReturnDefault(_)
| ir::Instruction::Jump { .. }
| ir::Instruction::Abort
| ir::Instruction::AbortMsg
| ir::Instruction::Throw
| ir::Instruction::EndTry { .. } => {
trimmed.push(instr);
terminated = true;
}
other => trimmed.push(other),
}
}
block.instructions = trimmed;
}
fn collect_live_labels(function: &ir::Function) -> std::collections::HashSet<usize> {
let mut live = std::collections::HashSet::new();
for block in &function.basic_blocks {
for instr in &block.instructions {
match instr {
ir::Instruction::Jump { target } | ir::Instruction::JumpIf { target } => {
live.insert(*target);
}
ir::Instruction::Try { catch_target } => {
live.insert(*catch_target);
}
ir::Instruction::EndTry { target } => {
live.insert(*target);
}
_ => {}
}
}
}
live
}
pub(crate) fn optimize_ir(mut module: ir::Module, optimizer_level: u8) -> ir::Module {
if optimizer_level == 0 {
return module;
}
let enable_neovm_specific = optimizer_level >= 3;
let enable_constant_folding = optimizer_level >= 2;
for function in &mut module.functions {
let mut label_remap = std::collections::HashMap::new();
let live_labels = collect_live_labels(function);
for block in &mut function.basic_blocks {
prune_after_terminator(block, &live_labels);
}
if enable_constant_folding {
for block in &mut function.basic_blocks {
fold_constant_binary_ops(block);
}
let live_labels = collect_live_labels(function);
for block in &mut function.basic_blocks {
prune_after_terminator(block, &live_labels);
}
}
if enable_neovm_specific {
for block in &mut function.basic_blocks {
dedupe_labels(block, &mut label_remap);
remove_trivial_jumps(block);
neovm_peephole_optimize(block);
neovm_simplify_identity_ops(block);
neovm_bool_optimize(block);
neovm_peephole_optimize(block);
}
}
if enable_neovm_specific && !label_remap.is_empty() {
retarget_jumps(&mut function.basic_blocks, &label_remap);
}
}
module
}