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