In particular, introduce initial support for the MOVI and MVNI instructions, with 8-bit elements. Also, treat vector constants as 32- or 64-bit floating-point numbers, if their value allows it, by relying on the architectural zero extension. Finally, stop generating literal loads for 32-bit constants. Copyright (c) 2020, Arm Limited.
88 lines
3.1 KiB
Rust
88 lines
3.1 KiB
Rust
//! Instruction predicates/properties, shared by various analyses.
|
|
|
|
use crate::ir::{DataFlowGraph, Function, Inst, InstructionData, Opcode};
|
|
use crate::machinst::ty_bits;
|
|
use cranelift_entity::EntityRef;
|
|
|
|
/// Preserve instructions with used result values.
|
|
pub fn any_inst_results_used(inst: Inst, live: &[bool], dfg: &DataFlowGraph) -> bool {
|
|
dfg.inst_results(inst).iter().any(|v| live[v.index()])
|
|
}
|
|
|
|
/// Test whether the given opcode is unsafe to even consider as side-effect-free.
|
|
fn trivially_has_side_effects(opcode: Opcode) -> bool {
|
|
opcode.is_call()
|
|
|| opcode.is_branch()
|
|
|| opcode.is_terminator()
|
|
|| opcode.is_return()
|
|
|| opcode.can_trap()
|
|
|| opcode.other_side_effects()
|
|
|| opcode.can_store()
|
|
}
|
|
|
|
/// Load instructions without the `notrap` flag are defined to trap when
|
|
/// operating on inaccessible memory, so we can't treat them as side-effect-free even if the loaded
|
|
/// value is unused.
|
|
fn is_load_with_defined_trapping(opcode: Opcode, data: &InstructionData) -> bool {
|
|
if !opcode.can_load() {
|
|
return false;
|
|
}
|
|
match *data {
|
|
InstructionData::StackLoad { .. } => false,
|
|
InstructionData::Load { flags, .. } => !flags.notrap(),
|
|
_ => true,
|
|
}
|
|
}
|
|
|
|
/// Does the given instruction have any side-effect that would preclude it from being removed when
|
|
/// its value is unused?
|
|
pub fn has_side_effect(func: &Function, inst: Inst) -> bool {
|
|
let data = &func.dfg[inst];
|
|
let opcode = data.opcode();
|
|
trivially_has_side_effects(opcode) || is_load_with_defined_trapping(opcode, data)
|
|
}
|
|
|
|
/// Does the given instruction have any side-effect as per [has_side_effect], or else is a load,
|
|
/// but not the get_pinned_reg opcode?
|
|
pub fn has_lowering_side_effect(func: &Function, inst: Inst) -> bool {
|
|
let op = func.dfg[inst].opcode();
|
|
op != Opcode::GetPinnedReg && (has_side_effect(func, inst) || op.can_load())
|
|
}
|
|
|
|
/// Is the given instruction a constant value (`iconst`, `fconst`, `bconst`) that can be
|
|
/// represented in 64 bits?
|
|
pub fn is_constant_64bit(func: &Function, inst: Inst) -> Option<u64> {
|
|
let data = &func.dfg[inst];
|
|
if data.opcode() == Opcode::Null {
|
|
return Some(0);
|
|
}
|
|
match data {
|
|
&InstructionData::UnaryImm { imm, .. } => Some(imm.bits() as u64),
|
|
&InstructionData::UnaryIeee32 { imm, .. } => Some(imm.bits() as u64),
|
|
&InstructionData::UnaryIeee64 { imm, .. } => Some(imm.bits()),
|
|
&InstructionData::UnaryBool { imm, .. } => {
|
|
let imm = if imm {
|
|
let bits = ty_bits(func.dfg.value_type(func.dfg.inst_results(inst)[0]));
|
|
|
|
if bits < 64 {
|
|
(1u64 << bits) - 1
|
|
} else {
|
|
u64::MAX
|
|
}
|
|
} else {
|
|
0
|
|
};
|
|
|
|
Some(imm)
|
|
}
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
/// Is the given instruction a safepoint (i.e., potentially causes a GC, depending on the
|
|
/// embedding, and so requires reftyped values to be enumerated with a stack map)?
|
|
pub fn is_safepoint(func: &Function, inst: Inst) -> bool {
|
|
let op = func.dfg[inst].opcode();
|
|
op.is_resumable_trap() || op.is_call()
|
|
}
|