Skip to content

Commit

Permalink
x64 new backend: port ABI implementation to shared infrastructure wit…
Browse files Browse the repository at this point in the history
…h AArch64.

Previously, in bytecodealliance#2128, we factored out a common "vanilla 64-bit ABI"
implementation from the AArch64 ABI code, with the idea that this should
be largely compatible with x64. This PR alters the new x64 backend to
make use of the shared infrastructure, removing the duplication that
existed previously. The generated code is nearly (not exactly) the same;
the only difference relates to how the clobber-save region is padded in
the prologue.

This also changes some register allocations in the aarch64 code because
call support in the shared ABI infra now passes a temp vreg in, rather
than requiring use of a fixed, non-allocable temp; tests have been
updated, and the runtime behavior is unchanged.
  • Loading branch information
cfallin committed Sep 9, 2020
1 parent 3d6c4d3 commit e8f772c
Show file tree
Hide file tree
Showing 17 changed files with 740 additions and 1,185 deletions.
59 changes: 32 additions & 27 deletions cranelift/codegen/src/isa/aarch64/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,15 @@ use alloc::boxed::Box;
use alloc::vec::Vec;
use regalloc::{RealReg, Reg, RegClass, Set, Writable};
use smallvec::SmallVec;
use std::convert::TryFrom;

// We use a generic implementation that factors out AArch64 and x64 ABI commonalities, because
// these ABIs are very similar.

/// Support for the AArch64 ABI from the callee side (within a function body).
pub type AArch64ABIBody = ABIBodyImpl<AArch64MachineImpl>;
pub(crate) type AArch64ABICallee = ABICalleeImpl<AArch64MachineDeps>;

/// Support for the AArch64 ABI from the caller side (at a callsite).
pub type AArch64ABICall = ABICallImpl<AArch64MachineImpl>;
pub(crate) type AArch64ABICaller = ABICallerImpl<AArch64MachineDeps>;

// Spidermonkey specific ABI convention.

