1 //! Instruction predicates/properties, shared by various analyses. 2 3 use crate::ir::{DataFlowGraph, Function, Inst, InstructionData, Opcode}; 4 use cranelift_entity::EntityRef; 5 6 /// Preserve instructions with used result values. 7 pub fn any_inst_results_used(inst: Inst, live: &[bool], dfg: &DataFlowGraph) -> bool { 8 dfg.inst_results(inst).iter().any(|v| live[v.index()]) 9 } 10 11 /// Test whether the given opcode is unsafe to even consider as side-effect-free. 12 fn trivially_has_side_effects(opcode: Opcode) -> bool { 13 opcode.is_call() 14 || opcode.is_branch() 15 || opcode.is_terminator() 16 || opcode.is_return() 17 || opcode.can_trap() 18 || opcode.other_side_effects() 19 || opcode.can_store() 20 } 21 22 /// Load instructions without the `notrap` flag are defined to trap when 23 /// operating on inaccessible memory, so we can't treat them as side-effect-free even if the loaded 24 /// value is unused. 25 fn is_load_with_defined_trapping(opcode: Opcode, data: &InstructionData) -> bool { 26 if !opcode.can_load() { 27 return false; 28 } 29 match *data { 30 InstructionData::StackLoad { .. } => false, 31 InstructionData::Load { flags, .. } => !flags.notrap(), 32 _ => true, 33 } 34 } 35 36 /// Does the given instruction have any side-effect that would preclude it from being removed when 37 /// its value is unused? 38 pub fn has_side_effect(func: &Function, inst: Inst) -> bool { 39 let data = &func.dfg[inst]; 40 let opcode = data.opcode(); 41 trivially_has_side_effects(opcode) || is_load_with_defined_trapping(opcode, data) 42 } 43 44 /// Does the given instruction have any side-effect as per [has_side_effect], or else is a load? 45 pub fn has_side_effect_or_load(func: &Function, inst: Inst) -> bool { 46 has_side_effect(func, inst) || func.dfg[inst].opcode().can_load() 47 } 48 49 /// Is the given instruction a constant value (`iconst`, `fconst`, `bconst`) that can be 50 /// represented in 64 bits? 51 pub fn is_constant_64bit(func: &Function, inst: Inst) -> Option<u64> { 52 let data = &func.dfg[inst]; 53 if data.opcode() == Opcode::Null { 54 return Some(0); 55 } 56 match data { 57 &InstructionData::UnaryImm { imm, .. } => Some(imm.bits() as u64), 58 &InstructionData::UnaryIeee32 { imm, .. } => Some(imm.bits() as u64), 59 &InstructionData::UnaryIeee64 { imm, .. } => Some(imm.bits()), 60 &InstructionData::UnaryBool { imm, .. } => Some(if imm { 1 } else { 0 }), 61 _ => None, 62 } 63 } 64