cranelift_codegen/isa/aarch64/
lower.rs

1//! Lowering rules for AArch64.
2//!
3//! TODO: opportunities for better code generation:
4//!
5//! - Smarter use of addressing modes. Recognize a+SCALE*b patterns. Recognize
6//!   pre/post-index opportunities.
7//!
8//! - Floating-point immediates (FIMM instruction).
9
10use crate::ir::condcodes::{FloatCC, IntCC};
11use crate::ir::pcc::{FactContext, PccResult};
12use crate::ir::Inst as IRInst;
13use crate::ir::{Opcode, Value};
14use crate::isa::aarch64::inst::*;
15use crate::isa::aarch64::pcc;
16use crate::isa::aarch64::AArch64Backend;
17use crate::machinst::lower::*;
18use crate::machinst::*;
19
20pub mod isle;
21
22//============================================================================
23// Lowering: convert instruction inputs to forms that we can use.
24
25fn get_as_extended_value(ctx: &mut Lower<Inst>, val: Value) -> Option<(Value, ExtendOp)> {
26    let inputs = ctx.get_value_as_source_or_const(val);
27    let (insn, n) = inputs.inst.as_inst()?;
28    if n != 0 {
29        return None;
30    }
31    let op = ctx.data(insn).opcode();
32    let out_ty = ctx.output_ty(insn, 0);
33    let out_bits = ty_bits(out_ty);
34
35    // Is this a zero-extend or sign-extend and can we handle that with a register-mode operator?
36    if op == Opcode::Uextend || op == Opcode::Sextend {
37        let sign_extend = op == Opcode::Sextend;
38        let inner_ty = ctx.input_ty(insn, 0);
39        let inner_bits = ty_bits(inner_ty);
40        assert!(inner_bits < out_bits);
41        let extendop = match (sign_extend, inner_bits) {
42            (true, 8) => ExtendOp::SXTB,
43            (false, 8) => ExtendOp::UXTB,
44            (true, 16) => ExtendOp::SXTH,
45            (false, 16) => ExtendOp::UXTH,
46            (true, 32) => ExtendOp::SXTW,
47            (false, 32) => ExtendOp::UXTW,
48            _ => unreachable!(),
49        };
50        return Some((ctx.input_as_value(insn, 0), extendop));
51    }
52
53    None
54}
55
56pub(crate) fn lower_condcode(cc: IntCC) -> Cond {
57    match cc {
58        IntCC::Equal => Cond::Eq,
59        IntCC::NotEqual => Cond::Ne,
60        IntCC::SignedGreaterThanOrEqual => Cond::Ge,
61        IntCC::SignedGreaterThan => Cond::Gt,
62        IntCC::SignedLessThanOrEqual => Cond::Le,
63        IntCC::SignedLessThan => Cond::Lt,
64        IntCC::UnsignedGreaterThanOrEqual => Cond::Hs,
65        IntCC::UnsignedGreaterThan => Cond::Hi,
66        IntCC::UnsignedLessThanOrEqual => Cond::Ls,
67        IntCC::UnsignedLessThan => Cond::Lo,
68    }
69}
70
71pub(crate) fn lower_fp_condcode(cc: FloatCC) -> Cond {
72    // Refer to `codegen/shared/src/condcodes.rs` and to the `FCMP` AArch64 docs.
73    // The FCMP instruction sets:
74    //               NZCV
75    // - PCSR.NZCV = 0011 on UN (unordered),
76    //               0110 on EQ,
77    //               1000 on LT,
78    //               0010 on GT.
79    match cc {
80        // EQ | LT | GT. Vc => V clear.
81        FloatCC::Ordered => Cond::Vc,
82        // UN. Vs => V set.
83        FloatCC::Unordered => Cond::Vs,
84        // EQ. Eq => Z set.
85        FloatCC::Equal => Cond::Eq,
86        // UN | LT | GT. Ne => Z clear.
87        FloatCC::NotEqual => Cond::Ne,
88        // LT | GT.
89        FloatCC::OrderedNotEqual => unimplemented!(),
90        //  UN | EQ
91        FloatCC::UnorderedOrEqual => unimplemented!(),
92        // LT. Mi => N set.
93        FloatCC::LessThan => Cond::Mi,
94        // LT | EQ. Ls => C clear or Z set.
95        FloatCC::LessThanOrEqual => Cond::Ls,
96        // GT. Gt => Z clear, N = V.
97        FloatCC::GreaterThan => Cond::Gt,
98        // GT | EQ. Ge => N = V.
99        FloatCC::GreaterThanOrEqual => Cond::Ge,
100        // UN | LT
101        FloatCC::UnorderedOrLessThan => unimplemented!(),
102        // UN | LT | EQ
103        FloatCC::UnorderedOrLessThanOrEqual => unimplemented!(),
104        // UN | GT
105        FloatCC::UnorderedOrGreaterThan => unimplemented!(),
106        // UN | GT | EQ
107        FloatCC::UnorderedOrGreaterThanOrEqual => unimplemented!(),
108    }
109}
110
111//=============================================================================
112// Lowering-backend trait implementation.
113
114impl LowerBackend for AArch64Backend {
115    type MInst = Inst;
116
117    fn lower(&self, ctx: &mut Lower<Inst>, ir_inst: IRInst) -> Option<InstOutput> {
118        isle::lower(ctx, self, ir_inst)
119    }
120
121    fn lower_branch(
122        &self,
123        ctx: &mut Lower<Inst>,
124        ir_inst: IRInst,
125        targets: &[MachLabel],
126    ) -> Option<()> {
127        isle::lower_branch(ctx, self, ir_inst, targets)
128    }
129
130    fn maybe_pinned_reg(&self) -> Option<Reg> {
131        Some(regs::pinned_reg())
132    }
133
134    fn check_fact(
135        &self,
136        ctx: &FactContext<'_>,
137        vcode: &mut VCode<Self::MInst>,
138        inst: InsnIndex,
139        state: &mut pcc::FactFlowState,
140    ) -> PccResult<()> {
141        pcc::check(ctx, vcode, inst, state)
142    }
143
144    type FactFlowState = pcc::FactFlowState;
145}