use super::*;
#[derive(Default)]
pub struct BranchToTrap {
just_trap_blocks: EntitySet<ir::Block>,
}
impl BranchToTrap {
pub fn analyze_trapping_block(&mut self, func: &ir::Function, block: ir::Block) {
if func.layout.block_contains_exactly_one_inst(block) {
self.just_trap_blocks.insert(block);
}
}
fn just_trap_block_code(&self, func: &ir::Function, block: ir::Block) -> ir::TrapCode {
debug_assert!(self.just_trap_blocks.contains(block));
debug_assert!(func.layout.block_contains_exactly_one_inst(block));
let inst = func.layout.first_inst(block).unwrap();
match func.dfg.insts[inst] {
InstructionData::Trap { code, .. } => code,
_ => unreachable!(),
}
}
pub fn process_brif(
&self,
func: &mut ir::Function,
inst: ir::Inst,
arg: ir::Value,
blocks: [ir::BlockCall; 2],
) {
let consequent = blocks[0].block(&func.dfg.value_lists);
let alternative = blocks[1].block(&func.dfg.value_lists);
if self.just_trap_blocks.contains(consequent) {
let mut pos = FuncCursor::new(func);
pos.use_srcloc(
pos.func
.layout
.first_inst(consequent)
.expect("just-trap blocks have exactly one inst"),
);
pos.goto_inst(inst);
let code = self.just_trap_block_code(pos.func, consequent);
pos.ins().trapnz(arg, code);
let args: SmallVec<[_; 8]> = blocks[1].args(&pos.func.dfg.value_lists).collect();
pos.func.dfg.replace(inst).jump(alternative, &args);
} else if self.just_trap_blocks.contains(alternative) {
let mut pos = FuncCursor::new(func);
pos.use_srcloc(
pos.func
.layout
.first_inst(alternative)
.expect("just-trap blocks have exactly one inst"),
);
pos.goto_inst(inst);
let code = self.just_trap_block_code(pos.func, alternative);
pos.ins().trapz(arg, code);
let args: SmallVec<[_; 8]> = blocks[0].args(&pos.func.dfg.value_lists).collect();
pos.func.dfg.replace(inst).jump(consequent, &args);
}
}
}