From 3dda6080597a3ddab94b11f234ee503ed8586351 Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Mon, 14 Feb 2022 10:46:07 -0800 Subject: [PATCH] Remove incomplete/unmaintained ARM32 backend (for now). In #3721, we have been discussing what to do about the ARM32 backend in Cranelift. Currently, this backend supports only 32-bit types, which is insufficient for full Wasm-MVP; it's missing other critical bits, like floating-point support; and it has only ever been exercised, AFAIK, via the filetests for the individual CLIF instructions that are implemented. We were very very thankful for the original contribution of this backend, even in its partial state, and we had hoped at the time that we could eventually mature it in-tree until it supported e.g. Wasm and other use-cases. But that hasn't yet happened -- to the blame of no-one, to be clear, we just haven't had a contributor with sufficient time. Unfortunately, the existence of the backend and lack of active maintainer now potentially pose a bit of a burden as we hope to make continuing changes to the backend framework. For example, the ISLE migration, and the use of regalloc2 that it will allow, would need all of the existing lowering patterns in the hand-written ARM32 backend to be rewritten as ISLE rules. Given that we don't currently have the resources to do this, we think it's probably best if we, sadly, for now remove this partial backend. This is not in any way a statement of what we might accept in the future, though. If, in the future, an ARM32 backend updated to our latest codebase with an active maintainer were to appear, we'd be happy to merge it (and likewise for any other architecture!). But for now, this is probably the best path. Thanks again to the original contributor @jmkrauz and we hope that this work can eventually be brought back and reused if someone has the time to do so! --- .github/workflows/main.yml | 2 - cranelift/Cargo.toml | 1 - cranelift/codegen/Cargo.toml | 1 - cranelift/codegen/meta/src/isa/arm32.rs | 15 - cranelift/codegen/meta/src/isa/mod.rs | 7 +- cranelift/codegen/src/isa/arm32/abi.rs | 506 ----- cranelift/codegen/src/isa/arm32/inst/args.rs | 335 --- cranelift/codegen/src/isa/arm32/inst/emit.rs | 821 ------- .../codegen/src/isa/arm32/inst/emit_tests.rs | 1956 ----------------- cranelift/codegen/src/isa/arm32/inst/mod.rs | 1361 ------------ cranelift/codegen/src/isa/arm32/inst/regs.rs | 128 -- cranelift/codegen/src/isa/arm32/lower.rs | 242 -- cranelift/codegen/src/isa/arm32/lower_inst.rs | 599 ----- cranelift/codegen/src/isa/arm32/mod.rs | 148 -- cranelift/codegen/src/isa/mod.rs | 4 - cranelift/codegen/src/machinst/lower.rs | 12 +- cranelift/codegen/src/machinst/valueregs.rs | 57 - cranelift/filetests/Cargo.toml | 3 - .../filetests/filetests/isa/arm32/aluops.clif | 244 -- .../filetests/filetests/isa/arm32/bitops.clif | 133 -- .../filetests/filetests/isa/arm32/cond.clif | 61 - .../filetests/isa/arm32/constants.clif | 108 - .../filetests/isa/arm32/control-flow.clif | 132 -- .../filetests/filetests/isa/arm32/extend.clif | 81 - .../filetests/filetests/isa/arm32/params.clif | 48 - .../filetests/isa/arm32/shift-rotate.clif | 158 -- cranelift/filetests/src/runone.rs | 30 - 27 files changed, 5 insertions(+), 7188 deletions(-) delete mode 100644 cranelift/codegen/meta/src/isa/arm32.rs delete mode 100644 cranelift/codegen/src/isa/arm32/abi.rs delete mode 100644 cranelift/codegen/src/isa/arm32/inst/args.rs delete mode 100644 cranelift/codegen/src/isa/arm32/inst/emit.rs delete mode 100644 cranelift/codegen/src/isa/arm32/inst/emit_tests.rs delete mode 100644 cranelift/codegen/src/isa/arm32/inst/mod.rs delete mode 100644 cranelift/codegen/src/isa/arm32/inst/regs.rs delete mode 100644 cranelift/codegen/src/isa/arm32/lower.rs delete mode 100644 cranelift/codegen/src/isa/arm32/lower_inst.rs delete mode 100644 cranelift/codegen/src/isa/arm32/mod.rs delete mode 100644 cranelift/filetests/filetests/isa/arm32/aluops.clif delete mode 100644 cranelift/filetests/filetests/isa/arm32/bitops.clif delete mode 100644 cranelift/filetests/filetests/isa/arm32/cond.clif delete mode 100644 cranelift/filetests/filetests/isa/arm32/constants.clif delete mode 100644 cranelift/filetests/filetests/isa/arm32/control-flow.clif delete mode 100644 cranelift/filetests/filetests/isa/arm32/extend.clif delete mode 100644 cranelift/filetests/filetests/isa/arm32/params.clif delete mode 100644 cranelift/filetests/filetests/isa/arm32/shift-rotate.clif 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..c81904fc22cf 100644 --- a/cranelift/filetests/src/runone.rs +++ b/cranelift/filetests/src/runone.rs @@ -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"); }