diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7e7b71e77822..8040ec432386 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -150,11 +150,9 @@ jobs: # Check a few builds of the cranelift backend # - only x86 backend support, # - only arm64 backend support, - # - experimental arm32 support, # - no debug_assertions. - run: cargo check --manifest-path=./cranelift/Cargo.toml --bin clif-util --no-default-features --features=cranelift-codegen/arm64 - run: cargo check --manifest-path=./cranelift/Cargo.toml --bin clif-util --no-default-features --features=cranelift-codegen/x86 - - run: cargo check --manifest-path=./cranelift/Cargo.toml --bin clif-util --no-default-features --features=cranelift-codegen/arm32 - run: cargo check --manifest-path=./cranelift/Cargo.toml --bin clif-util env: CARGO_PROFILE_DEV_DEBUG_ASSERTIONS: false diff --git a/cranelift/Cargo.toml b/cranelift/Cargo.toml index b6a66b0c8edf..f7335a819d5e 100644 --- a/cranelift/Cargo.toml +++ b/cranelift/Cargo.toml @@ -47,6 +47,5 @@ structopt = "0.3.17" default = ["disas", "wasm", "cranelift-codegen/all-arch", "souper-harvest"] disas = ["capstone"] wasm = ["wat", "cranelift-wasm"] -experimental_arm32 = ["cranelift-codegen/arm32", "cranelift-filetests/experimental_arm32"] souper-harvest = ["cranelift-codegen/souper-harvest", "rayon"] all-arch = ["cranelift-codegen/all-arch"] diff --git a/cranelift/codegen/Cargo.toml b/cranelift/codegen/Cargo.toml index c2e819c89f70..4003ee8b7ec7 100644 --- a/cranelift/codegen/Cargo.toml +++ b/cranelift/codegen/Cargo.toml @@ -62,7 +62,6 @@ unwind = ["gimli"] x86 = [] arm64 = [] s390x = [] -arm32 = [] # Work-in-progress codegen backend for ARM. # Stub feature that does nothing, for Cargo-features compatibility: the new # backend is the default now. diff --git a/cranelift/codegen/meta/src/isa/arm32.rs b/cranelift/codegen/meta/src/isa/arm32.rs deleted file mode 100644 index 1c3b4d1fe032..000000000000 --- a/cranelift/codegen/meta/src/isa/arm32.rs +++ /dev/null @@ -1,15 +0,0 @@ -use crate::cdsl::isa::TargetIsa; -use crate::cdsl::settings::{SettingGroup, SettingGroupBuilder}; - -use crate::shared::Definitions as SharedDefinitions; - -fn define_settings(_shared: &SettingGroup) -> SettingGroup { - let setting = SettingGroupBuilder::new("arm32"); - setting.build() -} - -pub(crate) fn define(shared_defs: &mut SharedDefinitions) -> TargetIsa { - let settings = define_settings(&shared_defs.settings); - - TargetIsa::new("arm32", settings) -} diff --git a/cranelift/codegen/meta/src/isa/mod.rs b/cranelift/codegen/meta/src/isa/mod.rs index 9465e63b2690..6411932b16ad 100644 --- a/cranelift/codegen/meta/src/isa/mod.rs +++ b/cranelift/codegen/meta/src/isa/mod.rs @@ -3,7 +3,6 @@ use crate::cdsl::isa::TargetIsa; use crate::shared::Definitions as SharedDefinitions; use std::fmt; -mod arm32; mod arm64; mod s390x; pub(crate) mod x86; @@ -12,7 +11,6 @@ pub(crate) mod x86; #[derive(PartialEq, Copy, Clone)] pub enum Isa { X86, - Arm32, Arm64, S390x, } @@ -32,14 +30,13 @@ impl Isa { "aarch64" => Some(Isa::Arm64), "s390x" => Some(Isa::S390x), x if ["x86_64", "i386", "i586", "i686"].contains(&x) => Some(Isa::X86), - x if x.starts_with("arm") || arch.starts_with("thumb") => Some(Isa::Arm32), _ => None, } } /// Returns all supported isa targets. pub fn all() -> &'static [Isa] { - &[Isa::X86, Isa::Arm32, Isa::Arm64, Isa::S390x] + &[Isa::X86, Isa::Arm64, Isa::S390x] } } @@ -48,7 +45,6 @@ impl fmt::Display for Isa { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Isa::X86 => write!(f, "x86"), - Isa::Arm32 => write!(f, "arm32"), Isa::Arm64 => write!(f, "arm64"), Isa::S390x => write!(f, "s390x"), } @@ -59,7 +55,6 @@ pub(crate) fn define(isas: &[Isa], shared_defs: &mut SharedDefinitions) -> Vec x86::define(shared_defs), - Isa::Arm32 => arm32::define(shared_defs), Isa::Arm64 => arm64::define(shared_defs), Isa::S390x => s390x::define(shared_defs), }) diff --git a/cranelift/codegen/src/isa/arm32/abi.rs b/cranelift/codegen/src/isa/arm32/abi.rs deleted file mode 100644 index 4fcf42386027..000000000000 --- a/cranelift/codegen/src/isa/arm32/abi.rs +++ /dev/null @@ -1,506 +0,0 @@ -//! Implementation of the 32-bit ARM ABI. - -use crate::ir; -use crate::ir::types::*; -use crate::isa; -use crate::isa::arm32::inst::*; -use crate::machinst::*; -use crate::settings; -use crate::{CodegenError, CodegenResult}; -use alloc::boxed::Box; -use alloc::vec::Vec; -use regalloc::{RealReg, Reg, RegClass, Set, Writable}; -use smallvec::{smallvec, SmallVec}; - -/// Support for the ARM ABI from the callee side (within a function body). -pub(crate) type Arm32ABICallee = ABICalleeImpl; - -/// Support for the ARM ABI from the caller side (at a callsite). -pub(crate) type Arm32ABICaller = ABICallerImpl; - -/// This is the limit for the size of argument and return-value areas on the -/// stack. We place a reasonable limit here to avoid integer overflow issues -/// with 32-bit arithmetic: for now, 128 MB. -static STACK_ARG_RET_SIZE_LIMIT: u64 = 128 * 1024 * 1024; - -/// ARM-specific ABI behavior. This struct just serves as an implementation -/// point for the trait; it is never actually instantiated. -pub(crate) struct Arm32MachineDeps; - -impl Into for StackAMode { - fn into(self) -> AMode { - match self { - StackAMode::FPOffset(off, ty) => AMode::FPOffset(off, ty), - StackAMode::NominalSPOffset(off, ty) => AMode::NominalSPOffset(off, ty), - StackAMode::SPOffset(off, ty) => AMode::SPOffset(off, ty), - } - } -} - -impl ABIMachineSpec for Arm32MachineDeps { - type I = Inst; - - fn word_bits() -> u32 { - 32 - } - - /// Return required stack alignment in bytes. - fn stack_align(_call_conv: isa::CallConv) -> u32 { - 8 - } - - fn compute_arg_locs( - _call_conv: isa::CallConv, - _flags: &settings::Flags, - params: &[ir::AbiParam], - args_or_rets: ArgsOrRets, - add_ret_area_ptr: bool, - ) -> CodegenResult<(Vec, i64, Option)> { - let mut next_rreg = 0; - let mut next_stack: u64 = 0; - let mut ret = vec![]; - let mut stack_args = vec![]; - - let max_reg_val = 4; // r0-r3 - - for i in 0..params.len() { - let param = params[i]; - - // Validate "purpose". - match ¶m.purpose { - &ir::ArgumentPurpose::VMContext - | &ir::ArgumentPurpose::Normal - | &ir::ArgumentPurpose::StackLimit - | &ir::ArgumentPurpose::SignatureId => {} - _ => panic!( - "Unsupported argument purpose {:?} in signature: {:?}", - param.purpose, params - ), - } - assert!(param.value_type.bits() <= 32); - - if next_rreg < max_reg_val { - let reg = rreg(next_rreg); - - ret.push(ABIArg::reg( - reg.to_real_reg(), - param.value_type, - param.extension, - param.purpose, - )); - next_rreg += 1; - } else { - // Arguments are stored on stack in reversed order. - // https://static.docs.arm.com/ihi0042/g/aapcs32.pdf - - // Stack offset is not known yet. Store param info for later. - stack_args.push((param.value_type, param.extension, param.purpose)); - next_stack += 4; - } - } - - let extra_arg = if add_ret_area_ptr { - debug_assert!(args_or_rets == ArgsOrRets::Args); - if next_rreg < max_reg_val { - ret.push(ABIArg::reg( - rreg(next_rreg).to_real_reg(), - I32, - ir::ArgumentExtension::None, - ir::ArgumentPurpose::Normal, - )); - } else { - stack_args.push(( - I32, - ir::ArgumentExtension::None, - ir::ArgumentPurpose::Normal, - )); - next_stack += 4; - } - Some(ret.len() - 1) - } else { - None - }; - - // Now we can assign proper stack offsets to params. - let max_stack = next_stack; - for (ty, ext, purpose) in stack_args.into_iter().rev() { - next_stack -= 4; - ret.push(ABIArg::stack( - (max_stack - next_stack) as i64, - ty, - ext, - purpose, - )); - } - assert_eq!(next_stack, 0); - - next_stack = (next_stack + 7) & !7; - - // To avoid overflow issues, limit the arg/return size to something - // reasonable -- here, 128 MB. - if next_stack > STACK_ARG_RET_SIZE_LIMIT { - return Err(CodegenError::ImplLimitExceeded); - } - - Ok((ret, next_stack as i64, extra_arg)) - } - - fn fp_to_arg_offset(_call_conv: isa::CallConv, _flags: &settings::Flags) -> i64 { - 8 // frame pointer and link register - } - - fn gen_load_stack(mem: StackAMode, into_reg: Writable, ty: Type) -> Inst { - Inst::gen_load(into_reg, mem.into(), ty) - } - - fn gen_store_stack(mem: StackAMode, from_reg: Reg, ty: Type) -> Inst { - Inst::gen_store(from_reg, mem.into(), ty) - } - - fn gen_move(to_reg: Writable, from_reg: Reg, ty: Type) -> Inst { - Inst::gen_move(to_reg, from_reg, ty) - } - - fn gen_extend( - to_reg: Writable, - from_reg: Reg, - is_signed: bool, - from_bits: u8, - to_bits: u8, - ) -> Inst { - assert!(to_bits == 32); - assert!(from_bits < 32); - Inst::Extend { - rd: to_reg, - rm: from_reg, - signed: is_signed, - from_bits, - } - } - - fn gen_ret() -> Inst { - Inst::Ret - } - - fn gen_epilogue_placeholder() -> Inst { - Inst::EpiloguePlaceholder - } - - fn gen_add_imm(into_reg: Writable, from_reg: Reg, imm: u32) -> SmallInstVec { - let mut insts = SmallVec::new(); - - if let Some(imm12) = UImm12::maybe_from_i64(imm as i64) { - insts.push(Inst::AluRRImm12 { - alu_op: ALUOp::Add, - rd: into_reg, - rn: from_reg, - imm12, - }); - } else { - let scratch2 = writable_tmp2_reg(); - insts.extend(Inst::load_constant(scratch2, imm)); - insts.push(Inst::AluRRRShift { - alu_op: ALUOp::Add, - rd: into_reg, - rn: from_reg, - rm: scratch2.to_reg(), - shift: None, - }); - } - insts - } - - fn gen_stack_lower_bound_trap(limit_reg: Reg) -> SmallInstVec { - let mut insts = SmallVec::new(); - insts.push(Inst::Cmp { - rn: sp_reg(), - rm: limit_reg, - }); - insts.push(Inst::TrapIf { - trap_info: ir::TrapCode::StackOverflow, - // Here `Lo` == "less than" when interpreting the two - // operands as unsigned integers. - cond: Cond::Lo, - }); - insts - } - - fn gen_get_stack_addr(mem: StackAMode, into_reg: Writable, _ty: Type) -> Inst { - let mem = mem.into(); - Inst::LoadAddr { rd: into_reg, mem } - } - - fn get_stacklimit_reg() -> Reg { - ip_reg() - } - - fn gen_load_base_offset(into_reg: Writable, base: Reg, offset: i32, ty: Type) -> Inst { - let mem = AMode::RegOffset(base, offset as i64); - Inst::gen_load(into_reg, mem, ty) - } - - fn gen_store_base_offset(base: Reg, offset: i32, from_reg: Reg, ty: Type) -> Inst { - let mem = AMode::RegOffset(base, offset as i64); - Inst::gen_store(from_reg, mem, ty) - } - - fn gen_sp_reg_adjust(amount: i32) -> SmallInstVec { - let mut ret = SmallVec::new(); - - if amount == 0 { - return ret; - } - let (amount, is_sub) = if amount > 0 { - (amount, false) - } else { - (-amount, true) - }; - - let alu_op = if is_sub { ALUOp::Sub } else { ALUOp::Add }; - - if let Some(imm12) = UImm12::maybe_from_i64(amount as i64) { - ret.push(Inst::AluRRImm12 { - alu_op, - rd: writable_sp_reg(), - rn: sp_reg(), - imm12, - }); - } else { - let tmp = writable_ip_reg(); - ret.extend(Inst::load_constant(tmp, amount as u32)); - ret.push(Inst::AluRRRShift { - alu_op, - rd: writable_sp_reg(), - rn: sp_reg(), - rm: tmp.to_reg(), - shift: None, - }); - } - ret - } - - fn gen_nominal_sp_adj(offset: i32) -> Inst { - let offset = i64::from(offset); - Inst::VirtualSPOffsetAdj { offset } - } - - fn gen_prologue_frame_setup(_: &settings::Flags) -> SmallInstVec { - let mut ret = SmallVec::new(); - let reg_list = vec![fp_reg(), lr_reg()]; - ret.push(Inst::Push { reg_list }); - ret.push(Inst::Mov { - rd: writable_fp_reg(), - rm: sp_reg(), - }); - ret - } - - fn gen_epilogue_frame_restore(_: &settings::Flags) -> SmallInstVec { - let mut ret = SmallVec::new(); - ret.push(Inst::Mov { - rd: writable_sp_reg(), - rm: fp_reg(), - }); - let reg_list = vec![writable_fp_reg(), writable_lr_reg()]; - ret.push(Inst::Pop { reg_list }); - ret - } - - fn gen_probestack(_: u32) -> SmallInstVec { - // TODO: implement if we ever require stack probes on ARM32 (unlikely - // unless Lucet is ported) - smallvec![] - } - - /// Returns stack bytes used as well as instructions. Does not adjust - /// nominal SP offset; caller will do that. - fn gen_clobber_save( - _call_conv: isa::CallConv, - _setup_frame: bool, - _flags: &settings::Flags, - clobbered_callee_saves: &Vec>, - fixed_frame_storage_size: u32, - _outgoing_args_size: u32, - ) -> (u64, SmallVec<[Inst; 16]>) { - let mut insts = SmallVec::new(); - if fixed_frame_storage_size > 0 { - insts.extend(Self::gen_sp_reg_adjust(-(fixed_frame_storage_size as i32)).into_iter()); - } - let mut clobbered_vec: Vec<_> = clobbered_callee_saves - .into_iter() - .map(|r| r.to_reg().to_reg()) - .collect(); - if clobbered_vec.len() % 2 == 1 { - // For alignment purposes. - clobbered_vec.push(ip_reg()); - } - let stack_used = clobbered_vec.len() * 4; - if !clobbered_vec.is_empty() { - insts.push(Inst::Push { - reg_list: clobbered_vec, - }); - } - - (stack_used as u64, insts) - } - - fn gen_clobber_restore( - call_conv: isa::CallConv, - _flags: &settings::Flags, - clobbers: &Set>, - _fixed_frame_storage_size: u32, - _outgoing_args_size: u32, - ) -> SmallVec<[Inst; 16]> { - let mut insts = SmallVec::new(); - let clobbered_vec = Self::get_clobbered_callee_saves(call_conv, clobbers); - let mut clobbered_vec: Vec<_> = clobbered_vec - .into_iter() - .map(|r| Writable::from_reg(r.to_reg().to_reg())) - .collect(); - if clobbered_vec.len() % 2 == 1 { - clobbered_vec.push(writable_ip_reg()); - } - if !clobbered_vec.is_empty() { - insts.push(Inst::Pop { - reg_list: clobbered_vec, - }); - } - insts - } - - fn gen_call( - dest: &CallDest, - uses: Vec, - defs: Vec>, - opcode: ir::Opcode, - tmp: Writable, - _callee_conv: isa::CallConv, - _caller_conv: isa::CallConv, - ) -> SmallVec<[(InstIsSafepoint, Inst); 2]> { - let mut insts = SmallVec::new(); - match &dest { - &CallDest::ExtName(ref name, RelocDistance::Near) => insts.push(( - InstIsSafepoint::Yes, - Inst::Call { - info: Box::new(CallInfo { - dest: name.clone(), - uses, - defs, - opcode, - }), - }, - )), - &CallDest::ExtName(ref name, RelocDistance::Far) => { - insts.push(( - InstIsSafepoint::No, - Inst::LoadExtName { - rt: tmp, - name: Box::new(name.clone()), - offset: 0, - }, - )); - insts.push(( - InstIsSafepoint::Yes, - Inst::CallInd { - info: Box::new(CallIndInfo { - rm: tmp.to_reg(), - uses, - defs, - opcode, - }), - }, - )); - } - &CallDest::Reg(reg) => insts.push(( - InstIsSafepoint::Yes, - Inst::CallInd { - info: Box::new(CallIndInfo { - rm: *reg, - uses, - defs, - opcode, - }), - }, - )), - } - - insts - } - - fn gen_memcpy( - _call_conv: isa::CallConv, - _dst: Reg, - _src: Reg, - _size: usize, - ) -> SmallVec<[Self::I; 8]> { - unimplemented!("StructArgs not implemented for ARM32 yet"); - } - - fn get_number_of_spillslots_for_value(rc: RegClass) -> u32 { - match rc { - RegClass::I32 => 1, - _ => panic!("Unexpected register class!"), - } - } - - fn get_virtual_sp_offset_from_state(s: &EmitState) -> i64 { - s.virtual_sp_offset - } - - fn get_nominal_sp_to_fp(s: &EmitState) -> i64 { - s.nominal_sp_to_fp - } - - fn get_regs_clobbered_by_call(_: isa::CallConv) -> Vec> { - let mut caller_saved = Vec::new(); - for i in 0..15 { - let r = writable_rreg(i); - if is_reg_clobbered_by_call(r.to_reg().to_real_reg()) { - caller_saved.push(r); - } - } - caller_saved - } - - fn get_ext_mode( - _call_conv: isa::CallConv, - specified: ir::ArgumentExtension, - ) -> ir::ArgumentExtension { - specified - } - - fn get_clobbered_callee_saves( - _call_conv: isa::CallConv, - regs: &Set>, - ) -> Vec> { - let mut ret = Vec::new(); - for ® in regs.iter() { - if is_callee_save(reg.to_reg()) { - ret.push(reg); - } - } - - // Sort registers for deterministic code output. - ret.sort_by_key(|r| r.to_reg().get_index()); - ret - } - - fn is_frame_setup_needed( - _is_leaf: bool, - _stack_args_size: u32, - _num_clobbered_callee_saves: usize, - _fixed_frame_storage_size: u32, - ) -> bool { - true - } -} - -fn is_callee_save(r: RealReg) -> bool { - let enc = r.get_hw_encoding(); - 4 <= enc && enc <= 10 -} - -fn is_reg_clobbered_by_call(r: RealReg) -> bool { - let enc = r.get_hw_encoding(); - enc <= 3 -} diff --git a/cranelift/codegen/src/isa/arm32/inst/args.rs b/cranelift/codegen/src/isa/arm32/inst/args.rs deleted file mode 100644 index 2c1b8e97d6ab..000000000000 --- a/cranelift/codegen/src/isa/arm32/inst/args.rs +++ /dev/null @@ -1,335 +0,0 @@ -//! 32-bit ARM ISA definitions: instruction arguments. - -use crate::isa::arm32::inst::*; - -use regalloc::{PrettyPrint, RealRegUniverse, Reg}; - -use std::string::String; - -/// A shift operator for a register or immediate. -#[derive(Clone, Copy, Debug)] -#[repr(u8)] -pub enum ShiftOp { - LSL = 0b00, - LSR = 0b01, - ASR = 0b10, - ROR = 0b11, -} - -impl ShiftOp { - /// Get the encoding of this shift op. - pub fn bits(self) -> u8 { - self as u8 - } -} - -/// A shift operator amount. -#[derive(Clone, Copy, Debug)] -pub struct ShiftOpShiftImm(u8); - -impl ShiftOpShiftImm { - /// Maximum shift for shifted-register operands. - pub const MAX_SHIFT: u32 = 31; - - /// Create a new shiftop shift amount, if possible. - pub fn maybe_from_shift(shift: u32) -> Option { - if shift <= Self::MAX_SHIFT { - Some(ShiftOpShiftImm(shift as u8)) - } else { - None - } - } - - /// Return the shift amount. - pub fn value(self) -> u8 { - self.0 - } -} - -/// A shift operator with an amount, guaranteed to be within range. -#[derive(Clone, Debug)] -pub struct ShiftOpAndAmt { - op: ShiftOp, - shift: ShiftOpShiftImm, -} - -impl ShiftOpAndAmt { - pub fn new(op: ShiftOp, shift: ShiftOpShiftImm) -> ShiftOpAndAmt { - ShiftOpAndAmt { op, shift } - } - - /// Get the shift op. - pub fn op(&self) -> ShiftOp { - self.op - } - - /// Get the shift amount. - pub fn amt(&self) -> ShiftOpShiftImm { - self.shift - } -} - -// An unsigned 8-bit immediate. -#[derive(Clone, Copy, Debug)] -pub struct UImm8 { - /// The value. - value: u8, -} - -impl UImm8 { - pub fn maybe_from_i64(value: i64) -> Option { - if 0 <= value && value < (1 << 8) { - Some(UImm8 { value: value as u8 }) - } else { - None - } - } - - /// Bits for encoding. - pub fn bits(&self) -> u32 { - u32::from(self.value) - } -} - -/// An unsigned 12-bit immediate. -#[derive(Clone, Copy, Debug)] -pub struct UImm12 { - /// The value. - value: u16, -} - -impl UImm12 { - pub fn maybe_from_i64(value: i64) -> Option { - if 0 <= value && value < (1 << 12) { - Some(UImm12 { - value: value as u16, - }) - } else { - None - } - } - - /// Bits for encoding. - pub fn bits(&self) -> u32 { - u32::from(self.value) - } -} - -/// An addressing mode specified for a load/store operation. -#[derive(Clone, Debug)] -pub enum AMode { - // Real addressing modes - /// Register plus register offset, which can be shifted left by imm2. - RegReg(Reg, Reg, u8), - - /// Unsigned 12-bit immediate offset from reg. - RegOffset12(Reg, UImm12), - - /// Immediate offset from program counter aligned to 4. - /// Cannot be used by store instructions. - PCRel(i32), - - // Virtual addressing modes that are lowered at emission time: - /// Immediate offset from reg. - RegOffset(Reg, i64), - - /// Signed immediate offset from stack pointer. - SPOffset(i64, Type), - - /// Offset from the frame pointer. - FPOffset(i64, Type), - - /// Signed immediate offset from "nominal stack pointer". - NominalSPOffset(i64, Type), -} - -impl AMode { - /// Memory reference using the sum of two registers as an address. - pub fn reg_plus_reg(reg1: Reg, reg2: Reg, shift_amt: u8) -> AMode { - assert!(shift_amt <= 3); - AMode::RegReg(reg1, reg2, shift_amt) - } - - /// Memory reference using the sum of a register and an immediate offset - /// as an address. - pub fn reg_plus_imm(reg: Reg, offset: i64) -> AMode { - AMode::RegOffset(reg, offset) - } -} - -/// Condition for conditional branches. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -#[repr(u8)] -pub enum Cond { - Eq = 0, - Ne = 1, - Hs = 2, - Lo = 3, - Mi = 4, - Pl = 5, - Vs = 6, - Vc = 7, - Hi = 8, - Ls = 9, - Ge = 10, - Lt = 11, - Gt = 12, - Le = 13, - Al = 14, -} - -impl Cond { - /// Return the inverted condition. - pub fn invert(self) -> Cond { - match self { - Cond::Eq => Cond::Ne, - Cond::Ne => Cond::Eq, - - Cond::Hs => Cond::Lo, - Cond::Lo => Cond::Hs, - - Cond::Mi => Cond::Pl, - Cond::Pl => Cond::Mi, - - Cond::Vs => Cond::Vc, - Cond::Vc => Cond::Vs, - - Cond::Hi => Cond::Ls, - Cond::Ls => Cond::Hi, - - Cond::Ge => Cond::Lt, - Cond::Lt => Cond::Ge, - - Cond::Gt => Cond::Le, - Cond::Le => Cond::Gt, - - Cond::Al => panic!("Cannot inverse {:?} condition", self), - } - } - - /// Return the machine encoding of this condition. - pub fn bits(self) -> u16 { - self as u16 - } -} - -/// A branch target. Either unresolved (basic-block index) or resolved (offset -/// from end of current instruction). -#[derive(Clone, Copy, Debug)] -pub enum BranchTarget { - /// An unresolved reference to a Label. - Label(MachLabel), - /// A fixed PC offset. - ResolvedOffset(i32), -} - -impl BranchTarget { - /// Return the target's label, if it is a label-based target. - pub fn as_label(self) -> Option { - match self { - BranchTarget::Label(l) => Some(l), - _ => None, - } - } - - // Ready for embedding in instruction. - fn as_offset(self, inst_16_bit: bool) -> i32 { - match self { - BranchTarget::ResolvedOffset(off) => { - if inst_16_bit { - // pc is equal to end of the current inst + 2. - (off - 2) >> 1 - } else { - // pc points to end of the current inst. - off >> 1 - } - } - _ => 0, - } - } - - // For 32-bit unconditional jump. - pub fn as_off24(self) -> u32 { - let off = self.as_offset(false); - assert!(off < (1 << 24)); - assert!(off >= -(1 << 24)); - (off as u32) & ((1 << 24) - 1) - } - - // For 32-bit conditional jump. - pub fn as_off20(self) -> u32 { - let off = self.as_offset(false); - assert!(off < (1 << 20)); - assert!(off >= -(1 << 20)); - (off as u32) & ((1 << 20) - 1) - } -} - -impl PrettyPrint for ShiftOpAndAmt { - fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String { - let op = match self.op() { - ShiftOp::LSL => "lsl", - ShiftOp::LSR => "lsr", - ShiftOp::ASR => "asr", - ShiftOp::ROR => "ror", - }; - format!("{} #{}", op, self.amt().value()) - } -} - -impl PrettyPrint for UImm8 { - fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String { - format!("#{}", self.value) - } -} - -impl PrettyPrint for UImm12 { - fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String { - format!("#{}", self.value) - } -} - -impl PrettyPrint for AMode { - fn show_rru(&self, mb_rru: Option<&RealRegUniverse>) -> String { - match self { - &AMode::RegReg(rn, rm, imm2) => { - let shift = if imm2 != 0 { - format!(", lsl #{}", imm2) - } else { - "".to_string() - }; - format!( - "[{}, {}{}]", - rn.show_rru(mb_rru), - rm.show_rru(mb_rru), - shift - ) - } - &AMode::RegOffset12(rn, off) => { - format!("[{}, {}]", rn.show_rru(mb_rru), off.show_rru(mb_rru)) - } - &AMode::PCRel(off) => format!("[pc, #{}]", off), - &AMode::RegOffset(..) - | &AMode::SPOffset(..) - | &AMode::FPOffset(..) - | &AMode::NominalSPOffset(..) => panic!("unexpected mem mode"), - } - } -} - -impl PrettyPrint for Cond { - fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String { - let mut s = format!("{:?}", self); - s.make_ascii_lowercase(); - s - } -} - -impl PrettyPrint for BranchTarget { - fn show_rru(&self, _mb_rru: Option<&RealRegUniverse>) -> String { - match self { - &BranchTarget::Label(label) => format!("label{:?}", label.get()), - &BranchTarget::ResolvedOffset(off) => format!("{}", off), - } - } -} diff --git a/cranelift/codegen/src/isa/arm32/inst/emit.rs b/cranelift/codegen/src/isa/arm32/inst/emit.rs deleted file mode 100644 index 7f6aa6ba62c3..000000000000 --- a/cranelift/codegen/src/isa/arm32/inst/emit.rs +++ /dev/null @@ -1,821 +0,0 @@ -//! 32-bit ARM ISA: binary code emission. - -use crate::binemit::{Reloc, StackMap}; -use crate::ir::SourceLoc; -use crate::isa::arm32::inst::*; - -use core::convert::TryFrom; - -/// Memory addressing mode finalization: convert "special" modes (e.g., -/// nominal stack offset) into real addressing modes, possibly by -/// emitting some helper instructions that come immediately before the use -/// of this amode. -pub fn mem_finalize(mem: &AMode, state: &EmitState) -> (SmallVec<[Inst; 4]>, AMode) { - match mem { - &AMode::RegOffset(_, off) - | &AMode::SPOffset(off, _) - | &AMode::FPOffset(off, _) - | &AMode::NominalSPOffset(off, _) => { - let basereg = match mem { - &AMode::RegOffset(reg, _) => reg, - &AMode::SPOffset(..) | &AMode::NominalSPOffset(..) => sp_reg(), - &AMode::FPOffset(..) => fp_reg(), - _ => unreachable!(), - }; - let adj = match mem { - &AMode::NominalSPOffset(..) => { - log::trace!( - "mem_finalize: nominal SP offset {} + adj {} -> {}", - off, - state.virtual_sp_offset, - off + state.virtual_sp_offset - ); - state.virtual_sp_offset - } - _ => 0, - }; - let off = off + adj; - - assert!(-(1 << 31) <= off && off <= (1 << 32)); - - if let Some(off) = UImm12::maybe_from_i64(off) { - let mem = AMode::RegOffset12(basereg, off); - (smallvec![], mem) - } else { - let tmp = writable_ip_reg(); - let const_insts = Inst::load_constant(tmp, off as u32); - let mem = AMode::reg_plus_reg(basereg, tmp.to_reg(), 0); - (const_insts, mem) - } - } - // Just assert immediate is valid here. - _ => (smallvec![], mem.clone()), - } -} - -//============================================================================= -// Instructions and subcomponents: emission - -fn machreg_to_gpr(m: Reg) -> u16 { - assert_eq!(m.get_class(), RegClass::I32); - u16::try_from(m.to_real_reg().get_hw_encoding()).unwrap() -} - -fn machreg_to_gpr_lo(m: Reg) -> u16 { - let gpr_lo = machreg_to_gpr(m); - assert!(gpr_lo < 8); - gpr_lo -} - -fn machreg_is_lo(m: Reg) -> bool { - machreg_to_gpr(m) < 8 -} - -fn enc_16_rr(bits_15_6: u16, rd: Reg, rm: Reg) -> u16 { - (bits_15_6 << 6) | machreg_to_gpr_lo(rd) | (machreg_to_gpr_lo(rm) << 3) -} - -fn enc_16_rr_any(bits_15_8: u16, rd: Reg, rm: Reg) -> u16 { - let rd = machreg_to_gpr(rd); - (bits_15_8 << 8) | (rd & 0x7) | ((rd >> 3) << 7) | (machreg_to_gpr(rm) << 3) -} - -fn enc_16_mov(rd: Writable, rm: Reg) -> u16 { - enc_16_rr_any(0b01000110, rd.to_reg(), rm) -} - -fn enc_16_it(cond: Cond, insts: &Vec) -> u16 { - let cond = cond.bits(); - let mut mask: u16 = 0; - for inst in insts.iter().skip(1) { - if inst.then { - mask |= cond & 0x1; - } else { - mask |= (cond & 0x1) ^ 0x1; - } - mask <<= 1; - } - mask |= 0x1; - mask <<= 4 - insts.len(); - 0b1011_1111_0000_0000 | (cond << 4) | mask -} - -fn enc_32_regs( - mut inst: u32, - reg_0: Option, - reg_8: Option, - reg_12: Option, - reg_16: Option, -) -> u32 { - if let Some(reg_0) = reg_0 { - inst |= u32::from(machreg_to_gpr(reg_0)); - } - if let Some(reg_8) = reg_8 { - inst |= u32::from(machreg_to_gpr(reg_8)) << 8; - } - if let Some(reg_12) = reg_12 { - inst |= u32::from(machreg_to_gpr(reg_12)) << 12; - } - if let Some(reg_16) = reg_16 { - inst |= u32::from(machreg_to_gpr(reg_16)) << 16; - } - inst -} - -fn enc_32_reg_shift(inst: u32, shift: &Option) -> u32 { - match shift { - Some(shift) => { - let op = u32::from(shift.op().bits()); - let amt = u32::from(shift.amt().value()); - let imm2 = amt & 0x3; - let imm3 = (amt >> 2) & 0x7; - - inst | (op << 4) | (imm2 << 6) | (imm3 << 12) - } - None => inst, - } -} - -fn enc_32_r_imm16(bits_31_20: u32, rd: Reg, imm16: u16) -> u32 { - let imm16 = u32::from(imm16); - let imm8 = imm16 & 0xff; - let imm3 = (imm16 >> 8) & 0x7; - let i = (imm16 >> 11) & 0x1; - let imm4 = (imm16 >> 12) & 0xf; - - let inst = ((bits_31_20 << 20) & !(1 << 26)) | imm8 | (imm3 << 12) | (imm4 << 16) | (i << 26); - enc_32_regs(inst, None, Some(rd), None, None) -} - -fn enc_32_rrr(bits_31_20: u32, bits_15_12: u32, bits_7_4: u32, rd: Reg, rm: Reg, rn: Reg) -> u32 { - let inst = (bits_31_20 << 20) | (bits_15_12 << 12) | (bits_7_4 << 4); - enc_32_regs(inst, Some(rm), Some(rd), None, Some(rn)) -} - -fn enc_32_imm12(inst: u32, imm12: UImm12) -> u32 { - let imm12 = imm12.bits(); - let imm8 = imm12 & 0xff; - let imm3 = (imm12 >> 8) & 0x7; - let i = (imm12 >> 11) & 0x1; - inst | imm8 | (imm3 << 12) | (i << 26) -} - -fn enc_32_mem_r(bits_24_20: u32, rt: Reg, rn: Reg, rm: Reg, imm2: u8) -> u32 { - let imm2 = u32::from(imm2); - let inst = (imm2 << 4) | (bits_24_20 << 20) | (0b11111 << 27); - enc_32_regs(inst, Some(rm), None, Some(rt), Some(rn)) -} - -fn enc_32_mem_off12(bits_24_20: u32, rt: Reg, rn: Reg, off12: UImm12) -> u32 { - let off12 = off12.bits(); - let inst = off12 | (bits_24_20 << 20) | (0b11111 << 27); - enc_32_regs(inst, None, None, Some(rt), Some(rn)) -} - -fn enc_32_jump(target: BranchTarget) -> u32 { - let off24 = target.as_off24(); - let imm11 = off24 & 0x7ff; - let imm10 = (off24 >> 11) & 0x3ff; - let i2 = (off24 >> 21) & 0x1; - let i1 = (off24 >> 22) & 0x1; - let s = (off24 >> 23) & 0x1; - let j1 = (i1 ^ s) ^ 1; - let j2 = (i2 ^ s) ^ 1; - - 0b11110_0_0000000000_10_0_1_0_00000000000 - | imm11 - | (j2 << 11) - | (j1 << 13) - | (imm10 << 16) - | (s << 26) -} - -fn enc_32_cond_branch(cond: Cond, target: BranchTarget) -> u32 { - let cond = u32::from(cond.bits()); - let off20 = target.as_off20(); - let imm11 = off20 & 0x7ff; - let imm6 = (off20 >> 11) & 0x3f; - let j1 = (off20 >> 17) & 0x1; - let j2 = (off20 >> 18) & 0x1; - let s = (off20 >> 19) & 0x1; - - 0b11110_0_0000_000000_10_0_0_0_00000000000 - | imm11 - | (j2 << 11) - | (j1 << 13) - | (imm6 << 16) - | (cond << 22) - | (s << 26) -} - -fn u32_swap_halfwords(x: u32) -> u32 { - (x >> 16) | (x << 16) -} - -fn emit_32(inst: u32, sink: &mut MachBuffer) { - let inst_hi = (inst >> 16) as u16; - let inst_lo = (inst & 0xffff) as u16; - sink.put2(inst_hi); - sink.put2(inst_lo); -} - -/// State carried between emissions of a sequence of instructions. -#[derive(Default, Clone, Debug)] -pub struct EmitState { - /// Addend to convert nominal-SP offsets to real-SP offsets at the current - /// program point. - pub(crate) virtual_sp_offset: i64, - /// Offset of FP from nominal-SP. - pub(crate) nominal_sp_to_fp: i64, - /// Safepoint stack map for upcoming instruction, as provided to `pre_safepoint()`. - stack_map: Option, - /// Source location of next machine code instruction to be emitted. - cur_srcloc: SourceLoc, -} - -impl MachInstEmitState for EmitState { - fn new(abi: &dyn ABICallee) -> Self { - EmitState { - virtual_sp_offset: 0, - nominal_sp_to_fp: abi.frame_size() as i64, - stack_map: None, - cur_srcloc: SourceLoc::default(), - } - } - - fn pre_safepoint(&mut self, stack_map: StackMap) { - self.stack_map = Some(stack_map); - } - - fn pre_sourceloc(&mut self, srcloc: SourceLoc) { - self.cur_srcloc = srcloc; - } -} - -impl EmitState { - fn take_stack_map(&mut self) -> Option { - self.stack_map.take() - } - - fn clear_post_insn(&mut self) { - self.stack_map = None; - } - - fn cur_srcloc(&self) -> SourceLoc { - self.cur_srcloc - } -} - -pub struct EmitInfo { - flags: settings::Flags, -} - -impl EmitInfo { - pub(crate) fn new(flags: settings::Flags) -> Self { - EmitInfo { flags } - } -} - -impl MachInstEmit for Inst { - type Info = EmitInfo; - type State = EmitState; - - fn emit(&self, sink: &mut MachBuffer, emit_info: &Self::Info, state: &mut EmitState) { - let start_off = sink.cur_offset(); - - match self { - &Inst::Nop0 | &Inst::EpiloguePlaceholder => {} - &Inst::Nop2 => { - sink.put2(0b1011_1111_0000_0000); - } - &Inst::AluRRR { alu_op, rd, rn, rm } => { - let (bits_31_20, bits_15_12, bits_7_4) = match alu_op { - ALUOp::Lsl => (0b111110100000, 0b1111, 0b0000), - ALUOp::Lsr => (0b111110100010, 0b1111, 0b0000), - ALUOp::Asr => (0b111110100100, 0b1111, 0b0000), - ALUOp::Ror => (0b111110100110, 0b1111, 0b0000), - ALUOp::Qadd => (0b111110101000, 0b1111, 0b1000), - ALUOp::Qsub => (0b111110101000, 0b1111, 0b1010), - ALUOp::Mul => (0b111110110000, 0b1111, 0b0000), - ALUOp::Udiv => (0b111110111011, 0b1111, 0b1111), - ALUOp::Sdiv => (0b111110111001, 0b1111, 0b1111), - _ => panic!("Invalid ALUOp {:?} in RRR form!", alu_op), - }; - emit_32( - enc_32_rrr(bits_31_20, bits_15_12, bits_7_4, rd.to_reg(), rm, rn), - sink, - ); - } - &Inst::AluRRRShift { - alu_op, - rd, - rn, - rm, - ref shift, - } => { - let bits_31_24 = 0b111_0101; - let bits_24_20 = match alu_op { - ALUOp::And => 0b00000, - ALUOp::Bic => 0b00010, - ALUOp::Orr => 0b00100, - ALUOp::Orn => 0b00110, - ALUOp::Eor => 0b01000, - ALUOp::Add => 0b10000, - ALUOp::Adds => 0b10001, - ALUOp::Adc => 0b10100, - ALUOp::Adcs => 0b10101, - ALUOp::Sbc => 0b10110, - ALUOp::Sbcs => 0b10111, - ALUOp::Sub => 0b11010, - ALUOp::Subs => 0b11011, - ALUOp::Rsb => 0b11100, - _ => panic!("Invalid ALUOp {:?} in RRRShift form!", alu_op), - }; - let bits_31_20 = (bits_31_24 << 5) | bits_24_20; - let inst = enc_32_rrr(bits_31_20, 0, 0, rd.to_reg(), rm, rn); - let inst = enc_32_reg_shift(inst, shift); - emit_32(inst, sink); - } - &Inst::AluRRShift { - alu_op, - rd, - rm, - ref shift, - } => { - let bits_24_21 = match alu_op { - ALUOp1::Mvn => 0b0011, - ALUOp1::Mov => 0b0010, - }; - let inst = 0b1110101_0000_0_1111_0_000_0000_00_00_0000 | (bits_24_21 << 21); - let inst = enc_32_regs(inst, Some(rm), Some(rd.to_reg()), None, None); - let inst = enc_32_reg_shift(inst, shift); - emit_32(inst, sink); - } - &Inst::AluRRRR { - alu_op, - rd_hi, - rd_lo, - rn, - rm, - } => { - let (bits_22_20, bits_7_4) = match alu_op { - ALUOp::Smull => (0b000, 0b0000), - ALUOp::Umull => (0b010, 0b0000), - _ => panic!("Invalid ALUOp {:?} in RRRR form!", alu_op), - }; - let inst = (0b111110111 << 23) | (bits_22_20 << 20) | (bits_7_4 << 4); - let inst = enc_32_regs( - inst, - Some(rm), - Some(rd_hi.to_reg()), - Some(rd_lo.to_reg()), - Some(rn), - ); - emit_32(inst, sink); - } - &Inst::AluRRImm12 { - alu_op, - rd, - rn, - imm12, - } => { - let bits_24_20 = match alu_op { - ALUOp::Add => 0b00000, - ALUOp::Sub => 0b01010, - _ => panic!("Invalid ALUOp {:?} in RRImm12 form!", alu_op), - }; - let inst = (0b11110_0_1 << 25) | (bits_24_20 << 20); - let inst = enc_32_regs(inst, None, Some(rd.to_reg()), None, Some(rn)); - let inst = enc_32_imm12(inst, imm12); - emit_32(inst, sink); - } - &Inst::AluRRImm8 { - alu_op, - rd, - rn, - imm8, - } => { - let bits_24_20 = match alu_op { - ALUOp::And => 0b00000, - ALUOp::Bic => 0b00010, - ALUOp::Orr => 0b00100, - ALUOp::Orn => 0b00110, - ALUOp::Eor => 0b01000, - ALUOp::Add => 0b10000, - ALUOp::Adds => 0b10001, - ALUOp::Adc => 0b10100, - ALUOp::Adcs => 0b10101, - ALUOp::Sbc => 0b10110, - ALUOp::Sbcs => 0b10111, - ALUOp::Sub => 0b11010, - ALUOp::Subs => 0b11011, - ALUOp::Rsb => 0b11100, - _ => panic!("Invalid ALUOp {:?} in RRImm8 form!", alu_op), - }; - let imm8 = imm8.bits(); - let inst = 0b11110_0_0_00000_0000_0_000_0000_00000000 | imm8 | (bits_24_20 << 20); - let inst = enc_32_regs(inst, None, Some(rd.to_reg()), None, Some(rn)); - emit_32(inst, sink); - } - &Inst::AluRImm8 { alu_op, rd, imm8 } => { - let bits_24_20 = match alu_op { - ALUOp1::Mvn => 0b00110, - ALUOp1::Mov => 0b00100, - }; - let imm8 = imm8.bits(); - let inst = 0b11110_0_0_00000_1111_0_000_0000_00000000 | imm8 | (bits_24_20 << 20); - let inst = enc_32_regs(inst, None, Some(rd.to_reg()), None, None); - emit_32(inst, sink); - } - &Inst::BitOpRR { bit_op, rd, rm } => { - let (bits_22_20, bits_7_4) = match bit_op { - BitOp::Rbit => (0b001, 0b1010), - BitOp::Rev => (0b001, 0b1000), - BitOp::Clz => (0b011, 0b1000), - }; - let inst = - 0b111110101_000_0000_1111_0000_0000_0000 | (bits_22_20 << 20) | (bits_7_4 << 4); - let inst = enc_32_regs(inst, Some(rm), Some(rd.to_reg()), None, Some(rm)); - emit_32(inst, sink); - } - &Inst::Mov { rd, rm } => { - sink.put2(enc_16_mov(rd, rm)); - } - &Inst::MovImm16 { rd, imm16 } => { - emit_32(enc_32_r_imm16(0b11110_0_100100, rd.to_reg(), imm16), sink); - } - &Inst::Movt { rd, imm16 } => { - emit_32(enc_32_r_imm16(0b11110_0_101100, rd.to_reg(), imm16), sink); - } - &Inst::Cmp { rn, rm } => { - // Check which 16-bit encoding is allowed. - if machreg_is_lo(rn) && machreg_is_lo(rm) { - sink.put2(enc_16_rr(0b0100001010, rn, rm)); - } else { - sink.put2(enc_16_rr_any(0b01000101, rn, rm)); - } - } - &Inst::CmpImm8 { rn, imm8 } => { - let inst = 0b11110_0_011011_0000_0_000_1111_00000000 | u32::from(imm8); - let inst = enc_32_regs(inst, None, None, None, Some(rn)); - emit_32(inst, sink); - } - &Inst::Store { rt, ref mem, bits } => { - let (mem_insts, mem) = mem_finalize(mem, state); - for inst in mem_insts.into_iter() { - inst.emit(sink, emit_info, state); - } - let srcloc = state.cur_srcloc(); - if srcloc != SourceLoc::default() { - // Register the offset at which the store instruction starts. - sink.add_trap(srcloc, TrapCode::HeapOutOfBounds); - } - match mem { - AMode::RegReg(rn, rm, imm2) => { - let bits_24_20 = match bits { - 32 => 0b00100, - 16 => 0b00010, - 8 => 0b00000, - _ => panic!("Unsupported store case {:?}", self), - }; - emit_32(enc_32_mem_r(bits_24_20, rt, rn, rm, imm2), sink); - } - AMode::RegOffset12(rn, off12) => { - let bits_24_20 = match bits { - 32 => 0b01100, - 16 => 0b01010, - 8 => 0b01000, - _ => panic!("Unsupported store case {:?}", self), - }; - emit_32(enc_32_mem_off12(bits_24_20, rt, rn, off12), sink); - } - AMode::PCRel(_) => panic!("Unsupported store case {:?}", self), - _ => unreachable!(), - } - } - &Inst::Load { - rt, - ref mem, - bits, - sign_extend, - } => { - let (mem_insts, mem) = mem_finalize(mem, state); - for inst in mem_insts.into_iter() { - inst.emit(sink, emit_info, state); - } - let srcloc = state.cur_srcloc(); - if srcloc != SourceLoc::default() { - // Register the offset at which the load instruction starts. - sink.add_trap(srcloc, TrapCode::HeapOutOfBounds); - } - match mem { - AMode::RegReg(rn, rm, imm2) => { - let bits_24_20 = match (bits, sign_extend) { - (32, _) => 0b00101, - (16, true) => 0b10011, - (16, false) => 0b00011, - (8, true) => 0b10001, - (8, false) => 0b00001, - _ => panic!("Unsupported load case {:?}", self), - }; - emit_32(enc_32_mem_r(bits_24_20, rt.to_reg(), rn, rm, imm2), sink); - } - AMode::RegOffset12(rn, off12) => { - let bits_24_20 = match (bits, sign_extend) { - (32, _) => 0b01101, - (16, true) => 0b11011, - (16, false) => 0b01011, - (8, true) => 0b11001, - (8, false) => 0b01001, - _ => panic!("Unsupported load case {:?}", self), - }; - emit_32(enc_32_mem_off12(bits_24_20, rt.to_reg(), rn, off12), sink); - } - AMode::PCRel(off12) => { - let mut bits_24_20 = match (bits, sign_extend) { - (32, _) => 0b00101, - (16, true) => 0b10011, - (16, false) => 0b00011, - (8, true) => 0b10001, - (8, false) => 0b00001, - _ => panic!("Unsupported load case {:?}", self), - }; - let (u, off12) = if off12 > 0 { (1, off12) } else { (0, -off12) }; - let off12 = UImm12::maybe_from_i64(i64::from(off12)).unwrap(); - bits_24_20 |= u << 3; - - emit_32( - enc_32_mem_off12(bits_24_20, rt.to_reg(), pc_reg(), off12), - sink, - ); - } - _ => unreachable!(), - } - } - &Inst::LoadAddr { rd, ref mem } => { - let (mem_insts, mem) = mem_finalize(mem, state); - for inst in mem_insts.into_iter() { - inst.emit(sink, emit_info, state); - } - let inst = match mem { - AMode::RegReg(reg1, reg2, shift) => { - let shift = u32::from(shift); - let shift_amt = ShiftOpShiftImm::maybe_from_shift(shift).unwrap(); - let shift = ShiftOpAndAmt::new(ShiftOp::LSL, shift_amt); - Inst::AluRRRShift { - alu_op: ALUOp::Add, - rd, - rn: reg1, - rm: reg2, - shift: Some(shift), - } - } - AMode::RegOffset12(reg, imm12) => Inst::AluRRImm12 { - alu_op: ALUOp::Add, - rd, - rn: reg, - imm12, - }, - AMode::PCRel(off12) => { - let (off12, alu_op) = if off12 > 0 { - (off12, ALUOp::Add) - } else { - (-off12, ALUOp::Sub) - }; - let imm12 = UImm12::maybe_from_i64(i64::from(off12)).unwrap(); - Inst::AluRRImm12 { - alu_op, - rd, - rn: pc_reg(), - imm12, - } - } - _ => unreachable!(), - }; - inst.emit(sink, emit_info, state); - } - &Inst::Extend { - rd, - rm, - from_bits, - signed, - } if from_bits >= 8 => { - let rd = rd.to_reg(); - if machreg_is_lo(rd) && machreg_is_lo(rm) { - let bits_15_9 = match (from_bits, signed) { - (16, true) => 0b1011001000, - (16, false) => 0b1011001010, - (8, true) => 0b1011001001, - (8, false) => 0b1011001011, - _ => panic!("Unsupported Extend case: {:?}", self), - }; - sink.put2(enc_16_rr(bits_15_9, rd, rm)); - } else { - let bits_22_20 = match (from_bits, signed) { - (16, true) => 0b000, - (16, false) => 0b001, - (8, true) => 0b100, - (8, false) => 0b101, - _ => panic!("Unsupported Extend case: {:?}", self), - }; - let inst = 0b111110100_000_11111111_0000_1000_0000 | (bits_22_20 << 20); - let inst = enc_32_regs(inst, Some(rm), Some(rd), None, None); - emit_32(inst, sink); - } - } - &Inst::Extend { - rd, - rm, - from_bits, - signed, - } if from_bits == 1 => { - let inst = Inst::AluRRImm8 { - alu_op: ALUOp::And, - rd, - rn: rm, - imm8: UImm8::maybe_from_i64(1).unwrap(), - }; - inst.emit(sink, emit_info, state); - - if signed { - let inst = Inst::AluRRImm8 { - alu_op: ALUOp::Rsb, - rd, - rn: rd.to_reg(), - imm8: UImm8::maybe_from_i64(1).unwrap(), - }; - inst.emit(sink, emit_info, state); - } - } - &Inst::Extend { .. } => { - panic!("Unsupported extend variant"); - } - &Inst::It { cond, ref insts } => { - assert!(1 <= insts.len() && insts.len() <= 4); - assert!(insts[0].then); - - sink.put2(enc_16_it(cond, insts)); - for inst in insts.iter() { - inst.inst.emit(sink, emit_info, state); - } - } - &Inst::Push { ref reg_list } => match reg_list.len() { - 0 => panic!("Unsupported Push case: {:?}", self), - 1 => { - let reg = u32::from(machreg_to_gpr(reg_list[0])); - let inst: u32 = 0b1111100001001101_0000_110100000100 | (reg << 12); - emit_32(inst, sink); - } - _ => { - let mut inst: u32 = 0b1110100100101101 << 16; - for reg in reg_list { - inst |= 1 << machreg_to_gpr(*reg); - } - if inst & ((1 << 13) | (1 << 15)) != 0 { - panic!("Unsupported Push case: {:?}", self); - } - emit_32(inst, sink); - } - }, - &Inst::Pop { ref reg_list } => match reg_list.len() { - 0 => panic!("Unsupported Pop case: {:?}", self), - 1 => { - let reg = u32::from(machreg_to_gpr(reg_list[0].to_reg())); - let inst: u32 = 0b1111100001011101_0000_101100000100 | (reg << 12); - emit_32(inst, sink); - } - _ => { - let mut inst: u32 = 0b1110100010111101 << 16; - for reg in reg_list { - inst |= 1 << machreg_to_gpr(reg.to_reg()); - } - if (inst & (1 << 14) != 0) && (inst & (1 << 15) != 0) { - panic!("Unsupported Pop case: {:?}", self); - } - emit_32(inst, sink); - } - }, - &Inst::Call { ref info } => { - let srcloc = state.cur_srcloc(); - sink.add_reloc(srcloc, Reloc::Arm32Call, &info.dest, 0); - emit_32(0b11110_0_0000000000_11_0_1_0_00000000000, sink); - if info.opcode.is_call() { - sink.add_call_site(srcloc, info.opcode); - } - } - &Inst::CallInd { ref info } => { - let srcloc = state.cur_srcloc(); - sink.put2(0b01000111_1_0000_000 | (machreg_to_gpr(info.rm) << 3)); - if info.opcode.is_call() { - sink.add_call_site(srcloc, info.opcode); - } - } - &Inst::LoadExtName { - rt, - ref name, - offset, - } => { - // maybe nop2 (0|2) bytes (pc is now 4-aligned) - // ldr rt, [pc, #4] 4 bytes - // b continue 4 bytes - // addr 4 bytes - // continue: - // - if start_off & 0x3 != 0 { - Inst::Nop2.emit(sink, emit_info, state); - } - assert_eq!(sink.cur_offset() & 0x3, 0); - - let mem = AMode::PCRel(4); - let inst = Inst::Load { - rt, - mem, - bits: 32, - sign_extend: false, - }; - inst.emit(sink, emit_info, state); - - let inst = Inst::Jump { - dest: BranchTarget::ResolvedOffset(4), - }; - inst.emit(sink, emit_info, state); - - let srcloc = state.cur_srcloc(); - sink.add_reloc(srcloc, Reloc::Abs4, name, offset.into()); - sink.put4(0); - } - &Inst::Ret => { - sink.put2(0b010001110_1110_000); // bx lr - } - &Inst::Jump { dest } => { - let off = sink.cur_offset(); - // Indicate that the jump uses a label, if so, so that a fixup can occur later. - if let Some(l) = dest.as_label() { - sink.use_label_at_offset(off, l, LabelUse::Branch24); - sink.add_uncond_branch(off, off + 4, l); - } - emit_32(enc_32_jump(dest), sink); - } - &Inst::CondBr { - taken, - not_taken, - cond, - } => { - // Conditional part first. - let cond_off = sink.cur_offset(); - if let Some(l) = taken.as_label() { - let label_use = LabelUse::Branch20; - sink.use_label_at_offset(cond_off, l, label_use); - let inverted = enc_32_cond_branch(cond.invert(), taken); - let inverted = u32_swap_halfwords(inverted).to_le_bytes(); - sink.add_cond_branch(cond_off, cond_off + 4, l, &inverted[..]); - } - emit_32(enc_32_cond_branch(cond, taken), sink); - - // Unconditional part. - let uncond_off = sink.cur_offset(); - if let Some(l) = not_taken.as_label() { - sink.use_label_at_offset(uncond_off, l, LabelUse::Branch24); - sink.add_uncond_branch(uncond_off, uncond_off + 4, l); - } - emit_32(enc_32_jump(not_taken), sink); - } - &Inst::IndirectBr { rm, .. } => { - let inst = 0b010001110_0000_000 | (machreg_to_gpr(rm) << 3); - sink.put2(inst); - } - &Inst::Udf { trap_info } => { - let srcloc = state.cur_srcloc(); - let code = trap_info; - sink.add_trap(srcloc, code); - sink.put2(0b11011110_00000000); - } - &Inst::Bkpt => { - sink.put2(0b10111110_00000000); - } - &Inst::TrapIf { cond, trap_info } => { - let cond = cond.invert(); - let dest = BranchTarget::ResolvedOffset(2); - emit_32(enc_32_cond_branch(cond, dest), sink); - - let trap = Inst::Udf { trap_info }; - trap.emit(sink, emit_info, state); - } - &Inst::VirtualSPOffsetAdj { offset } => { - log::trace!( - "virtual sp offset adjusted by {} -> {}", - offset, - state.virtual_sp_offset + offset, - ); - state.virtual_sp_offset += offset; - } - } - - let end_off = sink.cur_offset(); - debug_assert!((end_off - start_off) <= Inst::worst_case_size()); - } - - fn pretty_print(&self, mb_rru: Option<&RealRegUniverse>, state: &mut EmitState) -> String { - self.print_with_state(mb_rru, state) - } -} diff --git a/cranelift/codegen/src/isa/arm32/inst/emit_tests.rs b/cranelift/codegen/src/isa/arm32/inst/emit_tests.rs deleted file mode 100644 index 421cc2e54898..000000000000 --- a/cranelift/codegen/src/isa/arm32/inst/emit_tests.rs +++ /dev/null @@ -1,1956 +0,0 @@ -use crate::isa::arm32::inst::*; -use crate::settings; - -use alloc::vec::Vec; - -#[test] -fn test_arm32_emit() { - let flags = settings::Flags::new(settings::builder()); - let mut insns = Vec::<(Inst, &str, &str)>::new(); - - // litle endian order - insns.push((Inst::Nop0, "", "nop-zero-len")); - insns.push((Inst::Nop2, "00BF", "nop")); - insns.push(( - Inst::AluRRR { - alu_op: ALUOp::Lsl, - rd: writable_rreg(0), - rn: rreg(1), - rm: rreg(2), - }, - "01FA02F0", - "lsl r0, r1, r2", - )); - insns.push(( - Inst::AluRRR { - alu_op: ALUOp::Lsl, - rd: writable_rreg(8), - rn: rreg(9), - rm: rreg(10), - }, - "09FA0AF8", - "lsl r8, r9, r10", - )); - insns.push(( - Inst::AluRRR { - alu_op: ALUOp::Lsr, - rd: writable_rreg(0), - rn: rreg(1), - rm: rreg(2), - }, - "21FA02F0", - "lsr r0, r1, r2", - )); - insns.push(( - Inst::AluRRR { - alu_op: ALUOp::Lsr, - rd: writable_rreg(8), - rn: rreg(9), - rm: rreg(10), - }, - "29FA0AF8", - "lsr r8, r9, r10", - )); - insns.push(( - Inst::AluRRR { - alu_op: ALUOp::Asr, - rd: writable_rreg(0), - rn: rreg(1), - rm: rreg(2), - }, - "41FA02F0", - "asr r0, r1, r2", - )); - insns.push(( - Inst::AluRRR { - alu_op: ALUOp::Asr, - rd: writable_rreg(8), - rn: rreg(9), - rm: rreg(10), - }, - "49FA0AF8", - "asr r8, r9, r10", - )); - insns.push(( - Inst::AluRRR { - alu_op: ALUOp::Ror, - rd: writable_rreg(0), - rn: rreg(1), - rm: rreg(2), - }, - "61FA02F0", - "ror r0, r1, r2", - )); - insns.push(( - Inst::AluRRR { - alu_op: ALUOp::Ror, - rd: writable_rreg(8), - rn: rreg(9), - rm: rreg(10), - }, - "69FA0AF8", - "ror r8, r9, r10", - )); - insns.push(( - Inst::AluRRR { - alu_op: ALUOp::Qadd, - rd: writable_rreg(0), - rn: rreg(1), - rm: rreg(2), - }, - "81FA82F0", - "qadd r0, r1, r2", - )); - insns.push(( - Inst::AluRRR { - alu_op: ALUOp::Qadd, - rd: writable_rreg(8), - rn: rreg(9), - rm: rreg(10), - }, - "89FA8AF8", - "qadd r8, r9, r10", - )); - insns.push(( - Inst::AluRRR { - alu_op: ALUOp::Qsub, - rd: writable_rreg(0), - rn: rreg(1), - rm: rreg(2), - }, - "81FAA2F0", - "qsub r0, r1, r2", - )); - insns.push(( - Inst::AluRRR { - alu_op: ALUOp::Qsub, - rd: writable_rreg(8), - rn: rreg(9), - rm: rreg(10), - }, - "89FAAAF8", - "qsub r8, r9, r10", - )); - insns.push(( - Inst::AluRRR { - alu_op: ALUOp::Mul, - rd: writable_rreg(0), - rn: rreg(1), - rm: rreg(2), - }, - "01FB02F0", - "mul r0, r1, r2", - )); - insns.push(( - Inst::AluRRR { - alu_op: ALUOp::Mul, - rd: writable_rreg(8), - rn: rreg(9), - rm: rreg(10), - }, - "09FB0AF8", - "mul r8, r9, r10", - )); - insns.push(( - Inst::AluRRR { - alu_op: ALUOp::Udiv, - rd: writable_rreg(0), - rn: rreg(1), - rm: rreg(2), - }, - "B1FBF2F0", - "udiv r0, r1, r2", - )); - insns.push(( - Inst::AluRRR { - alu_op: ALUOp::Udiv, - rd: writable_rreg(8), - rn: rreg(9), - rm: rreg(10), - }, - "B9FBFAF8", - "udiv r8, r9, r10", - )); - insns.push(( - Inst::AluRRR { - alu_op: ALUOp::Sdiv, - rd: writable_rreg(0), - rn: rreg(1), - rm: rreg(2), - }, - "91FBF2F0", - "sdiv r0, r1, r2", - )); - insns.push(( - Inst::AluRRR { - alu_op: ALUOp::Sdiv, - rd: writable_rreg(8), - rn: rreg(9), - rm: rreg(10), - }, - "99FBFAF8", - "sdiv r8, r9, r10", - )); - insns.push(( - Inst::AluRRRShift { - alu_op: ALUOp::And, - rd: writable_rreg(0), - rn: rreg(1), - rm: rreg(2), - shift: Some(ShiftOpAndAmt::new( - ShiftOp::LSL, - ShiftOpShiftImm::maybe_from_shift(23).unwrap(), - )), - }, - "01EAC250", - "and r0, r1, r2, lsl #23", - )); - insns.push(( - Inst::AluRRRShift { - alu_op: ALUOp::And, - rd: writable_rreg(8), - rn: rreg(9), - rm: rreg(10), - shift: None, - }, - "09EA0A08", - "and r8, r9, r10", - )); - insns.push(( - Inst::AluRRRShift { - alu_op: ALUOp::Bic, - rd: writable_rreg(0), - rn: rreg(1), - rm: rreg(2), - shift: Some(ShiftOpAndAmt::new( - ShiftOp::LSL, - ShiftOpShiftImm::maybe_from_shift(23).unwrap(), - )), - }, - "21EAC250", - "bic r0, r1, r2, lsl #23", - )); - insns.push(( - Inst::AluRRRShift { - alu_op: ALUOp::Bic, - rd: writable_rreg(8), - rn: rreg(9), - rm: rreg(10), - shift: None, - }, - "29EA0A08", - "bic r8, r9, r10", - )); - insns.push(( - Inst::AluRRRShift { - alu_op: ALUOp::Orr, - rd: writable_rreg(0), - rn: rreg(1), - rm: rreg(2), - shift: Some(ShiftOpAndAmt::new( - ShiftOp::LSL, - ShiftOpShiftImm::maybe_from_shift(23).unwrap(), - )), - }, - "41EAC250", - "orr r0, r1, r2, lsl #23", - )); - insns.push(( - Inst::AluRRRShift { - alu_op: ALUOp::Orr, - rd: writable_rreg(8), - rn: rreg(9), - rm: rreg(10), - shift: None, - }, - "49EA0A08", - "orr r8, r9, r10", - )); - insns.push(( - Inst::AluRRRShift { - alu_op: ALUOp::Orn, - rd: writable_rreg(0), - rn: rreg(1), - rm: rreg(2), - shift: Some(ShiftOpAndAmt::new( - ShiftOp::LSL, - ShiftOpShiftImm::maybe_from_shift(23).unwrap(), - )), - }, - "61EAC250", - "orn r0, r1, r2, lsl #23", - )); - insns.push(( - Inst::AluRRRShift { - alu_op: ALUOp::Orn, - rd: writable_rreg(8), - rn: rreg(9), - rm: rreg(10), - shift: None, - }, - "69EA0A08", - "orn r8, r9, r10", - )); - insns.push(( - Inst::AluRRRShift { - alu_op: ALUOp::Eor, - rd: writable_rreg(0), - rn: rreg(1), - rm: rreg(2), - shift: Some(ShiftOpAndAmt::new( - ShiftOp::LSL, - ShiftOpShiftImm::maybe_from_shift(23).unwrap(), - )), - }, - "81EAC250", - "eor r0, r1, r2, lsl #23", - )); - insns.push(( - Inst::AluRRRShift { - alu_op: ALUOp::Eor, - rd: writable_rreg(8), - rn: rreg(9), - rm: rreg(10), - shift: None, - }, - "89EA0A08", - "eor r8, r9, r10", - )); - insns.push(( - Inst::AluRRRShift { - alu_op: ALUOp::Add, - rd: writable_rreg(0), - rn: rreg(1), - rm: rreg(2), - shift: Some(ShiftOpAndAmt::new( - ShiftOp::LSL, - ShiftOpShiftImm::maybe_from_shift(23).unwrap(), - )), - }, - "01EBC250", - "add r0, r1, r2, lsl #23", - )); - insns.push(( - Inst::AluRRRShift { - alu_op: ALUOp::Add, - rd: writable_rreg(8), - rn: rreg(9), - rm: rreg(10), - shift: None, - }, - "09EB0A08", - "add r8, r9, r10", - )); - insns.push(( - Inst::AluRRRShift { - alu_op: ALUOp::Adds, - rd: writable_rreg(0), - rn: rreg(1), - rm: rreg(2), - shift: Some(ShiftOpAndAmt::new( - ShiftOp::LSL, - ShiftOpShiftImm::maybe_from_shift(23).unwrap(), - )), - }, - "11EBC250", - "adds r0, r1, r2, lsl #23", - )); - insns.push(( - Inst::AluRRRShift { - alu_op: ALUOp::Adds, - rd: writable_rreg(8), - rn: rreg(9), - rm: rreg(10), - shift: None, - }, - "19EB0A08", - "adds r8, r9, r10", - )); - insns.push(( - Inst::AluRRRShift { - alu_op: ALUOp::Adc, - rd: writable_rreg(0), - rn: rreg(1), - rm: rreg(2), - shift: Some(ShiftOpAndAmt::new( - ShiftOp::LSL, - ShiftOpShiftImm::maybe_from_shift(23).unwrap(), - )), - }, - "41EBC250", - "adc r0, r1, r2, lsl #23", - )); - insns.push(( - Inst::AluRRRShift { - alu_op: ALUOp::Adc, - rd: writable_rreg(8), - rn: rreg(9), - rm: rreg(10), - shift: None, - }, - "49EB0A08", - "adc r8, r9, r10", - )); - insns.push(( - Inst::AluRRRShift { - alu_op: ALUOp::Adcs, - rd: writable_rreg(0), - rn: rreg(1), - rm: rreg(2), - shift: Some(ShiftOpAndAmt::new( - ShiftOp::LSL, - ShiftOpShiftImm::maybe_from_shift(23).unwrap(), - )), - }, - "51EBC250", - "adcs r0, r1, r2, lsl #23", - )); - insns.push(( - Inst::AluRRRShift { - alu_op: ALUOp::Adcs, - rd: writable_rreg(8), - rn: rreg(9), - rm: rreg(10), - shift: None, - }, - "59EB0A08", - "adcs r8, r9, r10", - )); - insns.push(( - Inst::AluRRRShift { - alu_op: ALUOp::Sbc, - rd: writable_rreg(0), - rn: rreg(1), - rm: rreg(2), - shift: Some(ShiftOpAndAmt::new( - ShiftOp::LSL, - ShiftOpShiftImm::maybe_from_shift(23).unwrap(), - )), - }, - "61EBC250", - "sbc r0, r1, r2, lsl #23", - )); - insns.push(( - Inst::AluRRRShift { - alu_op: ALUOp::Sbc, - rd: writable_rreg(8), - rn: rreg(9), - rm: rreg(10), - shift: None, - }, - "69EB0A08", - "sbc r8, r9, r10", - )); - insns.push(( - Inst::AluRRRShift { - alu_op: ALUOp::Sbcs, - rd: writable_rreg(0), - rn: rreg(1), - rm: rreg(2), - shift: Some(ShiftOpAndAmt::new( - ShiftOp::LSL, - ShiftOpShiftImm::maybe_from_shift(23).unwrap(), - )), - }, - "71EBC250", - "sbcs r0, r1, r2, lsl #23", - )); - insns.push(( - Inst::AluRRRShift { - alu_op: ALUOp::Sbcs, - rd: writable_rreg(8), - rn: rreg(9), - rm: rreg(10), - shift: None, - }, - "79EB0A08", - "sbcs r8, r9, r10", - )); - insns.push(( - Inst::AluRRRShift { - alu_op: ALUOp::Sub, - rd: writable_rreg(0), - rn: rreg(1), - rm: rreg(2), - shift: Some(ShiftOpAndAmt::new( - ShiftOp::LSL, - ShiftOpShiftImm::maybe_from_shift(23).unwrap(), - )), - }, - "A1EBC250", - "sub r0, r1, r2, lsl #23", - )); - insns.push(( - Inst::AluRRRShift { - alu_op: ALUOp::Sub, - rd: writable_rreg(8), - rn: rreg(9), - rm: rreg(10), - shift: None, - }, - "A9EB0A08", - "sub r8, r9, r10", - )); - insns.push(( - Inst::AluRRRShift { - alu_op: ALUOp::Subs, - rd: writable_rreg(0), - rn: rreg(1), - rm: rreg(2), - shift: Some(ShiftOpAndAmt::new( - ShiftOp::LSL, - ShiftOpShiftImm::maybe_from_shift(23).unwrap(), - )), - }, - "B1EBC250", - "subs r0, r1, r2, lsl #23", - )); - insns.push(( - Inst::AluRRRShift { - alu_op: ALUOp::Subs, - rd: writable_rreg(8), - rn: rreg(9), - rm: rreg(10), - shift: None, - }, - "B9EB0A08", - "subs r8, r9, r10", - )); - insns.push(( - Inst::AluRRRShift { - alu_op: ALUOp::Rsb, - rd: writable_rreg(0), - rn: rreg(1), - rm: rreg(2), - shift: Some(ShiftOpAndAmt::new( - ShiftOp::LSL, - ShiftOpShiftImm::maybe_from_shift(23).unwrap(), - )), - }, - "C1EBC250", - "rsb r0, r1, r2, lsl #23", - )); - insns.push(( - Inst::AluRRRShift { - alu_op: ALUOp::Rsb, - rd: writable_rreg(8), - rn: rreg(9), - rm: rreg(10), - shift: None, - }, - "C9EB0A08", - "rsb r8, r9, r10", - )); - insns.push(( - Inst::AluRRShift { - alu_op: ALUOp1::Mvn, - rd: writable_rreg(0), - rm: rreg(1), - shift: Some(ShiftOpAndAmt::new( - ShiftOp::LSL, - ShiftOpShiftImm::maybe_from_shift(11).unwrap(), - )), - }, - "6FEAC120", - "mvn r0, r1, lsl #11", - )); - insns.push(( - Inst::AluRRShift { - alu_op: ALUOp1::Mvn, - rd: writable_rreg(8), - rm: rreg(9), - shift: None, - }, - "6FEA0908", - "mvn r8, r9", - )); - insns.push(( - Inst::AluRRShift { - alu_op: ALUOp1::Mov, - rd: writable_rreg(0), - rm: rreg(1), - shift: Some(ShiftOpAndAmt::new( - ShiftOp::LSL, - ShiftOpShiftImm::maybe_from_shift(11).unwrap(), - )), - }, - "4FEAC120", - "mov r0, r1, lsl #11", - )); - insns.push(( - Inst::AluRRShift { - alu_op: ALUOp1::Mov, - rd: writable_rreg(2), - rm: rreg(8), - shift: Some(ShiftOpAndAmt::new( - ShiftOp::LSR, - ShiftOpShiftImm::maybe_from_shift(27).unwrap(), - )), - }, - "4FEAD862", - "mov r2, r8, lsr #27", - )); - insns.push(( - Inst::AluRRShift { - alu_op: ALUOp1::Mov, - rd: writable_rreg(9), - rm: rreg(3), - shift: Some(ShiftOpAndAmt::new( - ShiftOp::ASR, - ShiftOpShiftImm::maybe_from_shift(3).unwrap(), - )), - }, - "4FEAE309", - "mov r9, r3, asr #3", - )); - insns.push(( - Inst::AluRRShift { - alu_op: ALUOp1::Mov, - rd: writable_rreg(10), - rm: rreg(11), - shift: Some(ShiftOpAndAmt::new( - ShiftOp::ROR, - ShiftOpShiftImm::maybe_from_shift(7).unwrap(), - )), - }, - "4FEAFB1A", - "mov r10, fp, ror #7", - )); - insns.push(( - Inst::AluRRRR { - alu_op: ALUOp::Smull, - rd_lo: writable_rreg(0), - rd_hi: writable_rreg(1), - rn: rreg(2), - rm: rreg(3), - }, - "82FB0301", - "smull r0, r1, r2, r3", - )); - insns.push(( - Inst::AluRRRR { - alu_op: ALUOp::Smull, - rd_lo: writable_rreg(8), - rd_hi: writable_rreg(9), - rn: rreg(10), - rm: rreg(11), - }, - "8AFB0B89", - "smull r8, r9, r10, fp", - )); - insns.push(( - Inst::AluRRRR { - alu_op: ALUOp::Umull, - rd_lo: writable_rreg(0), - rd_hi: writable_rreg(1), - rn: rreg(2), - rm: rreg(3), - }, - "A2FB0301", - "umull r0, r1, r2, r3", - )); - insns.push(( - Inst::AluRRRR { - alu_op: ALUOp::Umull, - rd_lo: writable_rreg(8), - rd_hi: writable_rreg(9), - rn: rreg(10), - rm: rreg(11), - }, - "AAFB0B89", - "umull r8, r9, r10, fp", - )); - insns.push(( - Inst::AluRRImm12 { - alu_op: ALUOp::Add, - rd: writable_rreg(0), - rn: rreg(1), - imm12: UImm12::maybe_from_i64(4095).unwrap(), - }, - "01F6FF70", - "add r0, r1, #4095", - )); - insns.push(( - Inst::AluRRImm12 { - alu_op: ALUOp::Add, - rd: writable_rreg(8), - rn: rreg(9), - imm12: UImm12::maybe_from_i64(0).unwrap(), - }, - "09F20008", - "add r8, r9, #0", - )); - insns.push(( - Inst::AluRRImm12 { - alu_op: ALUOp::Sub, - rd: writable_rreg(0), - rn: rreg(1), - imm12: UImm12::maybe_from_i64(1999).unwrap(), - }, - "A1F2CF70", - "sub r0, r1, #1999", - )); - insns.push(( - Inst::AluRRImm12 { - alu_op: ALUOp::Sub, - rd: writable_rreg(8), - rn: rreg(9), - imm12: UImm12::maybe_from_i64(101).unwrap(), - }, - "A9F26508", - "sub r8, r9, #101", - )); - insns.push(( - Inst::AluRRImm8 { - alu_op: ALUOp::And, - rd: writable_rreg(0), - rn: rreg(1), - imm8: UImm8::maybe_from_i64(255).unwrap(), - }, - "01F0FF00", - "and r0, r1, #255", - )); - insns.push(( - Inst::AluRRImm8 { - alu_op: ALUOp::And, - rd: writable_rreg(8), - rn: rreg(9), - imm8: UImm8::maybe_from_i64(1).unwrap(), - }, - "09F00108", - "and r8, r9, #1", - )); - insns.push(( - Inst::AluRRImm8 { - alu_op: ALUOp::Bic, - rd: writable_rreg(0), - rn: rreg(1), - imm8: UImm8::maybe_from_i64(255).unwrap(), - }, - "21F0FF00", - "bic r0, r1, #255", - )); - insns.push(( - Inst::AluRRImm8 { - alu_op: ALUOp::Bic, - rd: writable_rreg(8), - rn: rreg(9), - imm8: UImm8::maybe_from_i64(1).unwrap(), - }, - "29F00108", - "bic r8, r9, #1", - )); - insns.push(( - Inst::AluRRImm8 { - alu_op: ALUOp::Orr, - rd: writable_rreg(0), - rn: rreg(1), - imm8: UImm8::maybe_from_i64(255).unwrap(), - }, - "41F0FF00", - "orr r0, r1, #255", - )); - insns.push(( - Inst::AluRRImm8 { - alu_op: ALUOp::Orr, - rd: writable_rreg(8), - rn: rreg(9), - imm8: UImm8::maybe_from_i64(1).unwrap(), - }, - "49F00108", - "orr r8, r9, #1", - )); - insns.push(( - Inst::AluRRImm8 { - alu_op: ALUOp::Orn, - rd: writable_rreg(0), - rn: rreg(1), - imm8: UImm8::maybe_from_i64(255).unwrap(), - }, - "61F0FF00", - "orn r0, r1, #255", - )); - insns.push(( - Inst::AluRRImm8 { - alu_op: ALUOp::Orn, - rd: writable_rreg(8), - rn: rreg(9), - imm8: UImm8::maybe_from_i64(1).unwrap(), - }, - "69F00108", - "orn r8, r9, #1", - )); - insns.push(( - Inst::AluRRImm8 { - alu_op: ALUOp::Eor, - rd: writable_rreg(0), - rn: rreg(1), - imm8: UImm8::maybe_from_i64(255).unwrap(), - }, - "81F0FF00", - "eor r0, r1, #255", - )); - insns.push(( - Inst::AluRRImm8 { - alu_op: ALUOp::Eor, - rd: writable_rreg(8), - rn: rreg(9), - imm8: UImm8::maybe_from_i64(1).unwrap(), - }, - "89F00108", - "eor r8, r9, #1", - )); - insns.push(( - Inst::AluRRImm8 { - alu_op: ALUOp::Add, - rd: writable_rreg(0), - rn: rreg(1), - imm8: UImm8::maybe_from_i64(255).unwrap(), - }, - "01F1FF00", - "add r0, r1, #255", - )); - insns.push(( - Inst::AluRRImm8 { - alu_op: ALUOp::Add, - rd: writable_rreg(8), - rn: rreg(9), - imm8: UImm8::maybe_from_i64(1).unwrap(), - }, - "09F10108", - "add r8, r9, #1", - )); - insns.push(( - Inst::AluRRImm8 { - alu_op: ALUOp::Adds, - rd: writable_rreg(0), - rn: rreg(1), - imm8: UImm8::maybe_from_i64(255).unwrap(), - }, - "11F1FF00", - "adds r0, r1, #255", - )); - insns.push(( - Inst::AluRRImm8 { - alu_op: ALUOp::Adds, - rd: writable_rreg(8), - rn: rreg(9), - imm8: UImm8::maybe_from_i64(1).unwrap(), - }, - "19F10108", - "adds r8, r9, #1", - )); - insns.push(( - Inst::AluRRImm8 { - alu_op: ALUOp::Adc, - rd: writable_rreg(0), - rn: rreg(1), - imm8: UImm8::maybe_from_i64(255).unwrap(), - }, - "41F1FF00", - "adc r0, r1, #255", - )); - insns.push(( - Inst::AluRRImm8 { - alu_op: ALUOp::Adc, - rd: writable_rreg(8), - rn: rreg(9), - imm8: UImm8::maybe_from_i64(1).unwrap(), - }, - "49F10108", - "adc r8, r9, #1", - )); - insns.push(( - Inst::AluRRImm8 { - alu_op: ALUOp::Adcs, - rd: writable_rreg(0), - rn: rreg(1), - imm8: UImm8::maybe_from_i64(255).unwrap(), - }, - "51F1FF00", - "adcs r0, r1, #255", - )); - insns.push(( - Inst::AluRRImm8 { - alu_op: ALUOp::Adcs, - rd: writable_rreg(8), - rn: rreg(9), - imm8: UImm8::maybe_from_i64(1).unwrap(), - }, - "59F10108", - "adcs r8, r9, #1", - )); - insns.push(( - Inst::AluRRImm8 { - alu_op: ALUOp::Sbc, - rd: writable_rreg(0), - rn: rreg(1), - imm8: UImm8::maybe_from_i64(255).unwrap(), - }, - "61F1FF00", - "sbc r0, r1, #255", - )); - insns.push(( - Inst::AluRRImm8 { - alu_op: ALUOp::Sbc, - rd: writable_rreg(8), - rn: rreg(9), - imm8: UImm8::maybe_from_i64(1).unwrap(), - }, - "69F10108", - "sbc r8, r9, #1", - )); - insns.push(( - Inst::AluRRImm8 { - alu_op: ALUOp::Sbcs, - rd: writable_rreg(0), - rn: rreg(1), - imm8: UImm8::maybe_from_i64(255).unwrap(), - }, - "71F1FF00", - "sbcs r0, r1, #255", - )); - insns.push(( - Inst::AluRRImm8 { - alu_op: ALUOp::Sbcs, - rd: writable_rreg(8), - rn: rreg(9), - imm8: UImm8::maybe_from_i64(1).unwrap(), - }, - "79F10108", - "sbcs r8, r9, #1", - )); - insns.push(( - Inst::AluRRImm8 { - alu_op: ALUOp::Sub, - rd: writable_rreg(0), - rn: rreg(1), - imm8: UImm8::maybe_from_i64(255).unwrap(), - }, - "A1F1FF00", - "sub r0, r1, #255", - )); - insns.push(( - Inst::AluRRImm8 { - alu_op: ALUOp::Sub, - rd: writable_rreg(8), - rn: rreg(9), - imm8: UImm8::maybe_from_i64(1).unwrap(), - }, - "A9F10108", - "sub r8, r9, #1", - )); - insns.push(( - Inst::AluRRImm8 { - alu_op: ALUOp::Subs, - rd: writable_rreg(0), - rn: rreg(1), - imm8: UImm8::maybe_from_i64(255).unwrap(), - }, - "B1F1FF00", - "subs r0, r1, #255", - )); - insns.push(( - Inst::AluRRImm8 { - alu_op: ALUOp::Subs, - rd: writable_rreg(8), - rn: rreg(9), - imm8: UImm8::maybe_from_i64(1).unwrap(), - }, - "B9F10108", - "subs r8, r9, #1", - )); - insns.push(( - Inst::AluRRImm8 { - alu_op: ALUOp::Rsb, - rd: writable_rreg(0), - rn: rreg(1), - imm8: UImm8::maybe_from_i64(255).unwrap(), - }, - "C1F1FF00", - "rsb r0, r1, #255", - )); - insns.push(( - Inst::AluRRImm8 { - alu_op: ALUOp::Rsb, - rd: writable_rreg(8), - rn: rreg(9), - imm8: UImm8::maybe_from_i64(1).unwrap(), - }, - "C9F10108", - "rsb r8, r9, #1", - )); - insns.push(( - Inst::AluRImm8 { - alu_op: ALUOp1::Mvn, - rd: writable_rreg(0), - imm8: UImm8::maybe_from_i64(255).unwrap(), - }, - "6FF0FF00", - "mvn r0, #255", - )); - insns.push(( - Inst::AluRImm8 { - alu_op: ALUOp1::Mvn, - rd: writable_rreg(8), - imm8: UImm8::maybe_from_i64(1).unwrap(), - }, - "6FF00108", - "mvn r8, #1", - )); - insns.push(( - Inst::AluRImm8 { - alu_op: ALUOp1::Mov, - rd: writable_rreg(0), - imm8: UImm8::maybe_from_i64(0).unwrap(), - }, - "4FF00000", - "mov r0, #0", - )); - insns.push(( - Inst::AluRImm8 { - alu_op: ALUOp1::Mov, - rd: writable_rreg(8), - imm8: UImm8::maybe_from_i64(176).unwrap(), - }, - "4FF0B008", - "mov r8, #176", - )); - insns.push(( - Inst::BitOpRR { - bit_op: BitOp::Rbit, - rd: writable_rreg(0), - rm: rreg(1), - }, - "91FAA1F0", - "rbit r0, r1", - )); - insns.push(( - Inst::BitOpRR { - bit_op: BitOp::Rbit, - rd: writable_rreg(8), - rm: rreg(9), - }, - "99FAA9F8", - "rbit r8, r9", - )); - insns.push(( - Inst::BitOpRR { - bit_op: BitOp::Rev, - rd: writable_rreg(0), - rm: rreg(1), - }, - "91FA81F0", - "rev r0, r1", - )); - insns.push(( - Inst::BitOpRR { - bit_op: BitOp::Rev, - rd: writable_rreg(8), - rm: rreg(9), - }, - "99FA89F8", - "rev r8, r9", - )); - insns.push(( - Inst::BitOpRR { - bit_op: BitOp::Clz, - rd: writable_rreg(0), - rm: rreg(1), - }, - "B1FA81F0", - "clz r0, r1", - )); - insns.push(( - Inst::BitOpRR { - bit_op: BitOp::Clz, - rd: writable_rreg(8), - rm: rreg(9), - }, - "B9FA89F8", - "clz r8, r9", - )); - insns.push(( - Inst::Mov { - rd: writable_rreg(0), - rm: rreg(1), - }, - "0846", - "mov r0, r1", - )); - insns.push(( - Inst::Mov { - rd: writable_rreg(2), - rm: rreg(8), - }, - "4246", - "mov r2, r8", - )); - insns.push(( - Inst::Mov { - rd: writable_rreg(9), - rm: rreg(3), - }, - "9946", - "mov r9, r3", - )); - insns.push(( - Inst::Mov { - rd: writable_rreg(10), - rm: rreg(11), - }, - "DA46", - "mov r10, fp", - )); - insns.push(( - Inst::MovImm16 { - rd: writable_rreg(0), - imm16: 0, - }, - "40F20000", - "mov r0, #0", - )); - insns.push(( - Inst::MovImm16 { - rd: writable_rreg(1), - imm16: 15, - }, - "40F20F01", - "mov r1, #15", - )); - insns.push(( - Inst::MovImm16 { - rd: writable_rreg(2), - imm16: 255, - }, - "40F2FF02", - "mov r2, #255", - )); - insns.push(( - Inst::MovImm16 { - rd: writable_rreg(8), - imm16: 4095, - }, - "40F6FF78", - "mov r8, #4095", - )); - insns.push(( - Inst::MovImm16 { - rd: writable_rreg(9), - imm16: 65535, - }, - "4FF6FF79", - "mov r9, #65535", - )); - insns.push(( - Inst::Movt { - rd: writable_rreg(0), - imm16: 0, - }, - "C0F20000", - "movt r0, #0", - )); - insns.push(( - Inst::Movt { - rd: writable_rreg(1), - imm16: 15, - }, - "C0F20F01", - "movt r1, #15", - )); - insns.push(( - Inst::Movt { - rd: writable_rreg(2), - imm16: 255, - }, - "C0F2FF02", - "movt r2, #255", - )); - insns.push(( - Inst::Movt { - rd: writable_rreg(8), - imm16: 4095, - }, - "C0F6FF78", - "movt r8, #4095", - )); - insns.push(( - Inst::Movt { - rd: writable_rreg(9), - imm16: 65535, - }, - "CFF6FF79", - "movt r9, #65535", - )); - insns.push(( - Inst::Cmp { - rn: rreg(0), - rm: rreg(1), - }, - "8842", - "cmp r0, r1", - )); - insns.push(( - Inst::Cmp { - rn: rreg(2), - rm: rreg(8), - }, - "4245", - "cmp r2, r8", - )); - insns.push(( - Inst::Cmp { - rn: rreg(9), - rm: rreg(3), - }, - "9945", - "cmp r9, r3", - )); - insns.push(( - Inst::Cmp { - rn: rreg(10), - rm: rreg(11), - }, - "DA45", - "cmp r10, fp", - )); - insns.push(( - Inst::CmpImm8 { - rn: rreg(0), - imm8: 255, - }, - "B0F1FF0F", - "cmp r0, #255", - )); - insns.push(( - Inst::CmpImm8 { - rn: rreg(1), - imm8: 0, - }, - "B1F1000F", - "cmp r1, #0", - )); - insns.push(( - Inst::CmpImm8 { - rn: rreg(8), - imm8: 1, - }, - "B8F1010F", - "cmp r8, #1", - )); - - insns.push(( - Inst::Store { - rt: rreg(0), - mem: AMode::reg_plus_reg(rreg(1), rreg(2), 0), - bits: 32, - }, - "41F80200", - "str r0, [r1, r2]", - )); - insns.push(( - Inst::Store { - rt: rreg(8), - mem: AMode::reg_plus_reg(rreg(9), rreg(10), 3), - bits: 32, - }, - "49F83A80", - "str r8, [r9, r10, lsl #3]", - )); - insns.push(( - Inst::Store { - rt: rreg(0), - mem: AMode::RegOffset(rreg(1), 4095), - bits: 32, - }, - "C1F8FF0F", - "str r0, [r1, #4095]", - )); - insns.push(( - Inst::Store { - rt: rreg(8), - mem: AMode::RegOffset(rreg(9), 0), - bits: 32, - }, - "C9F80080", - "str r8, [r9, #0]", - )); - insns.push(( - Inst::Store { - rt: rreg(7), - mem: AMode::RegOffset(rreg(11), 65535), - bits: 32, - }, - "4FF6FF7C4BF80C70", - "mov ip, #65535 ; str r7, [fp, ip]", - )); - insns.push(( - Inst::Store { - rt: rreg(10), - mem: AMode::RegOffset(rreg(4), 16777215), - bits: 32, - }, - "4FF6FF7CC0F2FF0C44F80CA0", - "mov ip, #65535 ; movt ip, #255 ; str r10, [r4, ip]", - )); - insns.push(( - Inst::Store { - rt: rreg(0), - mem: AMode::reg_plus_reg(rreg(1), rreg(2), 0), - bits: 16, - }, - "21F80200", - "strh r0, [r1, r2]", - )); - insns.push(( - Inst::Store { - rt: rreg(8), - mem: AMode::reg_plus_reg(rreg(9), rreg(10), 2), - bits: 16, - }, - "29F82A80", - "strh r8, [r9, r10, lsl #2]", - )); - insns.push(( - Inst::Store { - rt: rreg(0), - mem: AMode::RegOffset(rreg(1), 3210), - bits: 16, - }, - "A1F88A0C", - "strh r0, [r1, #3210]", - )); - insns.push(( - Inst::Store { - rt: rreg(8), - mem: AMode::RegOffset(rreg(9), 1), - bits: 16, - }, - "A9F80180", - "strh r8, [r9, #1]", - )); - insns.push(( - Inst::Store { - rt: rreg(7), - mem: AMode::RegOffset(rreg(11), 65535), - bits: 16, - }, - "4FF6FF7C2BF80C70", - "mov ip, #65535 ; strh r7, [fp, ip]", - )); - insns.push(( - Inst::Store { - rt: rreg(10), - mem: AMode::RegOffset(rreg(4), 16777215), - bits: 16, - }, - "4FF6FF7CC0F2FF0C24F80CA0", - "mov ip, #65535 ; movt ip, #255 ; strh r10, [r4, ip]", - )); - insns.push(( - Inst::Store { - rt: rreg(0), - mem: AMode::reg_plus_reg(rreg(1), rreg(2), 0), - bits: 8, - }, - "01F80200", - "strb r0, [r1, r2]", - )); - insns.push(( - Inst::Store { - rt: rreg(8), - mem: AMode::reg_plus_reg(rreg(9), rreg(10), 1), - bits: 8, - }, - "09F81A80", - "strb r8, [r9, r10, lsl #1]", - )); - insns.push(( - Inst::Store { - rt: rreg(0), - mem: AMode::RegOffset(rreg(1), 4), - bits: 8, - }, - "81F80400", - "strb r0, [r1, #4]", - )); - insns.push(( - Inst::Store { - rt: rreg(8), - mem: AMode::RegOffset(rreg(9), 777), - bits: 8, - }, - "89F80983", - "strb r8, [r9, #777]", - )); - insns.push(( - Inst::Store { - rt: rreg(7), - mem: AMode::RegOffset(rreg(11), 65535), - bits: 8, - }, - "4FF6FF7C0BF80C70", - "mov ip, #65535 ; strb r7, [fp, ip]", - )); - insns.push(( - Inst::Store { - rt: rreg(10), - mem: AMode::RegOffset(rreg(4), 16777215), - bits: 8, - }, - "4FF6FF7CC0F2FF0C04F80CA0", - "mov ip, #65535 ; movt ip, #255 ; strb r10, [r4, ip]", - )); - insns.push(( - Inst::Load { - rt: writable_rreg(0), - mem: AMode::reg_plus_reg(rreg(1), rreg(2), 0), - bits: 32, - sign_extend: false, - }, - "51F80200", - "ldr r0, [r1, r2]", - )); - insns.push(( - Inst::Load { - rt: writable_rreg(8), - mem: AMode::reg_plus_reg(rreg(9), rreg(10), 1), - bits: 32, - sign_extend: false, - }, - "59F81A80", - "ldr r8, [r9, r10, lsl #1]", - )); - insns.push(( - Inst::Load { - rt: writable_rreg(0), - mem: AMode::RegOffset(rreg(1), 55), - bits: 32, - sign_extend: false, - }, - "D1F83700", - "ldr r0, [r1, #55]", - )); - insns.push(( - Inst::Load { - rt: writable_rreg(8), - mem: AMode::RegOffset(rreg(9), 1234), - bits: 32, - sign_extend: false, - }, - "D9F8D284", - "ldr r8, [r9, #1234]", - )); - insns.push(( - Inst::Load { - rt: writable_rreg(7), - mem: AMode::RegOffset(rreg(11), 9876), - bits: 32, - sign_extend: false, - }, - "42F2946C5BF80C70", - "mov ip, #9876 ; ldr r7, [fp, ip]", - )); - insns.push(( - Inst::Load { - rt: writable_rreg(10), - mem: AMode::RegOffset(rreg(4), 252645135), - bits: 32, - sign_extend: false, - }, - "40F60F7CC0F60F7C54F80CA0", - "mov ip, #3855 ; movt ip, #3855 ; ldr r10, [r4, ip]", - )); - insns.push(( - Inst::Load { - rt: writable_rreg(0), - mem: AMode::PCRel(-56), - bits: 32, - sign_extend: false, - }, - "5FF83800", - "ldr r0, [pc, #-56]", - )); - insns.push(( - Inst::Load { - rt: writable_rreg(8), - mem: AMode::PCRel(1024), - bits: 32, - sign_extend: false, - }, - "DFF80084", - "ldr r8, [pc, #1024]", - )); - insns.push(( - Inst::Load { - rt: writable_rreg(0), - mem: AMode::reg_plus_reg(rreg(1), rreg(2), 0), - bits: 16, - sign_extend: true, - }, - "31F90200", - "ldrsh r0, [r1, r2]", - )); - insns.push(( - Inst::Load { - rt: writable_rreg(8), - mem: AMode::reg_plus_reg(rreg(9), rreg(10), 2), - bits: 16, - sign_extend: false, - }, - "39F82A80", - "ldrh r8, [r9, r10, lsl #2]", - )); - insns.push(( - Inst::Load { - rt: writable_rreg(0), - mem: AMode::RegOffset(rreg(1), 55), - bits: 16, - sign_extend: false, - }, - "B1F83700", - "ldrh r0, [r1, #55]", - )); - insns.push(( - Inst::Load { - rt: writable_rreg(8), - mem: AMode::RegOffset(rreg(9), 1234), - bits: 16, - sign_extend: true, - }, - "B9F9D284", - "ldrsh r8, [r9, #1234]", - )); - insns.push(( - Inst::Load { - rt: writable_rreg(7), - mem: AMode::RegOffset(rreg(11), 9876), - bits: 16, - sign_extend: true, - }, - "42F2946C3BF90C70", - "mov ip, #9876 ; ldrsh r7, [fp, ip]", - )); - insns.push(( - Inst::Load { - rt: writable_rreg(10), - mem: AMode::RegOffset(rreg(4), 252645135), - bits: 16, - sign_extend: false, - }, - "40F60F7CC0F60F7C34F80CA0", - "mov ip, #3855 ; movt ip, #3855 ; ldrh r10, [r4, ip]", - )); - insns.push(( - Inst::Load { - rt: writable_rreg(0), - mem: AMode::PCRel(56), - bits: 16, - sign_extend: false, - }, - "BFF83800", - "ldrh r0, [pc, #56]", - )); - insns.push(( - Inst::Load { - rt: writable_rreg(8), - mem: AMode::PCRel(-1000), - bits: 16, - sign_extend: true, - }, - "3FF9E883", - "ldrsh r8, [pc, #-1000]", - )); - insns.push(( - Inst::Load { - rt: writable_rreg(0), - mem: AMode::reg_plus_reg(rreg(1), rreg(2), 0), - bits: 8, - sign_extend: true, - }, - "11F90200", - "ldrsb r0, [r1, r2]", - )); - insns.push(( - Inst::Load { - rt: writable_rreg(8), - mem: AMode::reg_plus_reg(rreg(9), rreg(10), 3), - bits: 8, - sign_extend: false, - }, - "19F83A80", - "ldrb r8, [r9, r10, lsl #3]", - )); - insns.push(( - Inst::Load { - rt: writable_rreg(0), - mem: AMode::RegOffset(rreg(1), 55), - bits: 8, - sign_extend: false, - }, - "91F83700", - "ldrb r0, [r1, #55]", - )); - insns.push(( - Inst::Load { - rt: writable_rreg(8), - mem: AMode::RegOffset(rreg(9), 1234), - bits: 8, - sign_extend: true, - }, - "99F9D284", - "ldrsb r8, [r9, #1234]", - )); - insns.push(( - Inst::Load { - rt: writable_rreg(7), - mem: AMode::RegOffset(rreg(11), 9876), - bits: 8, - sign_extend: true, - }, - "42F2946C1BF90C70", - "mov ip, #9876 ; ldrsb r7, [fp, ip]", - )); - insns.push(( - Inst::Load { - rt: writable_rreg(10), - mem: AMode::RegOffset(rreg(4), 252645135), - bits: 8, - sign_extend: false, - }, - "40F60F7CC0F60F7C14F80CA0", - "mov ip, #3855 ; movt ip, #3855 ; ldrb r10, [r4, ip]", - )); - insns.push(( - Inst::Load { - rt: writable_rreg(0), - mem: AMode::PCRel(72), - bits: 8, - sign_extend: false, - }, - "9FF84800", - "ldrb r0, [pc, #72]", - )); - insns.push(( - Inst::Load { - rt: writable_rreg(8), - mem: AMode::PCRel(-1234), - bits: 8, - sign_extend: true, - }, - "1FF9D284", - "ldrsb r8, [pc, #-1234]", - )); - insns.push(( - Inst::Extend { - rd: writable_rreg(0), - rm: rreg(1), - from_bits: 16, - signed: false, - }, - "88B2", - "uxth r0, r1", - )); - insns.push(( - Inst::Extend { - rd: writable_rreg(8), - rm: rreg(9), - from_bits: 16, - signed: false, - }, - "1FFA89F8", - "uxth r8, r9", - )); - insns.push(( - Inst::Extend { - rd: writable_rreg(0), - rm: rreg(1), - from_bits: 8, - signed: false, - }, - "C8B2", - "uxtb r0, r1", - )); - insns.push(( - Inst::Extend { - rd: writable_rreg(8), - rm: rreg(9), - from_bits: 8, - signed: false, - }, - "5FFA89F8", - "uxtb r8, r9", - )); - insns.push(( - Inst::Extend { - rd: writable_rreg(0), - rm: rreg(1), - from_bits: 16, - signed: true, - }, - "08B2", - "sxth r0, r1", - )); - insns.push(( - Inst::Extend { - rd: writable_rreg(8), - rm: rreg(9), - from_bits: 16, - signed: true, - }, - "0FFA89F8", - "sxth r8, r9", - )); - insns.push(( - Inst::Extend { - rd: writable_rreg(0), - rm: rreg(1), - from_bits: 8, - signed: true, - }, - "48B2", - "sxtb r0, r1", - )); - insns.push(( - Inst::Extend { - rd: writable_rreg(8), - rm: rreg(9), - from_bits: 8, - signed: true, - }, - "4FFA89F8", - "sxtb r8, r9", - )); - insns.push(( - Inst::It { - cond: Cond::Eq, - insts: vec![CondInst::new(Inst::mov(writable_rreg(0), rreg(0)), true)], - }, - "08BF0046", - "it eq ; mov r0, r0", - )); - insns.push(( - Inst::It { - cond: Cond::Ne, - insts: vec![ - CondInst::new(Inst::mov(writable_rreg(0), rreg(0)), true), - CondInst::new(Inst::mov(writable_rreg(0), rreg(0)), false), - ], - }, - "14BF00460046", - "ite ne ; mov r0, r0 ; mov r0, r0", - )); - insns.push(( - Inst::It { - cond: Cond::Lt, - insts: vec![ - CondInst::new(Inst::mov(writable_rreg(0), rreg(0)), true), - CondInst::new(Inst::mov(writable_rreg(0), rreg(0)), false), - CondInst::new(Inst::mov(writable_rreg(0), rreg(0)), true), - ], - }, - "B6BF004600460046", - "itet lt ; mov r0, r0 ; mov r0, r0 ; mov r0, r0", - )); - insns.push(( - Inst::It { - cond: Cond::Hs, - insts: vec![ - CondInst::new(Inst::mov(writable_rreg(0), rreg(0)), true), - CondInst::new(Inst::mov(writable_rreg(0), rreg(0)), true), - CondInst::new(Inst::mov(writable_rreg(0), rreg(0)), false), - CondInst::new(Inst::mov(writable_rreg(0), rreg(0)), false), - ], - }, - "27BF0046004600460046", - "ittee hs ; mov r0, r0 ; mov r0, r0 ; mov r0, r0 ; mov r0, r0", - )); - insns.push(( - Inst::Push { - reg_list: vec![rreg(0)], - }, - "4DF8040D", - "push {r0}", - )); - insns.push(( - Inst::Push { - reg_list: vec![rreg(8)], - }, - "4DF8048D", - "push {r8}", - )); - insns.push(( - Inst::Push { - reg_list: vec![rreg(0), rreg(1), rreg(2), rreg(6), rreg(8)], - }, - "2DE94701", - "push {r0, r1, r2, r6, r8}", - )); - insns.push(( - Inst::Push { - reg_list: vec![rreg(8), rreg(9), rreg(10)], - }, - "2DE90007", - "push {r8, r9, r10}", - )); - insns.push(( - Inst::Pop { - reg_list: vec![writable_rreg(0)], - }, - "5DF8040B", - "pop {r0}", - )); - insns.push(( - Inst::Pop { - reg_list: vec![writable_rreg(8)], - }, - "5DF8048B", - "pop {r8}", - )); - insns.push(( - Inst::Pop { - reg_list: vec![ - writable_rreg(0), - writable_rreg(1), - writable_rreg(2), - writable_rreg(6), - writable_rreg(8), - ], - }, - "BDE84701", - "pop {r0, r1, r2, r6, r8}", - )); - insns.push(( - Inst::Pop { - reg_list: vec![writable_rreg(8), writable_rreg(9), writable_rreg(10)], - }, - "BDE80007", - "pop {r8, r9, r10}", - )); - insns.push(( - Inst::Call { - info: Box::new(CallInfo { - dest: ExternalName::testcase("test0"), - uses: Vec::new(), - defs: Vec::new(), - loc: SourceLoc::default(), - opcode: Opcode::Call, - }), - }, - "00F000D0", - "bl 0", - )); - insns.push(( - Inst::CallInd { - info: Box::new(CallIndInfo { - rm: rreg(0), - uses: Vec::new(), - defs: Vec::new(), - loc: SourceLoc::default(), - opcode: Opcode::CallIndirect, - }), - }, - "8047", - "blx r0", - )); - insns.push(( - Inst::CallInd { - info: Box::new(CallIndInfo { - rm: rreg(8), - uses: Vec::new(), - defs: Vec::new(), - loc: SourceLoc::default(), - opcode: Opcode::CallIndirect, - }), - }, - "C047", - "blx r8", - )); - insns.push((Inst::Ret, "7047", "bx lr")); - insns.push(( - Inst::Jump { - dest: BranchTarget::ResolvedOffset(32), - }, - "00F010B8", - "b 32", - )); - insns.push(( - Inst::Jump { - dest: BranchTarget::ResolvedOffset(0xfffff4), - }, - "FFF3FA97", - "b 16777204", - )); - insns.push(( - Inst::CondBr { - taken: BranchTarget::ResolvedOffset(20), - not_taken: BranchTarget::ResolvedOffset(68), - cond: Cond::Eq, - }, - "00F00A8000F022B8", - "beq 20 ; b 68", - )); - insns.push(( - Inst::CondBr { - taken: BranchTarget::ResolvedOffset(6), - not_taken: BranchTarget::ResolvedOffset(100), - cond: Cond::Gt, - }, - "00F3038000F032B8", - "bgt 6 ; b 100", - )); - insns.push(( - Inst::IndirectBr { - rm: rreg(0), - targets: vec![], - }, - "0047", - "bx r0", - )); - insns.push(( - Inst::IndirectBr { - rm: rreg(8), - targets: vec![], - }, - "4047", - "bx r8", - )); - insns.push(( - Inst::TrapIf { - cond: Cond::Eq, - trap_info: TrapCode::Interrupt, - }, - "40F0018000DE", - "bne 2 ; udf #0", - )); - insns.push(( - Inst::TrapIf { - cond: Cond::Hs, - trap_info: TrapCode::Interrupt, - }, - "C0F0018000DE", - "blo 2 ; udf #0", - )); - insns.push(( - Inst::Udf { - trap_info: TrapCode::Interrupt, - }, - "00DE", - "udf #0", - )); - insns.push((Inst::Bkpt, "00BE", "bkpt #0")); - - // ======================================================== - // Run the tests - let rru = regs::create_reg_universe(); - for (insn, expected_encoding, expected_printing) in insns { - // Check the printed text is as expected. - let actual_printing = insn.show_rru(Some(&rru)); - assert_eq!(expected_printing, actual_printing); - let mut buffer = MachBuffer::new(); - insn.emit(&mut buffer, &flags, &mut Default::default()); - let buffer = buffer.finish(); - let actual_encoding = &buffer.stringify_code_bytes(); - assert_eq!(expected_encoding, actual_encoding, "{}", expected_printing); - } -} diff --git a/cranelift/codegen/src/isa/arm32/inst/mod.rs b/cranelift/codegen/src/isa/arm32/inst/mod.rs deleted file mode 100644 index 7cba5d6c1c48..000000000000 --- a/cranelift/codegen/src/isa/arm32/inst/mod.rs +++ /dev/null @@ -1,1361 +0,0 @@ -//! This module defines 32-bit ARM specific machine instruction types. - -#![allow(dead_code)] - -use crate::binemit::{Addend, CodeOffset, Reloc}; -use crate::ir::types::{B1, B16, B32, B8, I16, I32, I8, IFLAGS}; -use crate::ir::{ExternalName, Opcode, TrapCode, Type}; -use crate::machinst::*; -use crate::{settings, CodegenError, CodegenResult}; - -use regalloc::{PrettyPrint, RealRegUniverse, Reg, RegClass, SpillSlot, VirtualReg, Writable}; -use regalloc::{RegUsageCollector, RegUsageMapper}; - -use alloc::boxed::Box; -use alloc::vec::Vec; -use smallvec::{smallvec, SmallVec}; -use std::string::{String, ToString}; - -mod args; -pub use self::args::*; -mod emit; -pub use self::emit::*; -mod regs; -pub use self::regs::*; - -#[cfg(test)] -mod emit_tests; - -//============================================================================= -// Instructions (top level): definition - -/// An ALU operation. This can be paired with several instruction formats -/// below (see `Inst`) in any combination. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum ALUOp { - Add, - Adds, - Adc, - Adcs, - Qadd, - Sub, - Subs, - Sbc, - Sbcs, - Rsb, - Qsub, - Mul, - Smull, - Umull, - Udiv, - Sdiv, - And, - Orr, - Orn, - Eor, - Bic, - Lsl, - Lsr, - Asr, - Ror, -} - -/// An ALU operation with one argument. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum ALUOp1 { - Mvn, - Mov, -} - -/// An operation on the bits of a register. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum BitOp { - Rbit, - Rev, - Clz, -} - -/// Additional information for (direct) Call instructions, left out of line to lower the size of -/// the Inst enum. -#[derive(Clone, Debug)] -pub struct CallInfo { - pub dest: ExternalName, - pub uses: Vec, - pub defs: Vec>, - pub opcode: Opcode, -} - -/// Additional information for CallInd instructions, left out of line to lower the size of the Inst -/// enum. -#[derive(Clone, Debug)] -pub struct CallIndInfo { - pub rm: Reg, - pub uses: Vec, - pub defs: Vec>, - pub opcode: Opcode, -} - -/// Instruction formats. -#[derive(Clone, Debug)] -pub enum Inst { - /// A no-op of zero size. - Nop0, - - /// A no-op that is two bytes large. - Nop2, - - /// An ALU operation with two register sources and one register destination. - AluRRR { - alu_op: ALUOp, - rd: Writable, - rn: Reg, - rm: Reg, - }, - - /// An ALU operation with two register sources, one of which can be optionally shifted - /// and one register destination. - AluRRRShift { - alu_op: ALUOp, - rd: Writable, - rn: Reg, - rm: Reg, - shift: Option, - }, - - /// An ALU operation with one register source, which can be optionally shifted - /// and one register destination. - AluRRShift { - alu_op: ALUOp1, - rd: Writable, - rm: Reg, - shift: Option, - }, - - /// An ALU operation with two register sources and two register destinations. - AluRRRR { - alu_op: ALUOp, - rd_hi: Writable, - rd_lo: Writable, - rn: Reg, - rm: Reg, - }, - - /// An ALU operation with a register source and a 12-bit immediate source, - /// and a register destination. - AluRRImm12 { - alu_op: ALUOp, - rd: Writable, - rn: Reg, - imm12: UImm12, - }, - - /// An ALU operation with a register source and a 8-bit immediate source, - /// and a register destination. - /// - /// In fact these instructions take a `modified immediate constant` operand, - /// which is encoded as a 12-bit immediate. The only case used here - /// is when high 4 bits of that 12-immediate are zeros. - /// In this case operand is simple 8-bit immediate. - /// For all possible operands see - /// https://static.docs.arm.com/ddi0406/c/DDI0406C_C_arm_architecture_reference_manual.pdf#G10.4954509 - AluRRImm8 { - alu_op: ALUOp, - rd: Writable, - rn: Reg, - imm8: UImm8, - }, - - /// An ALU operation with a 8-bit immediate and a register destination. - /// See `AluRRImm8` description above. - AluRImm8 { - alu_op: ALUOp1, - rd: Writable, - imm8: UImm8, - }, - - /// A bit operation with a register source and a register destination. - BitOpRR { - bit_op: BitOp, - rd: Writable, - rm: Reg, - }, - - /// A mov instruction with a GPR source and a GPR destination. - Mov { - rd: Writable, - rm: Reg, - }, - - /// A move instruction with a 16-bit immediate source and a register destination. - MovImm16 { - rd: Writable, - imm16: u16, - }, - - /// A move top instruction, which writes 16-bit immediate to the top - /// halfword of the destination register. - Movt { - rd: Writable, - imm16: u16, - }, - - /// A compare instruction with two register arguments. - Cmp { - rn: Reg, - rm: Reg, - }, - - /// A compare instruction with a register operand and a 8-bit immediate operand. - CmpImm8 { - rn: Reg, - imm8: u8, - }, - - /// A store instruction, which stores to memory 8, 16 or 32-bit operand. - Store { - rt: Reg, - mem: AMode, - bits: u8, - }, - - /// A load instruction, which loads from memory 8, 16 or 32-bit operand, - /// which can be sign- or zero-extended. - Load { - rt: Writable, - mem: AMode, - bits: u8, - sign_extend: bool, - }, - - /// Load address referenced by `mem` into `rd`. - LoadAddr { - rd: Writable, - mem: AMode, - }, - - /// A sign- or zero-extend operation. - Extend { - rd: Writable, - rm: Reg, - from_bits: u8, - signed: bool, - }, - - // An If-Then instruction, which makes up to four instructions conditinal. - It { - cond: Cond, - insts: Vec, - }, - - /// A push instuction, which stores registers to the stack and updates sp. - Push { - reg_list: Vec, - }, - - /// A pop instuction, which load registers from the stack and updates sp. - Pop { - reg_list: Vec>, - }, - - /// A machine call instruction. - Call { - info: Box, - }, - - /// A machine indirect-call instruction. - CallInd { - info: Box, - }, - - /// Load an inline symbol reference. - LoadExtName { - rt: Writable, - name: Box, - offset: i32, - }, - - /// A return instruction, which is encoded as `bx lr`. - Ret, - - /// An unconditional branch. - Jump { - dest: BranchTarget, - }, - - /// A conditional branch. - CondBr { - taken: BranchTarget, - not_taken: BranchTarget, - cond: Cond, - }, - - /// An indirect branch through a register, augmented with set of all - /// possible successors. - IndirectBr { - rm: Reg, - targets: Vec, - }, - - /// A conditional trap: execute a `udf` if the condition is true. This is - /// one VCode instruction because it uses embedded control flow; it is - /// logically a single-in, single-out region, but needs to appear as one - /// unit to the register allocator. - TrapIf { - cond: Cond, - trap_info: TrapCode, - }, - - /// An instruction guaranteed to always be undefined and to trigger an illegal instruction at - /// runtime. - Udf { - trap_info: TrapCode, - }, - - /// A "breakpoint" instruction, used for e.g. traps and debug breakpoints. - Bkpt, - - /// Marker, no-op in generated code: SP "virtual offset" is adjusted. - VirtualSPOffsetAdj { - offset: i64, - }, - - /// A placeholder instruction, generating no code, meaning that a function epilogue must be - /// inserted there. - EpiloguePlaceholder, -} - -/// An instruction inside an it block. -#[derive(Clone, Debug)] -pub struct CondInst { - inst: Inst, - // In which case execute the instruction: - // true => when it condition is met - // false => otherwise. - then: bool, -} - -impl CondInst { - pub fn new(inst: Inst, then: bool) -> Self { - match inst { - Inst::It { .. } - | Inst::Ret { .. } - | Inst::Jump { .. } - | Inst::CondBr { .. } - | Inst::TrapIf { .. } - | Inst::EpiloguePlaceholder { .. } - | Inst::LoadExtName { .. } => panic!("Instruction {:?} cannot occur in it block", inst), - _ => Self { inst, then }, - } - } -} - -impl Inst { - /// Create a move instruction. - pub fn mov(to_reg: Writable, from_reg: Reg) -> Inst { - Inst::Mov { - rd: to_reg, - rm: from_reg, - } - } - - /// Create an instruction that loads a constant. - pub fn load_constant(rd: Writable, value: u32) -> SmallVec<[Inst; 4]> { - let mut insts = smallvec![]; - let imm_lo = (value & 0xffff) as u16; - let imm_hi = (value >> 16) as u16; - - if imm_lo != 0 || imm_hi == 0 { - // imm_lo == 0 && imm_hi == 0 => we have to overwrite reg value with 0 - insts.push(Inst::MovImm16 { rd, imm16: imm_lo }); - } - if imm_hi != 0 { - insts.push(Inst::Movt { rd, imm16: imm_hi }); - } - - insts - } - - /// Generic constructor for a load (zero-extending where appropriate). - pub fn gen_load(into_reg: Writable, mem: AMode, ty: Type) -> Inst { - assert!(ty.bits() <= 32); - // Load 8 bits for B1. - let bits = std::cmp::max(ty.bits(), 8) as u8; - - Inst::Load { - rt: into_reg, - mem, - bits, - sign_extend: false, - } - } - - /// Generic constructor for a store. - pub fn gen_store(from_reg: Reg, mem: AMode, ty: Type) -> Inst { - assert!(ty.bits() <= 32); - // Store 8 bits for B1. - let bits = std::cmp::max(ty.bits(), 8) as u8; - - Inst::Store { - rt: from_reg, - mem, - bits, - } - } -} - -//============================================================================= -// Instructions: get_regs - -fn memarg_regs(memarg: &AMode, collector: &mut RegUsageCollector) { - match memarg { - &AMode::RegReg(rn, rm, ..) => { - collector.add_use(rn); - collector.add_use(rm); - } - &AMode::RegOffset12(rn, ..) | &AMode::RegOffset(rn, _) => { - collector.add_use(rn); - } - &AMode::SPOffset(..) | &AMode::NominalSPOffset(..) => { - collector.add_use(sp_reg()); - } - &AMode::FPOffset(..) => { - collector.add_use(fp_reg()); - } - &AMode::PCRel(_) => {} - } -} - -fn arm32_get_regs(inst: &Inst, collector: &mut RegUsageCollector) { - match inst { - &Inst::Nop0 - | &Inst::Nop2 - | &Inst::Ret - | &Inst::VirtualSPOffsetAdj { .. } - | &Inst::EpiloguePlaceholder - | &Inst::Jump { .. } - | &Inst::CondBr { .. } - | &Inst::Bkpt - | &Inst::Udf { .. } - | &Inst::TrapIf { .. } => {} - &Inst::AluRRR { rd, rn, rm, .. } => { - collector.add_def(rd); - collector.add_use(rn); - collector.add_use(rm); - } - &Inst::AluRRRShift { rd, rn, rm, .. } => { - collector.add_def(rd); - collector.add_use(rn); - collector.add_use(rm); - } - &Inst::AluRRShift { rd, rm, .. } => { - collector.add_def(rd); - collector.add_use(rm); - } - &Inst::AluRRRR { - rd_hi, - rd_lo, - rn, - rm, - .. - } => { - collector.add_def(rd_hi); - collector.add_def(rd_lo); - collector.add_use(rn); - collector.add_use(rm); - } - &Inst::AluRRImm12 { rd, rn, .. } => { - collector.add_def(rd); - collector.add_use(rn); - } - &Inst::AluRRImm8 { rd, rn, .. } => { - collector.add_def(rd); - collector.add_use(rn); - } - &Inst::AluRImm8 { rd, .. } => { - collector.add_def(rd); - } - &Inst::BitOpRR { rd, rm, .. } => { - collector.add_def(rd); - collector.add_use(rm); - } - &Inst::Mov { rd, rm, .. } => { - collector.add_def(rd); - collector.add_use(rm); - } - &Inst::MovImm16 { rd, .. } => { - collector.add_def(rd); - } - &Inst::Movt { rd, .. } => { - collector.add_def(rd); - } - &Inst::Cmp { rn, rm } => { - collector.add_use(rn); - collector.add_use(rm); - } - &Inst::CmpImm8 { rn, .. } => { - collector.add_use(rn); - } - &Inst::Store { rt, ref mem, .. } => { - collector.add_use(rt); - memarg_regs(mem, collector); - } - &Inst::Load { rt, ref mem, .. } => { - collector.add_def(rt); - memarg_regs(mem, collector); - } - &Inst::LoadAddr { rd, mem: _ } => { - collector.add_def(rd); - } - &Inst::Extend { rd, rm, .. } => { - collector.add_def(rd); - collector.add_use(rm); - } - &Inst::It { ref insts, .. } => { - for inst in insts.iter() { - arm32_get_regs(&inst.inst, collector); - } - } - &Inst::Push { ref reg_list } => { - for reg in reg_list { - collector.add_use(*reg); - } - } - &Inst::Pop { ref reg_list } => { - for reg in reg_list { - collector.add_def(*reg); - } - } - &Inst::Call { ref info, .. } => { - collector.add_uses(&*info.uses); - collector.add_defs(&*info.defs); - } - &Inst::CallInd { ref info, .. } => { - collector.add_uses(&*info.uses); - collector.add_defs(&*info.defs); - collector.add_use(info.rm); - } - &Inst::LoadExtName { rt, .. } => { - collector.add_def(rt); - } - &Inst::IndirectBr { rm, .. } => { - collector.add_use(rm); - } - } -} - -//============================================================================= -// Instructions: map_regs - -fn arm32_map_regs(inst: &mut Inst, mapper: &RUM) { - fn map_use(m: &RUM, r: &mut Reg) { - if r.is_virtual() { - let new = m.get_use(r.to_virtual_reg()).unwrap().to_reg(); - *r = new; - } - } - - fn map_def(m: &RUM, r: &mut Writable) { - if r.to_reg().is_virtual() { - let new = m.get_def(r.to_reg().to_virtual_reg()).unwrap().to_reg(); - *r = Writable::from_reg(new); - } - } - - fn map_mod(m: &RUM, r: &mut Writable) { - if r.to_reg().is_virtual() { - let new = m.get_mod(r.to_reg().to_virtual_reg()).unwrap().to_reg(); - *r = Writable::from_reg(new); - } - } - - fn map_mem(m: &RUM, mem: &mut AMode) { - match mem { - &mut AMode::RegReg(ref mut rn, ref mut rm, ..) => { - map_use(m, rn); - map_use(m, rm); - } - &mut AMode::RegOffset12(ref mut rn, ..) | &mut AMode::RegOffset(ref mut rn, ..) => { - map_use(m, rn) - } - &mut AMode::SPOffset(..) - | &mut AMode::FPOffset(..) - | &mut AMode::NominalSPOffset(..) - | &mut AMode::PCRel(_) => {} - }; - } - - match inst { - &mut Inst::Nop0 - | &mut Inst::Nop2 - | &mut Inst::Ret - | &mut Inst::VirtualSPOffsetAdj { .. } - | &mut Inst::EpiloguePlaceholder - | &mut Inst::Jump { .. } - | &mut Inst::CondBr { .. } - | &mut Inst::Bkpt - | &mut Inst::Udf { .. } - | &mut Inst::TrapIf { .. } => {} - &mut Inst::AluRRR { - ref mut rd, - ref mut rn, - ref mut rm, - .. - } => { - map_def(mapper, rd); - map_use(mapper, rn); - map_use(mapper, rm); - } - &mut Inst::AluRRRShift { - ref mut rd, - ref mut rn, - ref mut rm, - .. - } => { - map_def(mapper, rd); - map_use(mapper, rn); - map_use(mapper, rm); - } - &mut Inst::AluRRShift { - ref mut rd, - ref mut rm, - .. - } => { - map_def(mapper, rd); - map_use(mapper, rm); - } - &mut Inst::AluRRRR { - ref mut rd_hi, - ref mut rd_lo, - ref mut rn, - ref mut rm, - .. - } => { - map_def(mapper, rd_hi); - map_def(mapper, rd_lo); - map_use(mapper, rn); - map_use(mapper, rm); - } - &mut Inst::AluRRImm12 { - ref mut rd, - ref mut rn, - .. - } => { - map_def(mapper, rd); - map_use(mapper, rn); - } - &mut Inst::AluRRImm8 { - ref mut rd, - ref mut rn, - .. - } => { - map_def(mapper, rd); - map_use(mapper, rn); - } - &mut Inst::AluRImm8 { ref mut rd, .. } => { - map_def(mapper, rd); - } - &mut Inst::BitOpRR { - ref mut rd, - ref mut rm, - .. - } => { - map_def(mapper, rd); - map_use(mapper, rm); - } - &mut Inst::Mov { - ref mut rd, - ref mut rm, - .. - } => { - map_def(mapper, rd); - map_use(mapper, rm); - } - &mut Inst::MovImm16 { ref mut rd, .. } => { - map_def(mapper, rd); - } - &mut Inst::Movt { ref mut rd, .. } => { - map_def(mapper, rd); - } - &mut Inst::Cmp { - ref mut rn, - ref mut rm, - } => { - map_use(mapper, rn); - map_use(mapper, rm); - } - &mut Inst::CmpImm8 { ref mut rn, .. } => { - map_use(mapper, rn); - } - &mut Inst::Store { - ref mut rt, - ref mut mem, - .. - } => { - map_use(mapper, rt); - map_mem(mapper, mem); - } - &mut Inst::Load { - ref mut rt, - ref mut mem, - .. - } => { - map_def(mapper, rt); - map_mem(mapper, mem); - } - &mut Inst::LoadAddr { - ref mut rd, - ref mut mem, - } => { - map_def(mapper, rd); - map_mem(mapper, mem); - } - &mut Inst::Extend { - ref mut rd, - ref mut rm, - .. - } => { - map_def(mapper, rd); - map_use(mapper, rm); - } - &mut Inst::It { ref mut insts, .. } => { - for inst in insts.iter_mut() { - arm32_map_regs(&mut inst.inst, mapper); - } - } - &mut Inst::Push { ref mut reg_list } => { - for reg in reg_list { - map_use(mapper, reg); - } - } - &mut Inst::Pop { ref mut reg_list } => { - for reg in reg_list { - map_def(mapper, reg); - } - } - &mut Inst::Call { ref mut info } => { - for r in info.uses.iter_mut() { - map_use(mapper, r); - } - for r in info.defs.iter_mut() { - map_def(mapper, r); - } - } - &mut Inst::CallInd { ref mut info, .. } => { - for r in info.uses.iter_mut() { - map_use(mapper, r); - } - for r in info.defs.iter_mut() { - map_def(mapper, r); - } - map_use(mapper, &mut info.rm); - } - &mut Inst::LoadExtName { ref mut rt, .. } => { - map_def(mapper, rt); - } - &mut Inst::IndirectBr { ref mut rm, .. } => { - map_use(mapper, rm); - } - } -} - -//============================================================================= -// Instructions: misc functions and external interface - -impl MachInst for Inst { - type LabelUse = LabelUse; - - fn get_regs(&self, collector: &mut RegUsageCollector) { - arm32_get_regs(self, collector) - } - - fn map_regs(&mut self, mapper: &RUM) { - arm32_map_regs(self, mapper); - } - - fn is_move(&self) -> Option<(Writable, Reg)> { - match self { - &Inst::Mov { rd, rm } => Some((rd, rm)), - _ => None, - } - } - - fn is_epilogue_placeholder(&self) -> bool { - if let Inst::EpiloguePlaceholder = self { - true - } else { - false - } - } - - fn is_term<'a>(&'a self) -> MachTerminator<'a> { - match self { - &Inst::Ret | &Inst::EpiloguePlaceholder => MachTerminator::Ret, - &Inst::Jump { dest } => MachTerminator::Uncond(dest.as_label().unwrap()), - &Inst::CondBr { - taken, not_taken, .. - } => MachTerminator::Cond(taken.as_label().unwrap(), not_taken.as_label().unwrap()), - &Inst::IndirectBr { ref targets, .. } => MachTerminator::Indirect(&targets[..]), - _ => MachTerminator::None, - } - } - - fn gen_move(to_reg: Writable, from_reg: Reg, _ty: Type) -> Inst { - assert_eq!(from_reg.get_class(), RegClass::I32); - assert_eq!(to_reg.to_reg().get_class(), from_reg.get_class()); - - Inst::mov(to_reg, from_reg) - } - - fn gen_constant Writable>( - to_regs: ValueRegs>, - value: u128, - ty: Type, - _alloc_tmp: F, - ) -> SmallVec<[Inst; 4]> { - let to_reg = to_regs - .only_reg() - .expect("multi-reg values not supported yet"); - let value = value as u64; - - match ty { - B1 | I8 | B8 | I16 | B16 | I32 | B32 => { - let v: i64 = value as i64; - - if v >= (1 << 32) || v < -(1 << 32) { - panic!("Cannot load constant value {}", value) - } - Inst::load_constant(to_reg, value as u32) - } - _ => unimplemented!(), - } - } - - fn gen_nop(preferred_size: usize) -> Inst { - if preferred_size == 0 { - return Inst::Nop0; - } - assert!(preferred_size >= 2); - Inst::Nop2 - } - - fn maybe_direct_reload(&self, _reg: VirtualReg, _slot: SpillSlot) -> Option { - None - } - - fn rc_for_type(ty: Type) -> CodegenResult<(&'static [RegClass], &'static [Type])> { - match ty { - I8 | I16 | I32 | B1 | B8 | B16 | B32 => Ok((&[RegClass::I32], &[I32])), - IFLAGS => Ok((&[RegClass::I32], &[I32])), - _ => Err(CodegenError::Unsupported(format!( - "Unexpected SSA-value type: {}", - ty - ))), - } - } - - fn gen_jump(target: MachLabel) -> Inst { - Inst::Jump { - dest: BranchTarget::Label(target), - } - } - - fn worst_case_size() -> CodeOffset { - // It inst with four 32-bit instructions - 2 + 4 * 4 - } - - fn ref_type_regclass(_: &settings::Flags) -> RegClass { - RegClass::I32 - } -} - -//============================================================================= -// Pretty-printing of instructions. - -fn mem_finalize_for_show( - mem: &AMode, - mb_rru: Option<&RealRegUniverse>, - state: &EmitState, -) -> (String, AMode) { - let (mem_insts, mem) = mem_finalize(mem, state); - let mut mem_str = mem_insts - .into_iter() - .map(|inst| inst.show_rru(mb_rru)) - .collect::>() - .join(" ; "); - if !mem_str.is_empty() { - mem_str += " ; "; - } - - (mem_str, mem) -} - -impl PrettyPrint for Inst { - fn show_rru(&self, mb_rru: Option<&RealRegUniverse>) -> String { - self.pretty_print(mb_rru, &mut EmitState::default()) - } -} - -impl Inst { - fn print_with_state(&self, mb_rru: Option<&RealRegUniverse>, state: &mut EmitState) -> String { - fn op_name(alu_op: ALUOp) -> &'static str { - match alu_op { - ALUOp::Add => "add", - ALUOp::Adds => "adds", - ALUOp::Adc => "adc", - ALUOp::Adcs => "adcs", - ALUOp::Qadd => "qadd", - ALUOp::Sub => "sub", - ALUOp::Subs => "subs", - ALUOp::Sbc => "sbc", - ALUOp::Sbcs => "sbcs", - ALUOp::Rsb => "rsb", - ALUOp::Qsub => "qsub", - ALUOp::Mul => "mul", - ALUOp::Smull => "smull", - ALUOp::Umull => "umull", - ALUOp::Udiv => "udiv", - ALUOp::Sdiv => "sdiv", - ALUOp::And => "and", - ALUOp::Orr => "orr", - ALUOp::Orn => "orn", - ALUOp::Eor => "eor", - ALUOp::Bic => "bic", - ALUOp::Lsl => "lsl", - ALUOp::Lsr => "lsr", - ALUOp::Asr => "asr", - ALUOp::Ror => "ror", - } - } - - fn reg_shift_str( - shift: &Option, - mb_rru: Option<&RealRegUniverse>, - ) -> String { - if let Some(ref shift) = shift { - format!(", {}", shift.show_rru(mb_rru)) - } else { - "".to_string() - } - } - - match self { - &Inst::Nop0 => "nop-zero-len".to_string(), - &Inst::Nop2 => "nop".to_string(), - &Inst::AluRRR { alu_op, rd, rn, rm } => { - let op = op_name(alu_op); - let rd = rd.show_rru(mb_rru); - let rn = rn.show_rru(mb_rru); - let rm = rm.show_rru(mb_rru); - format!("{} {}, {}, {}", op, rd, rn, rm) - } - &Inst::AluRRRShift { - alu_op, - rd, - rn, - rm, - ref shift, - } => { - let op = op_name(alu_op); - let rd = rd.show_rru(mb_rru); - let rn = rn.show_rru(mb_rru); - let rm = rm.show_rru(mb_rru); - let shift = reg_shift_str(shift, mb_rru); - format!("{} {}, {}, {}{}", op, rd, rn, rm, shift) - } - &Inst::AluRRShift { - alu_op, - rd, - rm, - ref shift, - } => { - let op = match alu_op { - ALUOp1::Mvn => "mvn", - ALUOp1::Mov => "mov", - }; - let rd = rd.show_rru(mb_rru); - let rm = rm.show_rru(mb_rru); - let shift = reg_shift_str(shift, mb_rru); - format!("{} {}, {}{}", op, rd, rm, shift) - } - &Inst::AluRRRR { - alu_op, - rd_hi, - rd_lo, - rn, - rm, - } => { - let op = op_name(alu_op); - let rd_hi = rd_hi.show_rru(mb_rru); - let rd_lo = rd_lo.show_rru(mb_rru); - let rn = rn.show_rru(mb_rru); - let rm = rm.show_rru(mb_rru); - format!("{} {}, {}, {}, {}", op, rd_lo, rd_hi, rn, rm) - } - &Inst::AluRRImm12 { - alu_op, - rd, - rn, - imm12, - } => { - let op = op_name(alu_op); - let rd = rd.show_rru(mb_rru); - let rn = rn.show_rru(mb_rru); - let imm = imm12.show_rru(mb_rru); - format!("{} {}, {}, {}", op, rd, rn, imm) - } - &Inst::AluRRImm8 { - alu_op, - rd, - rn, - imm8, - } => { - let op = op_name(alu_op); - let rd = rd.show_rru(mb_rru); - let rn = rn.show_rru(mb_rru); - let imm = imm8.show_rru(mb_rru); - format!("{} {}, {}, {}", op, rd, rn, imm) - } - &Inst::AluRImm8 { alu_op, rd, imm8 } => { - let op = match alu_op { - ALUOp1::Mvn => "mvn", - ALUOp1::Mov => "mov", - }; - let rd = rd.show_rru(mb_rru); - let imm = imm8.show_rru(mb_rru); - format!("{} {}, {}", op, rd, imm) - } - &Inst::BitOpRR { bit_op, rd, rm } => { - let op = match bit_op { - BitOp::Rbit => "rbit", - BitOp::Rev => "rev", - BitOp::Clz => "clz", - }; - let rd = rd.show_rru(mb_rru); - let rm = rm.show_rru(mb_rru); - format!("{} {}, {}", op, rd, rm) - } - &Inst::Mov { rd, rm } => { - let rd = rd.show_rru(mb_rru); - let rm = rm.show_rru(mb_rru); - format!("mov {}, {}", rd, rm) - } - &Inst::MovImm16 { rd, imm16 } => { - let rd = rd.show_rru(mb_rru); - format!("mov {}, #{}", rd, imm16) - } - &Inst::Movt { rd, imm16 } => { - let rd = rd.show_rru(mb_rru); - format!("movt {}, #{}", rd, imm16) - } - &Inst::Cmp { rn, rm } => { - let rn = rn.show_rru(mb_rru); - let rm = rm.show_rru(mb_rru); - format!("cmp {}, {}", rn, rm) - } - &Inst::CmpImm8 { rn, imm8 } => { - let rn = rn.show_rru(mb_rru); - format!("cmp {}, #{}", rn, imm8) - } - &Inst::Store { - rt, ref mem, bits, .. - } => { - let op = match bits { - 32 => "str", - 16 => "strh", - 8 => "strb", - _ => panic!("Invalid bit amount {}", bits), - }; - let rt = rt.show_rru(mb_rru); - let (mem_str, mem) = mem_finalize_for_show(mem, mb_rru, state); - let mem = mem.show_rru(mb_rru); - format!("{}{} {}, {}", mem_str, op, rt, mem) - } - &Inst::Load { - rt, - ref mem, - bits, - sign_extend, - .. - } => { - let op = match (bits, sign_extend) { - (32, _) => "ldr", - (16, true) => "ldrsh", - (16, false) => "ldrh", - (8, true) => "ldrsb", - (8, false) => "ldrb", - (_, _) => panic!("Invalid bit amount {}", bits), - }; - let rt = rt.show_rru(mb_rru); - let (mem_str, mem) = mem_finalize_for_show(mem, mb_rru, state); - let mem = mem.show_rru(mb_rru); - format!("{}{} {}, {}", mem_str, op, rt, mem) - } - &Inst::LoadAddr { rd, ref mem } => { - let mut ret = String::new(); - let (mem_insts, mem) = mem_finalize(mem, state); - for inst in mem_insts.into_iter() { - ret.push_str(&inst.show_rru(mb_rru)); - } - let inst = match mem { - AMode::RegReg(rn, rm, shift) => { - let shift = u32::from(shift); - let shift_amt = ShiftOpShiftImm::maybe_from_shift(shift).unwrap(); - let shift = ShiftOpAndAmt::new(ShiftOp::LSL, shift_amt); - Inst::AluRRRShift { - alu_op: ALUOp::Add, - rd, - rn, - rm, - shift: Some(shift), - } - } - AMode::RegOffset12(reg, imm12) => Inst::AluRRImm12 { - alu_op: ALUOp::Add, - rd, - rn: reg, - imm12, - }, - _ => unreachable!(), - }; - ret.push_str(&inst.show_rru(mb_rru)); - ret - } - &Inst::Extend { - rd, - rm, - from_bits, - signed, - } => { - let op = match (from_bits, signed) { - (16, true) => "sxth", - (16, false) => "uxth", - (8, true) => "sxtb", - (8, false) => "uxtb", - _ => panic!("Unsupported extend case: {:?}", self), - }; - let rd = rd.show_rru(mb_rru); - let rm = rm.show_rru(mb_rru); - format!("{} {}, {}", op, rd, rm) - } - &Inst::It { cond, ref insts } => { - let te: String = insts - .iter() - .skip(1) - .map(|i| if i.then { "t" } else { "e" }) - .collect(); - let cond = cond.show_rru(mb_rru); - let mut ret = format!("it{} {}", te, cond); - for inst in insts.into_iter() { - ret.push_str(" ; "); - ret.push_str(&inst.inst.show_rru(mb_rru)); - } - ret - } - &Inst::Push { ref reg_list } => { - assert!(!reg_list.is_empty()); - let first_reg = reg_list[0].show_rru(mb_rru); - let regs: String = reg_list - .iter() - .skip(1) - .map(|r| [",", &r.show_rru(mb_rru)].join(" ")) - .collect(); - format!("push {{{}{}}}", first_reg, regs) - } - &Inst::Pop { ref reg_list } => { - assert!(!reg_list.is_empty()); - let first_reg = reg_list[0].show_rru(mb_rru); - let regs: String = reg_list - .iter() - .skip(1) - .map(|r| [",", &r.show_rru(mb_rru)].join(" ")) - .collect(); - format!("pop {{{}{}}}", first_reg, regs) - } - &Inst::Call { .. } => format!("bl 0"), - &Inst::CallInd { ref info, .. } => { - let rm = info.rm.show_rru(mb_rru); - format!("blx {}", rm) - } - &Inst::LoadExtName { - rt, - ref name, - offset, - } => { - let rt = rt.show_rru(mb_rru); - format!("ldr {}, [pc, #4] ; b 4 ; data {:?} + {}", rt, name, offset) - } - &Inst::Ret => "bx lr".to_string(), - &Inst::VirtualSPOffsetAdj { offset } => format!("virtual_sp_offset_adjust {}", offset), - &Inst::EpiloguePlaceholder => "epilogue placeholder".to_string(), - &Inst::Jump { ref dest } => { - let dest = dest.show_rru(mb_rru); - format!("b {}", dest) - } - &Inst::CondBr { - ref taken, - ref not_taken, - ref cond, - } => { - let taken = taken.show_rru(mb_rru); - let not_taken = not_taken.show_rru(mb_rru); - let c = cond.show_rru(mb_rru); - format!("b{} {} ; b {}", c, taken, not_taken) - } - &Inst::IndirectBr { rm, .. } => { - let rm = rm.show_rru(mb_rru); - format!("bx {}", rm) - } - &Inst::Udf { .. } => "udf #0".to_string(), - &Inst::Bkpt => "bkpt #0".to_string(), - &Inst::TrapIf { cond, .. } => { - let c = cond.invert().show_rru(mb_rru); - format!("b{} 2 ; udf #0", c) - } - } - } -} - -//============================================================================= -// Label fixups and jump veneers. - -/// Different forms of label references for different instruction formats. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum LabelUse { - /// 20-bit branch offset used by 32-bit conditional jumps. - Branch20, - - /// 24-bit branch offset used by 32-bit uncoditional jump instruction. - Branch24, -} - -impl MachInstLabelUse for LabelUse { - /// Alignment for veneer code. Every instruction must be 4-byte-aligned. - const ALIGN: CodeOffset = 2; - - // Branches range: - // 20-bit sign-extended immediate gives us range [-(2^19), 2^19 - 1]. - // Left-shifted by 1 => [-(2^20), 2^20 - 2]. - // PC is start of this instruction + 4 bytes => [-(2^20) + 4, 2^20 + 2]. - // Likewise for Branch24. - - /// Maximum PC-relative range (positive), inclusive. - fn max_pos_range(self) -> CodeOffset { - match self { - LabelUse::Branch20 => (1 << 20) + 2, - LabelUse::Branch24 => (1 << 24) + 2, - } - } - - /// Maximum PC-relative range (negative). - fn max_neg_range(self) -> CodeOffset { - match self { - LabelUse::Branch20 => (1 << 20) - 4, - LabelUse::Branch24 => (1 << 24) - 4, - } - } - - /// Size of window into code needed to do the patch. - fn patch_size(self) -> CodeOffset { - 4 - } - - /// Perform the patch. - fn patch(self, buffer: &mut [u8], use_offset: CodeOffset, label_offset: CodeOffset) { - let off = (label_offset as i64) - (use_offset as i64); - debug_assert!(off <= self.max_pos_range() as i64); - debug_assert!(off >= -(self.max_neg_range() as i64)); - let off = off - 4; - match self { - LabelUse::Branch20 => { - let off = off as u32 >> 1; - let imm11 = (off & 0x7ff) as u16; - let imm6 = ((off >> 11) & 0x3f) as u16; - let j1 = ((off >> 17) & 0x1) as u16; - let j2 = ((off >> 18) & 0x1) as u16; - let s = ((off >> 19) & 0x1) as u16; - let insn_fst = u16::from_le_bytes([buffer[0], buffer[1]]); - let insn_fst = (insn_fst & !0x43f) | imm6 | (s << 10); - let insn_snd = u16::from_le_bytes([buffer[2], buffer[3]]); - let insn_snd = (insn_snd & !0x2fff) | imm11 | (j2 << 11) | (j1 << 13); - buffer[0..2].clone_from_slice(&u16::to_le_bytes(insn_fst)); - buffer[2..4].clone_from_slice(&u16::to_le_bytes(insn_snd)); - } - LabelUse::Branch24 => { - let off = off as u32 >> 1; - let imm11 = (off & 0x7ff) as u16; - let imm10 = ((off >> 11) & 0x3ff) as u16; - let s = ((off >> 23) & 0x1) as u16; - let j1 = (((off >> 22) & 0x1) as u16 ^ s) ^ 0x1; - let j2 = (((off >> 21) & 0x1) as u16 ^ s) ^ 0x1; - let insn_fst = u16::from_le_bytes([buffer[0], buffer[1]]); - let insn_fst = (insn_fst & !0x07ff) | imm10 | (s << 10); - let insn_snd = u16::from_le_bytes([buffer[2], buffer[3]]); - let insn_snd = (insn_snd & !0x2fff) | imm11 | (j2 << 11) | (j1 << 13); - buffer[0..2].clone_from_slice(&u16::to_le_bytes(insn_fst)); - buffer[2..4].clone_from_slice(&u16::to_le_bytes(insn_snd)); - } - } - } - - fn supports_veneer(self) -> bool { - false - } - - fn veneer_size(self) -> CodeOffset { - 0 - } - - fn generate_veneer( - self, - _buffer: &mut [u8], - _veneer_offset: CodeOffset, - ) -> (CodeOffset, LabelUse) { - panic!("Veneer not supported yet.") - } - - fn from_reloc(_reloc: Reloc, _addend: Addend) -> Option { - None - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn patch_branch20() { - let label_use = LabelUse::Branch20; - let mut buffer = 0x8000_f000_u32.to_le_bytes(); // beq - let use_offset: CodeOffset = 0; - let label_offset: CodeOffset = label_use.max_pos_range(); - label_use.patch(&mut buffer, use_offset, label_offset); - assert_eq!(u16::from_le_bytes([buffer[0], buffer[1]]), 0xf03f); - assert_eq!(u16::from_le_bytes([buffer[2], buffer[3]]), 0xafff); - - let mut buffer = 0x8000_f000_u32.to_le_bytes(); // beq - let use_offset = label_use.max_neg_range(); - let label_offset: CodeOffset = 0; - label_use.patch(&mut buffer, use_offset, label_offset); - assert_eq!(u16::from_le_bytes([buffer[0], buffer[1]]), 0xf400); - assert_eq!(u16::from_le_bytes([buffer[2], buffer[3]]), 0x8000); - } - - #[test] - fn patch_branch24() { - let label_use = LabelUse::Branch24; - let mut buffer = 0x9000_f000_u32.to_le_bytes(); // b - let use_offset: CodeOffset = 0; - let label_offset: CodeOffset = label_use.max_pos_range(); - label_use.patch(&mut buffer, use_offset, label_offset); - assert_eq!(u16::from_le_bytes([buffer[0], buffer[1]]), 0xf3ff); - assert_eq!(u16::from_le_bytes([buffer[2], buffer[3]]), 0x97ff); - - let mut buffer = 0x9000_f000_u32.to_le_bytes(); // b - let use_offset = label_use.max_neg_range(); - let label_offset: CodeOffset = 0; - label_use.patch(&mut buffer, use_offset, label_offset); - assert_eq!(u16::from_le_bytes([buffer[0], buffer[1]]), 0xf400); - assert_eq!(u16::from_le_bytes([buffer[2], buffer[3]]), 0x9000); - } -} diff --git a/cranelift/codegen/src/isa/arm32/inst/regs.rs b/cranelift/codegen/src/isa/arm32/inst/regs.rs deleted file mode 100644 index 55df5c8db3bc..000000000000 --- a/cranelift/codegen/src/isa/arm32/inst/regs.rs +++ /dev/null @@ -1,128 +0,0 @@ -//! 32-bit ARM ISA definitions: registers. - -use regalloc::{RealRegUniverse, Reg, RegClass, RegClassInfo, Writable, NUM_REG_CLASSES}; - -use std::string::ToString; - -/// Get a reference to a GPR. -pub fn rreg(num: u8) -> Reg { - assert!(num < 16); - Reg::new_real(RegClass::I32, num, num) -} - -/// Get a writable reference to a GPR. -pub fn writable_rreg(num: u8) -> Writable { - Writable::from_reg(rreg(num)) -} - -/// Get a reference to the program counter (r15). -pub fn pc_reg() -> Reg { - rreg(15) -} - -/// Get a writable reference to the program counter. -pub fn writable_pc_reg() -> Writable { - Writable::from_reg(pc_reg()) -} - -/// Get a reference to the link register (r14). -pub fn lr_reg() -> Reg { - rreg(14) -} - -/// Get a writable reference to the link register. -pub fn writable_lr_reg() -> Writable { - Writable::from_reg(lr_reg()) -} - -/// Get a reference to the stack pointer (r13). -pub fn sp_reg() -> Reg { - rreg(13) -} - -/// Get a writable reference to the stack pointer. -pub fn writable_sp_reg() -> Writable { - Writable::from_reg(sp_reg()) -} - -/// Get a reference to the intra-procedure-call scratch register (r12), -/// which is used as a temporary register. -pub fn ip_reg() -> Reg { - rreg(12) -} - -/// Get a writable reference to the Intra-Procedure-call scratch register. -pub fn writable_ip_reg() -> Writable { - Writable::from_reg(ip_reg()) -} - -/// Get a reference to the frame pointer register (r11). -pub fn fp_reg() -> Reg { - rreg(11) -} - -/// Get a writable reference to the frame-pointer register. -pub fn writable_fp_reg() -> Writable { - Writable::from_reg(fp_reg()) -} - -/// Get a reference to the second temp register. We need this in some edge cases -/// where we need both the ip and another temporary. -/// -/// We use r10 for this role. -pub fn tmp2_reg() -> Reg { - rreg(10) -} - -/// Get a writable reference to the tmp2 reg. -pub fn writable_tmp2_reg() -> Writable { - Writable::from_reg(tmp2_reg()) -} - -/// Create the register universe. -/// Use only GPR for now. -pub fn create_reg_universe() -> RealRegUniverse { - let mut regs = vec![]; - let mut allocable_by_class = [None; NUM_REG_CLASSES]; - - let r_reg_base = 0u8; - let r_reg_count = 10; // to exclude r10, fp, ip, sp, lr and pc. - for i in 0..r_reg_count { - let reg = Reg::new_real( - RegClass::I32, - /* enc = */ i, - /* index = */ r_reg_base + i, - ) - .to_real_reg(); - let name = format!("r{}", i); - regs.push((reg, name)); - } - let r_reg_last = r_reg_base + r_reg_count - 1; - - allocable_by_class[RegClass::I32.rc_to_usize()] = Some(RegClassInfo { - first: r_reg_base as usize, - last: r_reg_last as usize, - suggested_scratch: None, - }); - - // Other regs, not available to the allocator. - let allocable = regs.len(); - regs.push((tmp2_reg().to_real_reg(), "r10".to_string())); - regs.push((fp_reg().to_real_reg(), "fp".to_string())); - regs.push((ip_reg().to_real_reg(), "ip".to_string())); - regs.push((sp_reg().to_real_reg(), "sp".to_string())); - regs.push((lr_reg().to_real_reg(), "lr".to_string())); - regs.push((pc_reg().to_real_reg(), "pc".to_string())); - - // The indices in the register structs must match their - // actual indices in the array. - for (i, reg) in regs.iter().enumerate() { - assert_eq!(i, reg.0.get_index()); - } - - RealRegUniverse { - regs, - allocable, - allocable_by_class, - } -} diff --git a/cranelift/codegen/src/isa/arm32/lower.rs b/cranelift/codegen/src/isa/arm32/lower.rs deleted file mode 100644 index f2a35f9820ef..000000000000 --- a/cranelift/codegen/src/isa/arm32/lower.rs +++ /dev/null @@ -1,242 +0,0 @@ -//! Lowering rules for 32-bit ARM. - -use crate::ir::condcodes::IntCC; -use crate::ir::types::*; -use crate::ir::Inst as IRInst; -use crate::ir::{InstructionData, Opcode, TrapCode}; -use crate::machinst::lower::*; -use crate::machinst::*; -use crate::CodegenResult; - -use crate::isa::arm32::inst::*; -use crate::isa::arm32::Arm32Backend; - -use super::lower_inst; - -use regalloc::{Reg, Writable}; - -//============================================================================ -// Lowering: convert instruction outputs to result types. - -/// Lower an instruction output to a 32-bit constant, if possible. -pub(crate) fn output_to_const>(ctx: &mut C, out: InsnOutput) -> Option { - if out.output > 0 { - None - } else { - let inst_data = ctx.data(out.insn); - if inst_data.opcode() == Opcode::Null { - Some(0) - } else { - match inst_data { - &InstructionData::UnaryImm { opcode: _, imm } => { - // Only has Into for i64; we use u64 elsewhere, so we cast. - let imm: i64 = imm.into(); - Some(imm as u64) - } - &InstructionData::UnaryBool { opcode: _, imm } => Some(u64::from(imm)), - &InstructionData::UnaryIeee32 { .. } | &InstructionData::UnaryIeee64 { .. } => { - unimplemented!() - } - _ => None, - } - } - } -} - -/// How to handle narrow values loaded into registers. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub(crate) enum NarrowValueMode { - None, - /// Zero-extend to 32 bits if original is < 32 bits. - ZeroExtend, - /// Sign-extend to 32 bits if original is < 32 bits. - SignExtend, -} - -/// Lower an instruction output to a reg. -pub(crate) fn output_to_reg>(ctx: &mut C, out: InsnOutput) -> Writable { - ctx.get_output(out.insn, out.output).only_reg().unwrap() -} - -/// Lower an instruction input to a reg. -/// -/// The given register will be extended appropriately, according to `narrow_mode`. -pub(crate) fn input_to_reg>( - ctx: &mut C, - input: InsnInput, - narrow_mode: NarrowValueMode, -) -> Reg { - let ty = ctx.input_ty(input.insn, input.input); - let from_bits = ty.bits() as u8; - let inputs = ctx.get_input_as_source_or_const(input.insn, input.input); - let in_reg = if let Some(c) = inputs.constant { - let to_reg = ctx.alloc_tmp(ty).only_reg().unwrap(); - for inst in Inst::gen_constant(ValueRegs::one(to_reg), c as u128, ty, |ty| { - ctx.alloc_tmp(ty).only_reg().unwrap() - }) - .into_iter() - { - ctx.emit(inst); - } - to_reg.to_reg() - } else { - ctx.put_input_in_regs(input.insn, input.input) - .only_reg() - .unwrap() - }; - - match (narrow_mode, from_bits) { - (NarrowValueMode::None, _) => in_reg, - (NarrowValueMode::ZeroExtend, 1) => { - let tmp = ctx.alloc_tmp(I32).only_reg().unwrap(); - ctx.emit(Inst::AluRRImm8 { - alu_op: ALUOp::And, - rd: tmp, - rn: in_reg, - imm8: UImm8::maybe_from_i64(0x1).unwrap(), - }); - tmp.to_reg() - } - (NarrowValueMode::ZeroExtend, n) if n < 32 => { - let tmp = ctx.alloc_tmp(I32).only_reg().unwrap(); - ctx.emit(Inst::Extend { - rd: tmp, - rm: in_reg, - signed: false, - from_bits: n, - }); - tmp.to_reg() - } - (NarrowValueMode::SignExtend, n) if n < 32 => { - let tmp = ctx.alloc_tmp(I32).only_reg().unwrap(); - ctx.emit(Inst::Extend { - rd: tmp, - rm: in_reg, - signed: true, - from_bits: n, - }); - tmp.to_reg() - } - (NarrowValueMode::ZeroExtend, 32) | (NarrowValueMode::SignExtend, 32) => in_reg, - _ => panic!( - "Unsupported input width: input ty {} bits {} mode {:?}", - ty, from_bits, narrow_mode - ), - } -} - -pub(crate) fn lower_constant>(ctx: &mut C, rd: Writable, value: u64) { - // We allow sign bits for high word. - assert!((value >> 32) == 0x0 || (value >> 32) == (1 << 32) - 1); - - for inst in Inst::load_constant(rd, (value & ((1 << 32) - 1)) as u32) { - ctx.emit(inst); - } -} - -pub(crate) fn emit_cmp>(ctx: &mut C, insn: IRInst) { - let inputs = [InsnInput { insn, input: 0 }, InsnInput { insn, input: 1 }]; - let rn = input_to_reg(ctx, inputs[0], NarrowValueMode::None); - let rm = input_to_reg(ctx, inputs[1], NarrowValueMode::None); - - ctx.emit(Inst::Cmp { rn, rm }); -} - -pub(crate) fn lower_condcode(cc: IntCC) -> Cond { - match cc { - IntCC::Equal => Cond::Eq, - IntCC::NotEqual => Cond::Ne, - IntCC::SignedGreaterThanOrEqual => Cond::Ge, - IntCC::SignedGreaterThan => Cond::Gt, - IntCC::SignedLessThanOrEqual => Cond::Le, - IntCC::SignedLessThan => Cond::Lt, - IntCC::UnsignedGreaterThanOrEqual => Cond::Hs, - IntCC::UnsignedGreaterThan => Cond::Hi, - IntCC::UnsignedLessThanOrEqual => Cond::Ls, - IntCC::UnsignedLessThan => Cond::Lo, - IntCC::Overflow => Cond::Vs, - IntCC::NotOverflow => Cond::Vc, - } -} - -/// Determines whether this condcode interprets inputs as signed or unsigned. -pub(crate) fn condcode_is_signed(cc: IntCC) -> bool { - match cc { - IntCC::Equal => false, - IntCC::NotEqual => false, - IntCC::SignedGreaterThanOrEqual => true, - IntCC::SignedGreaterThan => true, - IntCC::SignedLessThanOrEqual => true, - IntCC::SignedLessThan => true, - IntCC::UnsignedGreaterThanOrEqual => false, - IntCC::UnsignedGreaterThan => false, - IntCC::UnsignedLessThanOrEqual => false, - IntCC::UnsignedLessThan => false, - IntCC::Overflow => true, - IntCC::NotOverflow => true, - } -} - -//============================================================================= -// Helpers for instruction lowering. - -pub(crate) fn ldst_offset(data: &InstructionData) -> Option { - match data { - &InstructionData::Load { offset, .. } - | &InstructionData::StackLoad { offset, .. } - | &InstructionData::LoadComplex { offset, .. } - | &InstructionData::Store { offset, .. } - | &InstructionData::StackStore { offset, .. } - | &InstructionData::StoreComplex { offset, .. } => Some(offset.into()), - _ => None, - } -} - -pub(crate) fn inst_condcode(data: &InstructionData) -> Option { - match data { - &InstructionData::IntCond { cond, .. } - | &InstructionData::BranchIcmp { cond, .. } - | &InstructionData::IntCompare { cond, .. } - | &InstructionData::IntCondTrap { cond, .. } - | &InstructionData::BranchInt { cond, .. } - | &InstructionData::IntSelect { cond, .. } - | &InstructionData::IntCompareImm { cond, .. } => Some(cond), - _ => None, - } -} - -pub(crate) fn inst_trapcode(data: &InstructionData) -> Option { - match data { - &InstructionData::Trap { code, .. } - | &InstructionData::CondTrap { code, .. } - | &InstructionData::IntCondTrap { code, .. } => Some(code), - &InstructionData::FloatCondTrap { code, .. } => { - panic!("Unexpected float cond trap {:?}", code) - } - _ => None, - } -} - -//============================================================================= -// Lowering-backend trait implementation. - -impl LowerBackend for Arm32Backend { - type MInst = Inst; - - fn lower>(&self, ctx: &mut C, ir_inst: IRInst) -> CodegenResult<()> { - lower_inst::lower_insn_to_regs(ctx, ir_inst, &self.flags) - } - - fn lower_branch_group>( - &self, - ctx: &mut C, - branches: &[IRInst], - targets: &[MachLabel], - ) -> CodegenResult<()> { - lower_inst::lower_branch(ctx, branches, targets) - } - - fn maybe_pinned_reg(&self) -> Option { - None - } -} diff --git a/cranelift/codegen/src/isa/arm32/lower_inst.rs b/cranelift/codegen/src/isa/arm32/lower_inst.rs deleted file mode 100644 index 32937991b96b..000000000000 --- a/cranelift/codegen/src/isa/arm32/lower_inst.rs +++ /dev/null @@ -1,599 +0,0 @@ -//! Lower a single Cranelift instruction into vcode. - -use crate::ir::types::*; -use crate::ir::Inst as IRInst; -use crate::ir::Opcode; -use crate::machinst::lower::*; -use crate::machinst::*; -use crate::settings::Flags; -use crate::CodegenResult; - -use crate::isa::arm32::abi::*; -use crate::isa::arm32::inst::*; - -use smallvec::SmallVec; - -use super::lower::*; - -/// Actually codegen an instruction's results into registers. -pub(crate) fn lower_insn_to_regs>( - ctx: &mut C, - insn: IRInst, - flags: &Flags, -) -> CodegenResult<()> { - let op = ctx.data(insn).opcode(); - let inputs: SmallVec<[InsnInput; 4]> = (0..ctx.num_inputs(insn)) - .map(|i| InsnInput { insn, input: i }) - .collect(); - let outputs: SmallVec<[InsnOutput; 2]> = (0..ctx.num_outputs(insn)) - .map(|i| InsnOutput { insn, output: i }) - .collect(); - let ty = if outputs.len() > 0 { - let ty = ctx.output_ty(insn, 0); - if ty.bits() > 32 || ty.is_float() { - panic!("Cannot lower inst with type {}!", ty); - } - Some(ty) - } else { - None - }; - - match op { - Opcode::Iconst | Opcode::Bconst | Opcode::Null => { - let value = output_to_const(ctx, outputs[0]).unwrap(); - let rd = output_to_reg(ctx, outputs[0]); - lower_constant(ctx, rd, value); - } - Opcode::Iadd - | Opcode::IaddIfcin - | Opcode::IaddIfcout - | Opcode::IaddIfcarry - | Opcode::Isub - | Opcode::IsubIfbin - | Opcode::IsubIfbout - | Opcode::IsubIfborrow - | Opcode::Band - | Opcode::Bor - | Opcode::Bxor - | Opcode::BandNot - | Opcode::BorNot => { - let rd = output_to_reg(ctx, outputs[0]); - let rn = input_to_reg(ctx, inputs[0], NarrowValueMode::None); - let rm = input_to_reg(ctx, inputs[1], NarrowValueMode::None); - - let alu_op = match op { - Opcode::Iadd => ALUOp::Add, - Opcode::IaddIfcin => ALUOp::Adc, - Opcode::IaddIfcout => ALUOp::Adds, - Opcode::IaddIfcarry => ALUOp::Adcs, - Opcode::Isub => ALUOp::Sub, - Opcode::IsubIfbin => ALUOp::Sbc, - Opcode::IsubIfbout => ALUOp::Subs, - Opcode::IsubIfborrow => ALUOp::Sbcs, - Opcode::Band => ALUOp::And, - Opcode::Bor => ALUOp::Orr, - Opcode::Bxor => ALUOp::Eor, - Opcode::BandNot => ALUOp::Bic, - Opcode::BorNot => ALUOp::Orn, - _ => unreachable!(), - }; - ctx.emit(Inst::AluRRRShift { - alu_op, - rd, - rn, - rm, - shift: None, - }); - } - Opcode::Imul | Opcode::Udiv | Opcode::Sdiv => { - let rd = output_to_reg(ctx, outputs[0]); - let rn = input_to_reg(ctx, inputs[0], NarrowValueMode::None); - let rm = input_to_reg(ctx, inputs[1], NarrowValueMode::None); - - let alu_op = match op { - Opcode::Imul => ALUOp::Mul, - Opcode::Udiv => ALUOp::Udiv, - Opcode::Sdiv => ALUOp::Sdiv, - _ => unreachable!(), - }; - ctx.emit(Inst::AluRRR { alu_op, rd, rn, rm }); - } - Opcode::Ineg => { - let rd = output_to_reg(ctx, outputs[0]); - let rn = input_to_reg(ctx, inputs[0], NarrowValueMode::None); - - ctx.emit(Inst::AluRRImm8 { - alu_op: ALUOp::Rsb, - rd, - rn, - imm8: UImm8::maybe_from_i64(0).unwrap(), - }); - } - Opcode::Ishl | Opcode::Ushr | Opcode::Sshr => { - let (alu_op, ext) = match op { - Opcode::Ishl => (ALUOp::Lsl, NarrowValueMode::None), - Opcode::Ushr => (ALUOp::Lsr, NarrowValueMode::ZeroExtend), - Opcode::Sshr => (ALUOp::Asr, NarrowValueMode::SignExtend), - _ => unreachable!(), - }; - let rd = output_to_reg(ctx, outputs[0]); - let rn = input_to_reg(ctx, inputs[0], ext); - let rm = input_to_reg(ctx, inputs[1], NarrowValueMode::ZeroExtend); - ctx.emit(Inst::AluRRR { alu_op, rd, rn, rm }); - } - Opcode::Rotr => { - if ty.unwrap().bits() != 32 { - unimplemented!() - } - let rd = output_to_reg(ctx, outputs[0]); - let rn = input_to_reg(ctx, inputs[0], NarrowValueMode::None); - let rm = input_to_reg(ctx, inputs[1], NarrowValueMode::None); - ctx.emit(Inst::AluRRR { - alu_op: ALUOp::Ror, - rd, - rn, - rm, - }); - } - Opcode::Rotl => { - if ty.unwrap().bits() != 32 { - unimplemented!() - } - let rd = output_to_reg(ctx, outputs[0]); - let rn = input_to_reg(ctx, inputs[0], NarrowValueMode::None); - let rm = input_to_reg(ctx, inputs[1], NarrowValueMode::None); - let tmp = ctx.alloc_tmp(I32).only_reg().unwrap(); - - // ror rd, rn, 32 - (rm & 31) - ctx.emit(Inst::AluRRImm8 { - alu_op: ALUOp::And, - rd: tmp, - rn: rm, - imm8: UImm8::maybe_from_i64(31).unwrap(), - }); - ctx.emit(Inst::AluRRImm8 { - alu_op: ALUOp::Rsb, - rd: tmp, - rn: tmp.to_reg(), - imm8: UImm8::maybe_from_i64(32).unwrap(), - }); - ctx.emit(Inst::AluRRR { - alu_op: ALUOp::Ror, - rd, - rn, - rm: tmp.to_reg(), - }); - } - Opcode::Smulhi | Opcode::Umulhi => { - let ty = ty.unwrap(); - let is_signed = op == Opcode::Smulhi; - match ty { - I32 => { - let rd_hi = output_to_reg(ctx, outputs[0]); - let rd_lo = ctx.alloc_tmp(ty).only_reg().unwrap(); - let rn = input_to_reg(ctx, inputs[0], NarrowValueMode::None); - let rm = input_to_reg(ctx, inputs[1], NarrowValueMode::None); - - let alu_op = if is_signed { - ALUOp::Smull - } else { - ALUOp::Umull - }; - ctx.emit(Inst::AluRRRR { - alu_op, - rd_hi, - rd_lo, - rn, - rm, - }); - } - I16 | I8 => { - let narrow_mode = if is_signed { - NarrowValueMode::SignExtend - } else { - NarrowValueMode::ZeroExtend - }; - let rd = output_to_reg(ctx, outputs[0]); - let rn = input_to_reg(ctx, inputs[0], narrow_mode); - let rm = input_to_reg(ctx, inputs[1], narrow_mode); - - ctx.emit(Inst::AluRRR { - alu_op: ALUOp::Mul, - rd, - rn, - rm, - }); - let shift_amt = if ty == I16 { 16 } else { 8 }; - let imm8 = UImm8::maybe_from_i64(shift_amt).unwrap(); - let alu_op = if is_signed { ALUOp::Asr } else { ALUOp::Lsr }; - - ctx.emit(Inst::AluRRImm8 { - alu_op, - rd, - rn: rd.to_reg(), - imm8, - }); - } - _ => panic!("Unexpected type {} in lower {}!", ty, op), - } - } - Opcode::Bnot => { - let rd = output_to_reg(ctx, outputs[0]); - let rm = input_to_reg(ctx, inputs[0], NarrowValueMode::None); - - ctx.emit(Inst::AluRRShift { - alu_op: ALUOp1::Mvn, - rd, - rm, - shift: None, - }); - } - Opcode::Clz | Opcode::Ctz => { - let rd = output_to_reg(ctx, outputs[0]); - let rm = input_to_reg(ctx, inputs[0], NarrowValueMode::ZeroExtend); - let ty = ctx.output_ty(insn, 0); - - let in_reg = if op == Opcode::Ctz { - ctx.emit(Inst::BitOpRR { - bit_op: BitOp::Rbit, - rd, - rm, - }); - rd.to_reg() - } else { - rm - }; - ctx.emit(Inst::BitOpRR { - bit_op: BitOp::Clz, - rd, - rm: in_reg, - }); - - if ty.bits() < 32 { - let imm12 = UImm12::maybe_from_i64(32 - ty.bits() as i64).unwrap(); - ctx.emit(Inst::AluRRImm12 { - alu_op: ALUOp::Sub, - rd, - rn: rd.to_reg(), - imm12, - }); - } - } - Opcode::Bitrev => { - let rd = output_to_reg(ctx, outputs[0]); - let rm = input_to_reg(ctx, inputs[0], NarrowValueMode::None); - let ty = ctx.output_ty(insn, 0); - let bit_op = BitOp::Rbit; - - match ty.bits() { - 32 => ctx.emit(Inst::BitOpRR { bit_op, rd, rm }), - n if n < 32 => { - let shift = ShiftOpAndAmt::new( - ShiftOp::LSL, - ShiftOpShiftImm::maybe_from_shift(32 - n as u32).unwrap(), - ); - ctx.emit(Inst::AluRRShift { - alu_op: ALUOp1::Mov, - rd, - rm, - shift: Some(shift), - }); - ctx.emit(Inst::BitOpRR { - bit_op, - rd, - rm: rd.to_reg(), - }); - } - _ => panic!("Unexpected output type {}", ty), - } - } - Opcode::Icmp | Opcode::Ifcmp => { - let condcode = inst_condcode(ctx.data(insn)).unwrap(); - let cond = lower_condcode(condcode); - let is_signed = condcode_is_signed(condcode); - - let narrow_mode = if is_signed { - NarrowValueMode::SignExtend - } else { - NarrowValueMode::ZeroExtend - }; - let rd = output_to_reg(ctx, outputs[0]); - let rn = input_to_reg(ctx, inputs[0], narrow_mode); - let rm = input_to_reg(ctx, inputs[1], narrow_mode); - - ctx.emit(Inst::Cmp { rn, rm }); - - if op == Opcode::Icmp { - let mut it_insts = vec![]; - it_insts.push(CondInst::new(Inst::MovImm16 { rd, imm16: 1 }, true)); - it_insts.push(CondInst::new(Inst::MovImm16 { rd, imm16: 0 }, false)); - ctx.emit(Inst::It { - cond, - insts: it_insts, - }); - } - } - Opcode::Trueif => { - let cmp_insn = ctx - .get_input_as_source_or_const(inputs[0].insn, inputs[0].input) - .inst - .unwrap() - .0; - debug_assert_eq!(ctx.data(cmp_insn).opcode(), Opcode::Ifcmp); - emit_cmp(ctx, cmp_insn); - - let condcode = inst_condcode(ctx.data(insn)).unwrap(); - let cond = lower_condcode(condcode); - let rd = output_to_reg(ctx, outputs[0]); - - let mut it_insts = vec![]; - it_insts.push(CondInst::new(Inst::MovImm16 { rd, imm16: 1 }, true)); - it_insts.push(CondInst::new(Inst::MovImm16 { rd, imm16: 0 }, false)); - - ctx.emit(Inst::It { - cond, - insts: it_insts, - }); - } - Opcode::Select | Opcode::Selectif => { - let cond = if op == Opcode::Select { - let rn = input_to_reg(ctx, inputs[0], NarrowValueMode::ZeroExtend); - ctx.emit(Inst::CmpImm8 { rn, imm8: 0 }); - Cond::Ne - } else { - // Verification ensures that the input is always a single-def ifcmp. - let cmp_insn = ctx - .get_input_as_source_or_const(inputs[0].insn, inputs[0].input) - .inst - .unwrap() - .0; - debug_assert_eq!(ctx.data(cmp_insn).opcode(), Opcode::Ifcmp); - emit_cmp(ctx, cmp_insn); - - let condcode = inst_condcode(ctx.data(insn)).unwrap(); - lower_condcode(condcode) - }; - let r1 = input_to_reg(ctx, inputs[1], NarrowValueMode::None); - let r2 = input_to_reg(ctx, inputs[2], NarrowValueMode::None); - let out_reg = output_to_reg(ctx, outputs[0]); - - let mut it_insts = vec![]; - it_insts.push(CondInst::new(Inst::mov(out_reg, r1), true)); - it_insts.push(CondInst::new(Inst::mov(out_reg, r2), false)); - - ctx.emit(Inst::It { - cond, - insts: it_insts, - }); - } - Opcode::Store | Opcode::Istore8 | Opcode::Istore16 | Opcode::Istore32 => { - let off = ldst_offset(ctx.data(insn)).unwrap(); - let elem_ty = match op { - Opcode::Istore8 => I8, - Opcode::Istore16 => I16, - Opcode::Istore32 => I32, - Opcode::Store => ctx.input_ty(insn, 0), - _ => unreachable!(), - }; - if elem_ty.bits() > 32 { - unimplemented!() - } - let bits = elem_ty.bits() as u8; - - assert_eq!(inputs.len(), 2, "only one input for store memory operands"); - let rt = input_to_reg(ctx, inputs[0], NarrowValueMode::None); - let base = input_to_reg(ctx, inputs[1], NarrowValueMode::None); - - let mem = AMode::RegOffset(base, i64::from(off)); - - ctx.emit(Inst::Store { rt, mem, bits }); - } - Opcode::Load - | Opcode::Uload8 - | Opcode::Sload8 - | Opcode::Uload16 - | Opcode::Sload16 - | Opcode::Uload32 - | Opcode::Sload32 => { - let off = ldst_offset(ctx.data(insn)).unwrap(); - let elem_ty = match op { - Opcode::Sload8 | Opcode::Uload8 => I8, - Opcode::Sload16 | Opcode::Uload16 => I16, - Opcode::Sload32 | Opcode::Uload32 => I32, - Opcode::Load => ctx.output_ty(insn, 0), - _ => unreachable!(), - }; - if elem_ty.bits() > 32 { - unimplemented!() - } - let bits = elem_ty.bits() as u8; - - let sign_extend = match op { - Opcode::Sload8 | Opcode::Sload16 | Opcode::Sload32 => true, - _ => false, - }; - let out_reg = output_to_reg(ctx, outputs[0]); - - assert_eq!(inputs.len(), 2, "only one input for store memory operands"); - let base = input_to_reg(ctx, inputs[1], NarrowValueMode::None); - let mem = AMode::RegOffset(base, i64::from(off)); - - ctx.emit(Inst::Load { - rt: out_reg, - mem, - bits, - sign_extend, - }); - } - Opcode::Uextend | Opcode::Sextend => { - let output_ty = ty.unwrap(); - let input_ty = ctx.input_ty(insn, 0); - let from_bits = input_ty.bits() as u8; - let to_bits = 32; - let signed = op == Opcode::Sextend; - - let rm = input_to_reg(ctx, inputs[0], NarrowValueMode::None); - let rd = output_to_reg(ctx, outputs[0]); - - if output_ty.bits() > 32 { - panic!("Unexpected output type {}", output_ty); - } - if from_bits < to_bits { - ctx.emit(Inst::Extend { - rd, - rm, - from_bits, - signed, - }); - } - } - Opcode::Bint | Opcode::Breduce | Opcode::Bextend | Opcode::Ireduce => { - let rn = input_to_reg(ctx, inputs[0], NarrowValueMode::ZeroExtend); - let rd = output_to_reg(ctx, outputs[0]); - let ty = ctx.input_ty(insn, 0); - - ctx.emit(Inst::gen_move(rd, rn, ty)); - } - Opcode::Copy => { - let rd = output_to_reg(ctx, outputs[0]); - let rn = input_to_reg(ctx, inputs[0], NarrowValueMode::None); - let ty = ctx.input_ty(insn, 0); - - ctx.emit(Inst::gen_move(rd, rn, ty)); - } - Opcode::Debugtrap => { - ctx.emit(Inst::Bkpt); - } - Opcode::Trap => { - let trap_info = inst_trapcode(ctx.data(insn)).unwrap(); - ctx.emit(Inst::Udf { trap_info }) - } - Opcode::Trapif => { - let cmp_insn = ctx - .get_input_as_source_or_const(inputs[0].insn, inputs[0].input) - .inst - .unwrap() - .0; - debug_assert_eq!(ctx.data(cmp_insn).opcode(), Opcode::Ifcmp); - emit_cmp(ctx, cmp_insn); - - let trap_info = inst_trapcode(ctx.data(insn)).unwrap(); - let condcode = inst_condcode(ctx.data(insn)).unwrap(); - let cond = lower_condcode(condcode); - - ctx.emit(Inst::TrapIf { cond, trap_info }); - } - Opcode::FallthroughReturn | Opcode::Return => { - for (i, input) in inputs.iter().enumerate() { - let reg = input_to_reg(ctx, *input, NarrowValueMode::None); - let retval_reg = ctx.retval(i).only_reg().unwrap(); - let ty = ctx.input_ty(insn, i); - - ctx.emit(Inst::gen_move(retval_reg, reg, ty)); - } - } - Opcode::Call | Opcode::CallIndirect => { - let caller_conv = ctx.abi().call_conv(); - let (mut abi, inputs) = match op { - Opcode::Call => { - let (extname, dist) = ctx.call_target(insn).unwrap(); - let extname = extname.clone(); - let sig = ctx.call_sig(insn).unwrap(); - assert_eq!(inputs.len(), sig.params.len()); - assert_eq!(outputs.len(), sig.returns.len()); - ( - Arm32ABICaller::from_func(sig, &extname, dist, caller_conv, flags)?, - &inputs[..], - ) - } - Opcode::CallIndirect => { - let ptr = input_to_reg(ctx, inputs[0], NarrowValueMode::ZeroExtend); - let sig = ctx.call_sig(insn).unwrap(); - assert_eq!(inputs.len() - 1, sig.params.len()); - assert_eq!(outputs.len(), sig.returns.len()); - ( - Arm32ABICaller::from_ptr(sig, ptr, op, caller_conv, flags)?, - &inputs[1..], - ) - } - _ => unreachable!(), - }; - assert_eq!(inputs.len(), abi.num_args()); - for (i, input) in inputs.iter().enumerate().filter(|(i, _)| *i <= 3) { - let arg_reg = input_to_reg(ctx, *input, NarrowValueMode::None); - abi.emit_copy_regs_to_arg(ctx, i, ValueRegs::one(arg_reg)); - } - abi.emit_call(ctx); - for (i, output) in outputs.iter().enumerate() { - let retval_reg = output_to_reg(ctx, *output); - abi.emit_copy_retval_to_regs(ctx, i, ValueRegs::one(retval_reg)); - } - } - _ => panic!("lowering {} unimplemented!", op), - } - - Ok(()) -} - -pub(crate) fn lower_branch>( - ctx: &mut C, - branches: &[IRInst], - targets: &[MachLabel], -) -> CodegenResult<()> { - // A block should end with at most two branches. The first may be a - // conditional branch; a conditional branch can be followed only by an - // unconditional branch. Otherwise, if only one branch, it may be an - // unconditional branch, a return, or a trap. These conditions are verified - // by `is_ebb_basic()` during the verifier pass. - assert!(branches.len() <= 2); - - if branches.len() == 2 { - // Must be a conditional branch followed by an unconditional branch. - let op0 = ctx.data(branches[0]).opcode(); - let op1 = ctx.data(branches[1]).opcode(); - - assert!(op1 == Opcode::Jump); - let taken = BranchTarget::Label(targets[0]); - let not_taken = BranchTarget::Label(targets[1]); - - match op0 { - Opcode::Brz | Opcode::Brnz => { - let rn = input_to_reg( - ctx, - InsnInput { - insn: branches[0], - input: 0, - }, - NarrowValueMode::ZeroExtend, - ); - let cond = if op0 == Opcode::Brz { - Cond::Eq - } else { - Cond::Ne - }; - - ctx.emit(Inst::CmpImm8 { rn, imm8: 0 }); - ctx.emit(Inst::CondBr { - taken, - not_taken, - cond, - }); - } - _ => unimplemented!(), - } - } else { - // Must be an unconditional branch or an indirect branch. - let op = ctx.data(branches[0]).opcode(); - match op { - Opcode::Jump => { - assert_eq!(branches.len(), 1); - ctx.emit(Inst::Jump { - dest: BranchTarget::Label(targets[0]), - }); - } - _ => unimplemented!(), - } - } - - Ok(()) -} diff --git a/cranelift/codegen/src/isa/arm32/mod.rs b/cranelift/codegen/src/isa/arm32/mod.rs deleted file mode 100644 index f66809bfc966..000000000000 --- a/cranelift/codegen/src/isa/arm32/mod.rs +++ /dev/null @@ -1,148 +0,0 @@ -//! 32-bit ARM Instruction Set Architecture. - -use crate::ir::condcodes::IntCC; -use crate::ir::Function; -use crate::isa::{Builder as IsaBuilder, TargetIsa}; -use crate::machinst::{ - compile, MachCompileResult, MachTextSectionBuilder, TextSectionBuilder, VCode, -}; -use crate::result::CodegenResult; -use crate::settings; - -use alloc::{boxed::Box, vec::Vec}; -use core::fmt; -use regalloc::{PrettyPrint, RealRegUniverse}; -use target_lexicon::{Architecture, ArmArchitecture, Triple}; - -// New backend: -mod abi; -mod inst; -mod lower; -mod lower_inst; - -use inst::{create_reg_universe, EmitInfo}; - -/// An ARM32 backend. -pub struct Arm32Backend { - triple: Triple, - flags: settings::Flags, - reg_universe: RealRegUniverse, -} - -impl Arm32Backend { - /// Create a new ARM32 backend with the given (shared) flags. - pub fn new_with_flags(triple: Triple, flags: settings::Flags) -> Arm32Backend { - let reg_universe = create_reg_universe(); - Arm32Backend { - triple, - flags, - reg_universe, - } - } - - fn compile_vcode( - &self, - func: &Function, - flags: settings::Flags, - ) -> CodegenResult> { - // This performs lowering to VCode, register-allocates the code, computes - // block layout and finalizes branches. The result is ready for binary emission. - let emit_info = EmitInfo::new(flags.clone()); - let abi = Box::new(abi::Arm32ABICallee::new(func, flags, self.isa_flags())?); - compile::compile::(func, self, abi, &self.reg_universe, emit_info) - } -} - -impl TargetIsa for Arm32Backend { - fn compile_function( - &self, - func: &Function, - want_disasm: bool, - ) -> CodegenResult { - let flags = self.flags(); - let vcode = self.compile_vcode(func, flags.clone())?; - let (buffer, bb_starts, bb_edges) = vcode.emit(); - let frame_size = vcode.frame_size(); - let stackslot_offsets = vcode.stackslot_offsets().clone(); - - let disasm = if want_disasm { - Some(vcode.show_rru(Some(&create_reg_universe()))) - } else { - None - }; - - let buffer = buffer.finish(); - - Ok(MachCompileResult { - buffer, - frame_size, - disasm, - value_labels_ranges: Default::default(), - stackslot_offsets, - bb_starts, - bb_edges, - }) - } - - fn name(&self) -> &'static str { - "arm32" - } - - fn triple(&self) -> &Triple { - &self.triple - } - - fn flags(&self) -> &settings::Flags { - &self.flags - } - - fn isa_flags(&self) -> Vec { - Vec::new() - } - - #[cfg(feature = "unwind")] - fn emit_unwind_info( - &self, - _result: &MachCompileResult, - _kind: crate::machinst::UnwindInfoKind, - ) -> CodegenResult> { - Ok(None) // FIXME implement this - } - - fn unsigned_add_overflow_condition(&self) -> IntCC { - // Carry flag set. - IntCC::UnsignedGreaterThanOrEqual - } - - fn text_section_builder(&self, num_funcs: u32) -> Box { - Box::new(MachTextSectionBuilder::::new(num_funcs)) - } -} - -impl fmt::Display for Arm32Backend { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("MachBackend") - .field("name", &self.name()) - .field("triple", &self.triple()) - .field("flags", &format!("{}", self.flags())) - .finish() - } -} - -/// Create a new `isa::Builder`. -pub fn isa_builder(triple: Triple) -> IsaBuilder { - assert!(match triple.architecture { - Architecture::Arm(ArmArchitecture::Arm) - | Architecture::Arm(ArmArchitecture::Armv7) - | Architecture::Arm(ArmArchitecture::Armv6) => true, - _ => false, - }); - IsaBuilder { - triple, - setup: settings::builder(), - constructor: |triple, shared_flags, _| { - let backend = Arm32Backend::new_with_flags(triple, shared_flags); - Box::new(backend) - }, - } -} diff --git a/cranelift/codegen/src/isa/mod.rs b/cranelift/codegen/src/isa/mod.rs index f50cb83f9d2a..8b69315f2478 100644 --- a/cranelift/codegen/src/isa/mod.rs +++ b/cranelift/codegen/src/isa/mod.rs @@ -63,9 +63,6 @@ use target_lexicon::{triple, Architecture, OperatingSystem, PointerWidth, Triple #[cfg(feature = "x86")] pub mod x64; -#[cfg(feature = "arm32")] -mod arm32; - #[cfg(feature = "arm64")] pub(crate) mod aarch64; @@ -98,7 +95,6 @@ pub fn lookup(triple: Triple) -> Result { Architecture::X86_64 => { isa_builder!(x64, (feature = "x86"), triple) } - Architecture::Arm { .. } => isa_builder!(arm32, (feature = "arm32"), triple), Architecture::Aarch64 { .. } => isa_builder!(aarch64, (feature = "arm64"), triple), Architecture::S390x { .. } => isa_builder!(s390x, (feature = "s390x"), triple), _ => Err(LookupError::Unsupported), diff --git a/cranelift/codegen/src/machinst/lower.rs b/cranelift/codegen/src/machinst/lower.rs index c394acb202a3..cd28dfea0dfc 100644 --- a/cranelift/codegen/src/machinst/lower.rs +++ b/cranelift/codegen/src/machinst/lower.rs @@ -333,14 +333,10 @@ fn alloc_vregs( let regs = match regclasses { &[rc0] => ValueRegs::one(Reg::new_virtual(rc0, v)), &[rc0, rc1] => ValueRegs::two(Reg::new_virtual(rc0, v), Reg::new_virtual(rc1, v + 1)), - #[cfg(feature = "arm32")] - &[rc0, rc1, rc2, rc3] => ValueRegs::four( - Reg::new_virtual(rc0, v), - Reg::new_virtual(rc1, v + 1), - Reg::new_virtual(rc2, v + 2), - Reg::new_virtual(rc3, v + 3), - ), - _ => panic!("Value must reside in 1, 2 or 4 registers"), + // We can extend this if/when we support 32-bit targets; e.g., + // an i128 on a 32-bit machine will need up to four machine regs + // for a `Value`. + _ => panic!("Value must reside in 1 or 2 registers"), }; for (®_ty, ®) in tys.iter().zip(regs.regs().iter()) { vcode.set_vreg_type(reg.to_virtual_reg(), reg_ty); diff --git a/cranelift/codegen/src/machinst/valueregs.rs b/cranelift/codegen/src/machinst/valueregs.rs index 8ffcc73ab384..df18202ccce8 100644 --- a/cranelift/codegen/src/machinst/valueregs.rs +++ b/cranelift/codegen/src/machinst/valueregs.rs @@ -4,10 +4,6 @@ use regalloc::{RealReg, Reg, VirtualReg, Writable}; use std::fmt::Debug; -#[cfg(feature = "arm32")] -const VALUE_REGS_PARTS: usize = 4; - -#[cfg(not(feature = "arm32"))] const VALUE_REGS_PARTS: usize = 2; /// Location at which a `Value` is stored in register(s): the value is located @@ -90,59 +86,6 @@ impl ValueRegs { } } -#[cfg(feature = "arm32")] -impl ValueRegs { - /// Create a Value-in-R location for a value stored in one register. - pub fn one(reg: R) -> Self { - ValueRegs { - parts: [ - reg, - R::invalid_sentinel(), - R::invalid_sentinel(), - R::invalid_sentinel(), - ], - } - } - /// Create a Value-in-R location for a value stored in two registers. - pub fn two(r1: R, r2: R) -> Self { - ValueRegs { - parts: [r1, r2, R::invalid_sentinel(), R::invalid_sentinel()], - } - } - /// Create a Value-in-R location for a value stored in four registers. - pub fn four(r1: R, r2: R, r3: R, r4: R) -> Self { - ValueRegs { - parts: [r1, r2, r3, r4], - } - } - - /// Return the number of registers used. - pub fn len(self) -> usize { - // If rustc/LLVM is smart enough, this might even be vectorized... - (self.parts[0] != R::invalid_sentinel()) as usize - + (self.parts[1] != R::invalid_sentinel()) as usize - + (self.parts[2] != R::invalid_sentinel()) as usize - + (self.parts[3] != R::invalid_sentinel()) as usize - } - - /// Map individual registers via a map function. - pub fn map(self, f: F) -> ValueRegs - where - NewR: Clone + Copy + Debug + PartialEq + Eq + InvalidSentinel, - F: Fn(R) -> NewR, - { - ValueRegs { - parts: [ - f(self.parts[0]), - f(self.parts[1]), - f(self.parts[2]), - f(self.parts[3]), - ], - } - } -} - -#[cfg(not(feature = "arm32"))] impl ValueRegs { /// Create a Value-in-R location for a value stored in one register. pub fn one(reg: R) -> Self { diff --git a/cranelift/filetests/Cargo.toml b/cranelift/filetests/Cargo.toml index e71052cb3578..72e5375cedf4 100644 --- a/cranelift/filetests/Cargo.toml +++ b/cranelift/filetests/Cargo.toml @@ -25,6 +25,3 @@ num_cpus = "1.8.0" target-lexicon = "0.12" thiserror = "1.0.15" anyhow = "1.0.32" - -[features] -experimental_arm32 = [] diff --git a/cranelift/filetests/filetests/isa/arm32/aluops.clif b/cranelift/filetests/filetests/isa/arm32/aluops.clif deleted file mode 100644 index af11be481778..000000000000 --- a/cranelift/filetests/filetests/isa/arm32/aluops.clif +++ /dev/null @@ -1,244 +0,0 @@ -test compile -target arm -feature "experimental_arm32" - -function %iadd(i8, i8) -> i8 { -block0(v0: i8, v1: i8): - v2 = iadd v0, v1 - return v2 -} -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: add r0, r0, r1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %iadd(i16, i16) -> i16 { -block0(v0: i16, v1: i16): - v2 = iadd v0, v1 - return v2 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: add r0, r0, r1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %iadd(i32, i32) -> i32 { -block0(v0: i32, v1: i32): - v2 = iadd v0, v1 - return v2 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: add r0, r0, r1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %isub(i32, i32) -> i32 { -block0(v0: i32, v1: i32): - v2 = isub v0, v1 - return v2 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: sub r0, r0, r1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %ineg(i32) -> i32 { -block0(v0: i32): - v1 = ineg v0 - return v1 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: rsb r0, r0, #0 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %imul(i32, i32) -> i32 { -block0(v0: i32, v1: i32): - v2 = imul v0, v1 - return v2 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: mul r0, r0, r1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %umulhi(i32, i32) -> i32 { -block0(v0: i32, v1: i32): - v2 = umulhi v0, v1 - return v2 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: umull r1, r0, r0, r1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %smulhi(i32, i32) -> i32 { -block0(v0: i32, v1: i32): - v2 = smulhi v0, v1 - return v2 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: smull r1, r0, r0, r1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %udiv(i32, i32) -> i32 { -block0(v0: i32, v1: i32): - v2 = udiv v0, v1 - return v2 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: udiv r0, r0, r1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %sdiv(i32, i32) -> i32 { -block0(v0: i32, v1: i32): - v2 = sdiv v0, v1 - return v2 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: sdiv r0, r0, r1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %iadd_flags(i32, i32) -> i32 { -block0(v0: i32, v1: i32): - v2, v3 = iadd_ifcout v0, v1 - v4, v5 = iadd_ifcarry v1, v2, v3 - v6 = iadd_ifcin v1, v4, v5 - return v6 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: adds r0, r0, r1 -; nextln: adcs r0, r1, r0 -; nextln: adc r0, r1, r0 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %isub_flags(i32, i32) -> i32 { -block0(v0: i32, v1: i32): - v2, v3 = isub_ifbout v0, v1 - v4, v5 = isub_ifborrow v1, v2, v3 - v6 = isub_ifbin v1, v4, v5 - return v6 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: subs r0, r0, r1 -; nextln: sbcs r0, r1, r0 -; nextln: sbc r0, r1, r0 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %band(i32, i32) -> i32 { -block0(v0: i32, v1: i32): - v2 = band v0, v1 - return v2 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: and r0, r0, r1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %bor(i32, i32) -> i32 { -block0(v0: i32, v1: i32): - v2 = bor v0, v1 - return v2 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: orr r0, r0, r1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %bxor(i32, i32) -> i32 { -block0(v0: i32, v1: i32): - v2 = bxor v0, v1 - return v2 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: eor r0, r0, r1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %bnot(i32) -> i32 { -block0(v0: i32): - v1 = bnot v0 - return v1 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: mvn r0, r0 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %band_not(i32, i32) -> i32 { -block0(v0: i32, v1: i32): - v2 = band_not v0, v1 - return v2 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: bic r0, r0, r1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %bor_not(i32, i32) -> i32 { -block0(v0: i32, v1: i32): - v2 = bor_not v0, v1 - return v2 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: orn r0, r0, r1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr diff --git a/cranelift/filetests/filetests/isa/arm32/bitops.clif b/cranelift/filetests/filetests/isa/arm32/bitops.clif deleted file mode 100644 index 77031faa686a..000000000000 --- a/cranelift/filetests/filetests/isa/arm32/bitops.clif +++ /dev/null @@ -1,133 +0,0 @@ -test compile -target arm -feature "experimental_arm32" - -function %bitrev_i8(i8) -> i8 { -block0(v0: i8): - v1 = bitrev v0 - return v1 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: mov r0, r0, lsl #24 -; nextln: rbit r0, r0 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %bitrev_i16(i16) -> i16 { -block0(v0: i16): - v1 = bitrev v0 - return v1 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: mov r0, r0, lsl #16 -; nextln: rbit r0, r0 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %bitrev_i32(i32) -> i32 { -block0(v0: i32): - v1 = bitrev v0 - return v1 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: rbit r0, r0 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %clz_i8(i8) -> i8 { -block0(v0: i8): - v1 = clz v0 - return v1 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: uxtb r0, r0 -; nextln: clz r0, r0 -; nextln: sub r0, r0, #24 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %clz_i16(i16) -> i16 { -block0(v0: i16): - v1 = clz v0 - return v1 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: uxth r0, r0 -; nextln: clz r0, r0 -; nextln: sub r0, r0, #16 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %clz_i32(i32) -> i32 { -block0(v0: i32): - v1 = clz v0 - return v1 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: clz r0, r0 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %ctz_i8(i8) -> i8 { -block0(v0: i8): - v1 = ctz v0 - return v1 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: uxtb r0, r0 -; nextln: rbit r0, r0 -; nextln: clz r0, r0 -; nextln: sub r0, r0, #24 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %ctz_i16(i16) -> i16 { -block0(v0: i16): - v1 = ctz v0 - return v1 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: uxth r0, r0 -; nextln: rbit r0, r0 -; nextln: clz r0, r0 -; nextln: sub r0, r0, #16 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %ctz_i32(i32) -> i32 { -block0(v0: i32): - v1 = ctz v0 - return v1 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: rbit r0, r0 -; nextln: clz r0, r0 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr diff --git a/cranelift/filetests/filetests/isa/arm32/cond.clif b/cranelift/filetests/filetests/isa/arm32/cond.clif deleted file mode 100644 index 4924c4e80d75..000000000000 --- a/cranelift/filetests/filetests/isa/arm32/cond.clif +++ /dev/null @@ -1,61 +0,0 @@ -test compile -target arm -feature "experimental_arm32" - -function %icmp(i32, i32) -> b1 { -block0(v0: i32, v1: i32): - v2 = icmp eq v0, v1 - return v2 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: cmp r0, r1 -; nextln: ite eq ; mov r0, #1 ; mov r0, #0 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %ifcmp_trueif(i32, i32) -> b1 { -block0(v0: i32, v1: i32): - v2 = ifcmp v0, v1 - v3 = trueif eq v2 - return v3 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: cmp r0, r1 -; nextln: ite eq ; mov r0, #1 ; mov r0, #0 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %select(i32, i32, i32) -> i32 { -block0(v0: i32, v1: i32, v2: i32): - v3 = select v0, v1, v2 - return v3 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: cmp r0, #0 -; nextln: ite ne ; mov r0, r1 ; mov r0, r2 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %selectif(i32, i32, i32, i32) -> i32 { -block0(v0: i32, v1: i32, v2: i32, v3: i32): - v4 = ifcmp v0, v1 - v5 = selectif.i32 eq v4, v2, v3 - return v5 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: cmp r0, r1 -; nextln: ite eq ; mov r0, r2 ; mov r0, r3 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr diff --git a/cranelift/filetests/filetests/isa/arm32/constants.clif b/cranelift/filetests/filetests/isa/arm32/constants.clif deleted file mode 100644 index 5da12b878284..000000000000 --- a/cranelift/filetests/filetests/isa/arm32/constants.clif +++ /dev/null @@ -1,108 +0,0 @@ -test compile -target arm -feature "experimental_arm32" - -function %b1() -> b1 { -block0: - v0 = bconst.b1 true - return v0 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: mov r0, #1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %b8() -> b8 { -block0: - v0 = bconst.b8 false - return v0 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: mov r0, #0 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %b16() -> b16 { -block0: - v0 = bconst.b16 true - return v0 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: mov r0, #1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %b32() -> b32 { -block0: - v0 = bconst.b32 false - return v0 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: mov r0, #0 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %i8() -> i8 { -block0: - v0 = iconst.i8 0xff - return v0 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: mov r0, #255 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %i8() -> i16 { -block0: - v0 = iconst.i16 0xffff - return v0 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: mov r0, #65535 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %f() -> i32 { -block0: - v0 = iconst.i32 0xffff - return v0 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: mov r0, #65535 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %f() -> i32 { -block0: - v0 = iconst.i32 0xffffffff - return v0 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: mov r0, #65535 -; nextln: movt r0, #65535 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr diff --git a/cranelift/filetests/filetests/isa/arm32/control-flow.clif b/cranelift/filetests/filetests/isa/arm32/control-flow.clif deleted file mode 100644 index 0148d6924343..000000000000 --- a/cranelift/filetests/filetests/isa/arm32/control-flow.clif +++ /dev/null @@ -1,132 +0,0 @@ -test compile -target arm -feature "experimental_arm32" - -function %brnz(b1) -> i32 { -block0(v0: b1): - brnz v0, block1 - jump block2 - -block1: - v1 = iconst.i32 1 - return v1 - -block2: - v2 = iconst.i32 2 - return v2 -} - -; check: Block 0: -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: and r0, r0, #1 -; nextln: cmp r0, #0 -; nextln: bne label1 ; b label2 -; check: Block 1: -; check: mov r0, #1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr -; check: Block 2: -; check: mov r0, #2 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %brz(b1) -> i32 { -block0(v0: b1): - brz v0, block1 - jump block2 - -block1: - v1 = iconst.i32 1 - return v1 - -block2: - v2 = iconst.i32 2 - return v2 -} - -; check: Block 0: -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: and r0, r0, #1 -; nextln: cmp r0, #0 -; nextln: beq label1 ; b label2 -; check: Block 1: -; check: mov r0, #1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr -; check: Block 2: -; check: mov r0, #2 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %trap() { -block0: - trap user0 -} - -; check: udf #0 - -function %trapif(i32, i32) { -block0(v0: i32, v1: i32): - v2 = ifcmp v0, v1 - trapif eq v2, user0 - return -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: cmp r0, r1 -; nextln: bne 2 ; udf #0 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %debugtrap() { -block0: - debugtrap - return -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: bkpt #0 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %call(i32) -> i32 { - fn0 = %f(i32) -> i32 -block0(v0: i32): - v1 = call fn0(v0) - return v1 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: ldr r1, [pc, #4] ; b 4 ; data -; nextln: blx r1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - - -function %call_indirect(i32, i32) -> i32 { - sig0 = (i32) -> i32 -block0(v0: i32, v1: i32): - v2 = call_indirect.i32 sig0, v1(v0) - return v2 -} - - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: blx r1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - diff --git a/cranelift/filetests/filetests/isa/arm32/extend.clif b/cranelift/filetests/filetests/isa/arm32/extend.clif deleted file mode 100644 index 3cc1733a0afd..000000000000 --- a/cranelift/filetests/filetests/isa/arm32/extend.clif +++ /dev/null @@ -1,81 +0,0 @@ -test compile -target arm -feature "experimental_arm32" - -function %uextend_i8_i32(i8) -> i32 { -block0(v0: i8): - v1 = uextend.i32 v0 - return v1 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: uxtb r0, r0 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %uextend_i8_i16(i8) -> i16 { -block0(v0: i8): - v1 = uextend.i16 v0 - return v1 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: uxtb r0, r0 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %uextend_i16_i32(i16) -> i32 { -block0(v0: i16): - v1 = uextend.i32 v0 - return v1 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: uxth r0, r0 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %sextend_i8_i32(i8) -> i32 { -block0(v0: i8): - v1 = sextend.i32 v0 - return v1 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: sxtb r0, r0 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %sextend_i8_i16(i8) -> i16 { -block0(v0: i8): - v1 = sextend.i16 v0 - return v1 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: sxtb r0, r0 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %sextend_i16_i32(i16) -> i32 { -block0(v0: i16): - v1 = sextend.i32 v0 - return v1 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: sxth r0, r0 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr diff --git a/cranelift/filetests/filetests/isa/arm32/params.clif b/cranelift/filetests/filetests/isa/arm32/params.clif deleted file mode 100644 index 1e4ee309118e..000000000000 --- a/cranelift/filetests/filetests/isa/arm32/params.clif +++ /dev/null @@ -1,48 +0,0 @@ -test compile -target arm -feature "experimental_arm32" - -function %args(i32) -> i32 { - sig0 = (i32, i32, i32, i32) -> i32 -block0(v0: i32): - v1 = iconst.i32 1 - v2 = iconst.i32 2 - v3 = iconst.i32 3 - v4 = iconst.i32 4 - v5 = call_indirect.i32 sig0, v0(v1, v2, v3, v4) - return v5 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: push {r4, ip} -; nextln: virtual_sp_offset_adjust 8 -; nextln: mov r4, r0 -; nextln: mov r0, #1 -; nextln: mov r1, #2 -; nextln: mov r2, #3 -; nextln: mov r3, #4 -; nextln: blx r4 -; nextln: pop {r4, ip} -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %multi_return() -> i32, i32, i32, i32 { -block0: - v0 = iconst.i32 1 - v1 = iconst.i32 2 - v2 = iconst.i32 3 - v3 = iconst.i32 4 - return v0, v1, v2, v3 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: mov r0, #1 -; nextln: mov r1, #2 -; nextln: mov r2, #3 -; nextln: mov r3, #4 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr diff --git a/cranelift/filetests/filetests/isa/arm32/shift-rotate.clif b/cranelift/filetests/filetests/isa/arm32/shift-rotate.clif deleted file mode 100644 index 67e4a11e57f0..000000000000 --- a/cranelift/filetests/filetests/isa/arm32/shift-rotate.clif +++ /dev/null @@ -1,158 +0,0 @@ -test compile -target arm -feature "experimental_arm32" - -function %ishl_i8(i8, i8) -> i8 { -block0(v0: i8, v1: i8): - v2 = ishl v0, v1 - return v2 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: uxtb r1, r1 -; nextln: lsl r0, r0, r1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %ishl_i16(i16, i16) -> i16 { -block0(v0: i16, v1: i16): - v2 = ishl v0, v1 - return v2 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: uxth r1, r1 -; nextln: lsl r0, r0, r1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %ishl_i32(i32, i32) -> i32 { -block0(v0: i32, v1: i32): - v2 = ishl v0, v1 - return v2 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: lsl r0, r0, r1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %ushr_i8(i8, i8) -> i8 { -block0(v0: i8, v1: i8): - v2 = ushr v0, v1 - return v2 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: uxtb r0, r0 -; nextln: uxtb r1, r1 -; nextln: lsr r0, r0, r1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %ushr_i16(i16, i16) -> i16 { -block0(v0: i16, v1: i16): - v2 = ushr v0, v1 - return v2 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: uxth r0, r0 -; nextln: uxth r1, r1 -; nextln: lsr r0, r0, r1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %ushr_i32(i32, i32) -> i32 { -block0(v0: i32, v1: i32): - v2 = ushr v0, v1 - return v2 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: lsr r0, r0, r1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %sshr_i8(i8, i8) -> i8 { -block0(v0: i8, v1: i8): - v2 = sshr v0, v1 - return v2 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: sxtb r0, r0 -; nextln: uxtb r1, r1 -; nextln: asr r0, r0, r1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %sshr_i16(i16, i16) -> i16 { -block0(v0: i16, v1: i16): - v2 = sshr v0, v1 - return v2 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: sxth r0, r0 -; nextln: uxth r1, r1 -; nextln: asr r0, r0, r1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %sshr_i32(i32, i32) -> i32 { -block0(v0: i32, v1: i32): - v2 = sshr v0, v1 - return v2 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: asr r0, r0, r1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %ror_i32(i32, i32) -> i32 { -block0(v0: i32, v1: i32): - v2 = rotr v0, v1 - return v2 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: ror r0, r0, r1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr - -function %rotl_i32(i32, i32) -> i32 { -block0(v0: i32, v1: i32): - v2 = rotl v0, v1 - return v2 -} - -; check: push {fp, lr} -; nextln: mov fp, sp -; nextln: and r1, r1, #31 -; nextln: rsb r1, r1, #32 -; nextln: ror r0, r0, r1 -; nextln: mov sp, fp -; nextln: pop {fp, lr} -; nextln: bx lr diff --git a/cranelift/filetests/src/runone.rs b/cranelift/filetests/src/runone.rs index dfd746636873..51df59758650 100644 --- a/cranelift/filetests/src/runone.rs +++ b/cranelift/filetests/src/runone.rs @@ -9,7 +9,7 @@ use cranelift_codegen::print_errors::pretty_verifier_error; use cranelift_codegen::settings::Flags; use cranelift_codegen::timing; use cranelift_codegen::verify_function; -use cranelift_reader::{parse_test, Feature, IsaSpec, Location, ParseOptions, TestFile}; +use cranelift_reader::{parse_test, IsaSpec, Location, ParseOptions}; use log::info; use std::borrow::Cow; use std::cell::Cell; @@ -18,31 +18,6 @@ use std::path::{Path, PathBuf}; use std::str::Lines; use std::time; -/// Skip the tests which define features and for which there's a feature mismatch. -/// -/// When a test must be skipped, returns an Option with a string containing an explanation why; -/// otherwise, return None. -fn skip_feature_mismatches(testfile: &TestFile) -> Option<&'static str> { - let mut has_experimental_arm32 = false; - - for feature in &testfile.features { - if let Feature::With(name) = feature { - match *name { - "experimental_arm32" => has_experimental_arm32 = true, - _ => {} - } - } - } - - // Don't run tests if the experimental support for arm32 is disabled. - #[cfg(not(feature = "experimental_arm32"))] - if has_experimental_arm32 { - return Some("missing support for experimental_arm32"); - } - - None -} - /// Load `path` and run the test in it. /// /// If running this test causes a panic, it will propagate as normal. @@ -78,11 +53,6 @@ pub fn run( } }; - if let Some(msg) = skip_feature_mismatches(&testfile) { - println!("skipped {:?}: {}", path, msg); - return Ok(started.elapsed()); - } - if testfile.functions.is_empty() { anyhow::bail!("no functions found"); }