Expand Down Expand Up @@ -105,9 +104,9 @@ impl Into<AMode> for StackAMode {

/// AArch64-specific ABI behavior. This struct just serves as an implementation
/// point for the trait; it is never actually instantiated.
pub struct AArch64MachineImpl;
pub(crate) struct AArch64MachineDeps;

impl ABIMachineImpl for AArch64MachineImpl {
impl ABIMachineSpec for AArch64MachineDeps {
type I = Inst;

fn compute_arg_locs(
Expand Down Expand Up @@ -285,7 +284,8 @@ impl ABIMachineImpl for AArch64MachineImpl {
Inst::Ret
}

fn gen_add_imm(into_reg: Writable<Reg>, from_reg: Reg, imm: u64) -> SmallVec<[Inst; 4]> {
fn gen_add_imm(into_reg: Writable<Reg>, from_reg: Reg, imm: u32) -> SmallVec<[Inst; 4]> {
let imm = imm as u64;
let mut insts = SmallVec::new();
if let Some(imm12) = Imm12::maybe_from_u64(imm) {
insts.push(Inst::AluRRImm12 {
Expand All @@ -296,6 +296,7 @@ impl ABIMachineImpl for AArch64MachineImpl {
});
} else {
let scratch2 = writable_tmp2_reg();
assert_ne!(scratch2.to_reg(), from_reg);
insts.extend(Inst::load_constant(scratch2, imm.into()));
insts.push(Inst::AluRRRExtend {
alu_op: ALUOp::Add64,
Expand Down Expand Up @@ -334,29 +335,29 @@ impl ABIMachineImpl for AArch64MachineImpl {
Inst::LoadAddr { rd: into_reg, mem }
}

fn get_fixed_tmp_reg() -> Reg {
fn get_stacklimit_reg() -> Reg {
spilltmp_reg()
}

fn gen_load_base_offset(into_reg: Writable<Reg>, base: Reg, offset: i64, ty: Type) -> Inst {
let mem = AMode::RegOffset(base, offset, ty);
fn gen_load_base_offset(into_reg: Writable<Reg>, base: Reg, offset: i32, ty: Type) -> Inst {
let mem = AMode::RegOffset(base, offset as i64, ty);
Inst::gen_load(into_reg, mem, ty)
}

fn gen_store_base_offset(base: Reg, offset: i64, from_reg: Reg, ty: Type) -> Inst {
let mem = AMode::RegOffset(base, offset, ty);
fn gen_store_base_offset(base: Reg, offset: i32, from_reg: Reg, ty: Type) -> Inst {
let mem = AMode::RegOffset(base, offset as i64, ty);
Inst::gen_store(mem, from_reg, ty)
}

fn gen_sp_reg_adjust(amount: i64) -> SmallVec<[Inst; 2]> {
fn gen_sp_reg_adjust(amount: i32) -> SmallVec<[Inst; 2]> {
if amount == 0 {
return SmallVec::new();
}

let (amount, is_sub) = if amount > 0 {
(u64::try_from(amount).unwrap(), false)
(amount as u64, false)
} else {
(u64::try_from(-amount).unwrap(), true)
(-amount as u64, true)
};

let alu_op = if is_sub { ALUOp::Sub64 } else { ALUOp::Add64 };
Expand Down Expand Up @@ -389,8 +390,10 @@ impl ABIMachineImpl for AArch64MachineImpl {
ret
}

fn gen_nominal_sp_adj(offset: i64) -> Inst {
Inst::VirtualSPOffsetAdj { offset }
fn gen_nominal_sp_adj(offset: i32) -> Inst {
Inst::VirtualSPOffsetAdj {
offset: offset as i64,
}
}

fn gen_prologue_frame_setup() -> SmallVec<[Inst; 2]> {
Expand Down Expand Up @@ -553,11 +556,12 @@ impl ABIMachineImpl for AArch64MachineImpl {
defs: Vec<Writable<Reg>>,
loc: SourceLoc,
opcode: ir::Opcode,
) -> SmallVec<[(/* is_safepoint = */ bool, Inst); 2]> {
tmp: Writable<Reg>,
) -> SmallVec<[(InstIsSafepoint, Inst); 2]> {
let mut insts = SmallVec::new();
match &dest {
&CallDest::ExtName(ref name, RelocDistance::Near) => insts.push((
true,
InstIsSafepoint::Yes,
Inst::Call {
info: Box::new(CallInfo {
dest: name.clone(),
Expand All @@ -570,19 +574,19 @@ impl ABIMachineImpl for AArch64MachineImpl {
)),
&CallDest::ExtName(ref name, RelocDistance::Far) => {
insts.push((
false,
InstIsSafepoint::No,
Inst::LoadExtName {
rd: writable_spilltmp_reg(),
rd: tmp,
name: Box::new(name.clone()),
offset: 0,
srcloc: loc,
},
));
insts.push((
true,
InstIsSafepoint::Yes,
Inst::CallInd {
info: Box::new(CallIndInfo {
rn: spilltmp_reg(),
rn: tmp.to_reg(),
uses,
defs,
loc,
Expand All @@ -592,7 +596,7 @@ impl ABIMachineImpl for AArch64MachineImpl {
));
}
&CallDest::Reg(reg) => insts.push((
true,
InstIsSafepoint::Yes,
Inst::CallInd {
info: Box::new(CallIndInfo {
rn: *reg,
Expand All @@ -608,7 +612,7 @@ impl ABIMachineImpl for AArch64MachineImpl {
insts
}

fn get_spillslot_size(rc: RegClass, ty: Type) -> u32 {
fn get_number_of_spillslots_for_value(rc: RegClass, ty: Type) -> u32 {
// We allocate in terms of 8-byte slots.
match (rc, ty) {
(RegClass::I64, _) => 1,
Expand Down Expand Up @@ -698,9 +702,10 @@ fn get_callee_saves(
}
}
}
// Sort registers for deterministic code output.
int_saves.sort_by_key(|r| r.to_reg().get_index());
vec_saves.sort_by_key(|r| r.to_reg().get_index());
// Sort registers for deterministic code output. We can do an unstable sort because the
// registers will be unique (there are no dups).
int_saves.sort_unstable_by_key(|r| r.to_reg().get_index());
vec_saves.sort_unstable_by_key(|r| r.to_reg().get_index());
(int_saves, vec_saves)
}

Expand Down
2 changes: 1 addition & 1 deletion cranelift/codegen/src/isa/aarch64/inst/emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ pub struct EmitState {
}

impl MachInstEmitState<Inst> for EmitState {
fn new(abi: &dyn ABIBody<I = Inst>) -> Self {
fn new(abi: &dyn ABICallee<I = Inst>) -> Self {
EmitState {
virtual_sp_offset: 0,
nominal_sp_to_fp: abi.frame_size() as i64,
Expand Down
4 changes: 2 additions & 2 deletions cranelift/codegen/src/isa/aarch64/lower_inst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1837,7 +1837,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
assert!(inputs.len() == sig.params.len());
assert!(outputs.len() == sig.returns.len());
(
AArch64ABICall::from_func(sig, &extname, dist, loc)?,
AArch64ABICaller::from_func(sig, &extname, dist, loc)?,
&inputs[..],
)
}
Expand All @@ -1846,7 +1846,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
let sig = ctx.call_sig(insn).unwrap();
assert!(inputs.len() - 1 == sig.params.len());
assert!(outputs.len() == sig.returns.len());
(AArch64ABICall::from_ptr(sig, ptr, loc, op)?, &inputs[1..])
(AArch64ABICaller::from_ptr(sig, ptr, loc, op)?, &inputs[1..])
}
_ => unreachable!(),
};
Expand Down
2 changes: 1 addition & 1 deletion cranelift/codegen/src/isa/aarch64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ impl AArch64Backend {
func: &Function,
flags: settings::Flags,
) -> CodegenResult<VCode<inst::Inst>> {
let abi = Box::new(abi::AArch64ABIBody::new(func, flags)?);
let abi = Box::new(abi::AArch64ABICallee::new(func, flags)?);
compile::compile::<AArch64Backend>(func, self, abi)
}
}
Expand Down
Loading

0 comments on commit e8f772c

Please sign in to comment.