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.
any_inst_results_used(inst: Inst, live: &[bool], dfg: &DataFlowGraph) -> bool8 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.
trivially_has_side_effects(opcode: Opcode) -> bool13 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.
is_load_with_defined_trapping(opcode: Opcode, data: &InstructionData) -> bool26 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?
has_side_effect(func: &Function, inst: Inst) -> bool39 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?
has_lowering_side_effect(func: &Function, inst: Inst) -> bool47 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?
is_constant_64bit(func: &Function, inst: Inst) -> Option<u64>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
82 /// Is the given instruction a safepoint (i.e., potentially causes a GC, depending on the
83 /// embedding, and so requires reftyped values to be enumerated with a stack map)?
is_safepoint(func: &Function, inst: Inst) -> bool84 pub fn is_safepoint(func: &Function, inst: Inst) -> bool {
85 let op = func.dfg[inst].opcode();
86 op.is_resumable_trap() || op.is_call()
87 }
88