Path: blob/main/cranelift/codegen/src/legalizer/branch_to_trap.rs
1693 views
//! Rewrite branch-to-unconditional-trap into conditional trap instructions.1//!2//! Given this instruction:3//!4//! ```clif5//! brif v0, block1, block26//! ```7//!8//! If we know that `block1` does nothing but immediately trap then we can9//! rewrite that `brif` into the following:10//!11//! ```clif12//! trapz v0, <trapcode>13//! jump block214//! ```15//!16//! (And we can do the equivalent with `trapz` if `block2` immediately traps).17//!18//! This transformation allows for the conditional trap instructions to be GVN'd19//! and for our egraphs mid-end to generally better optimize the program. We20//! additionally have better codegen in our backends for `trapz` than branches21//! to unconditional traps.2223use super::*;2425#[derive(Default)]26pub struct BranchToTrap {27/// The set of blocks that contain exactly one unconditional trap28/// instruction.29just_trap_blocks: EntitySet<ir::Block>,30}3132impl BranchToTrap {33/// Analyze the given block.34///35/// The `block` must be terminated by a `trap` instruction.36pub fn analyze_trapping_block(&mut self, func: &ir::Function, block: ir::Block) {37if func.layout.block_contains_exactly_one_inst(block) {38self.just_trap_blocks.insert(block);39}40}4142fn just_trap_block_code(&self, func: &ir::Function, block: ir::Block) -> ir::TrapCode {43debug_assert!(self.just_trap_blocks.contains(block));44debug_assert!(func.layout.block_contains_exactly_one_inst(block));45let inst = func.layout.first_inst(block).unwrap();46match func.dfg.insts[inst] {47InstructionData::Trap { code, .. } => code,48_ => unreachable!(),49}50}5152/// Process a `brif` instruction, potentially performing our rewrite.53///54/// The `inst` must be a `brif` containing the given `arg` and `blocks`.55pub fn process_brif(56&self,57func: &mut ir::Function,58inst: ir::Inst,59arg: ir::Value,60blocks: [ir::BlockCall; 2],61) {62let consequent = blocks[0].block(&func.dfg.value_lists);63let alternative = blocks[1].block(&func.dfg.value_lists);6465if self.just_trap_blocks.contains(consequent) {66let mut pos = FuncCursor::new(func);67pos.use_srcloc(68pos.func69.layout70.first_inst(consequent)71.expect("just-trap blocks have exactly one inst"),72);73pos.goto_inst(inst);7475let code = self.just_trap_block_code(pos.func, consequent);76pos.ins().trapnz(arg, code);7778let args: SmallVec<[_; 8]> = blocks[1].args(&pos.func.dfg.value_lists).collect();79pos.func.dfg.replace(inst).jump(alternative, &args);80} else if self.just_trap_blocks.contains(alternative) {81let mut pos = FuncCursor::new(func);82pos.use_srcloc(83pos.func84.layout85.first_inst(alternative)86.expect("just-trap blocks have exactly one inst"),87);88pos.goto_inst(inst);8990let code = self.just_trap_block_code(pos.func, alternative);91pos.ins().trapz(arg, code);9293let args: SmallVec<[_; 8]> = blocks[0].args(&pos.func.dfg.value_lists).collect();94pos.func.dfg.replace(inst).jump(consequent, &args);95}96}97}9899100