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.
any_inst_results_used(inst: Inst, live: &[bool], dfg: &DataFlowGraph) -> bool7 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.
trivially_has_side_effects(opcode: Opcode) -> bool12 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.
is_load_with_defined_trapping(opcode: Opcode, data: &InstructionData) -> bool25 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?
has_side_effect(func: &Function, inst: Inst) -> bool38 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?
has_side_effect_or_load(func: &Function, inst: Inst) -> bool45 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?
is_constant_64bit(func: &Function, inst: Inst) -> Option<u64>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