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 10 use crate::ir::Inst as IRInst; 11 use crate::ir::condcodes::{FloatCC, IntCC}; 12 use crate::ir::pcc::{FactContext, PccResult}; 13 use crate::ir::{Opcode, Value}; 14 use crate::isa::aarch64::AArch64Backend; 15 use crate::isa::aarch64::inst::*; 16 use crate::isa::aarch64::pcc; 17 use crate::machinst::lower::*; 18 use crate::machinst::*; 19 20 pub mod isle; 21 22 //============================================================================ 23 // Lowering: convert instruction inputs to forms that we can use. 24 25 fn 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 56 pub(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 71 pub(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 114 impl 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 } 146