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