Skip to content

Commit e8f772c

Browse files
committed
x64 new backend: port ABI implementation to shared infrastructure with AArch64.
Previously, in #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.
1 parent 3d6c4d3 commit e8f772c

File tree

17 files changed

+740
-1185
lines changed

17 files changed

+740
-1185
lines changed

cranelift/codegen/src/isa/aarch64/abi.rs

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,15 @@ use alloc::boxed::Box;
1313
use alloc::vec::Vec;
1414
use regalloc::{RealReg, Reg, RegClass, Set, Writable};
1515
use smallvec::SmallVec;
16-
use std::convert::TryFrom;
1716

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

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

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

2726
// Spidermonkey specific ABI convention.
2827

@@ -105,9 +104,9 @@ impl Into<AMode> for StackAMode {
105104

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

110-
impl ABIMachineImpl for AArch64MachineImpl {
109+
impl ABIMachineSpec for AArch64MachineDeps {
111110
type I = Inst;
112111

113112
fn compute_arg_locs(
@@ -285,7 +284,8 @@ impl ABIMachineImpl for AArch64MachineImpl {
285284
Inst::Ret
286285
}
287286

288-
fn gen_add_imm(into_reg: Writable<Reg>, from_reg: Reg, imm: u64) -> SmallVec<[Inst; 4]> {
287+
fn gen_add_imm(into_reg: Writable<Reg>, from_reg: Reg, imm: u32) -> SmallVec<[Inst; 4]> {
288+
let imm = imm as u64;
289289
let mut insts = SmallVec::new();
290290
if let Some(imm12) = Imm12::maybe_from_u64(imm) {
291291
insts.push(Inst::AluRRImm12 {
@@ -296,6 +296,7 @@ impl ABIMachineImpl for AArch64MachineImpl {
296296
});
297297
} else {
298298
let scratch2 = writable_tmp2_reg();
299+
assert_ne!(scratch2.to_reg(), from_reg);
299300
insts.extend(Inst::load_constant(scratch2, imm.into()));
300301
insts.push(Inst::AluRRRExtend {
301302
alu_op: ALUOp::Add64,
@@ -334,29 +335,29 @@ impl ABIMachineImpl for AArch64MachineImpl {
334335
Inst::LoadAddr { rd: into_reg, mem }
335336
}
336337

337-
fn get_fixed_tmp_reg() -> Reg {
338+
fn get_stacklimit_reg() -> Reg {
338339
spilltmp_reg()
339340
}
340341

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

346-
fn gen_store_base_offset(base: Reg, offset: i64, from_reg: Reg, ty: Type) -> Inst {
347-
let mem = AMode::RegOffset(base, offset, ty);
347+
fn gen_store_base_offset(base: Reg, offset: i32, from_reg: Reg, ty: Type) -> Inst {
348+
let mem = AMode::RegOffset(base, offset as i64, ty);
348349
Inst::gen_store(mem, from_reg, ty)
349350
}
350351

351-
fn gen_sp_reg_adjust(amount: i64) -> SmallVec<[Inst; 2]> {
352+
fn gen_sp_reg_adjust(amount: i32) -> SmallVec<[Inst; 2]> {
352353
if amount == 0 {
353354
return SmallVec::new();
354355
}
355356

356357
let (amount, is_sub) = if amount > 0 {
357-
(u64::try_from(amount).unwrap(), false)
358+
(amount as u64, false)
358359
} else {
359-
(u64::try_from(-amount).unwrap(), true)
360+
(-amount as u64, true)
360361
};
361362

362363
let alu_op = if is_sub { ALUOp::Sub64 } else { ALUOp::Add64 };
@@ -389,8 +390,10 @@ impl ABIMachineImpl for AArch64MachineImpl {
389390
ret
390391
}
391392

392-
fn gen_nominal_sp_adj(offset: i64) -> Inst {
393-
Inst::VirtualSPOffsetAdj { offset }
393+
fn gen_nominal_sp_adj(offset: i32) -> Inst {
394+
Inst::VirtualSPOffsetAdj {
395+
offset: offset as i64,
396+
}
394397
}
395398

396399
fn gen_prologue_frame_setup() -> SmallVec<[Inst; 2]> {
@@ -553,11 +556,12 @@ impl ABIMachineImpl for AArch64MachineImpl {
553556
defs: Vec<Writable<Reg>>,
554557
loc: SourceLoc,
555558
opcode: ir::Opcode,
556-
) -> SmallVec<[(/* is_safepoint = */ bool, Inst); 2]> {
559+
tmp: Writable<Reg>,
560+
) -> SmallVec<[(InstIsSafepoint, Inst); 2]> {
557561
let mut insts = SmallVec::new();
558562
match &dest {
559563
&CallDest::ExtName(ref name, RelocDistance::Near) => insts.push((
560-
true,
564+
InstIsSafepoint::Yes,
561565
Inst::Call {
562566
info: Box::new(CallInfo {
563567
dest: name.clone(),
@@ -570,19 +574,19 @@ impl ABIMachineImpl for AArch64MachineImpl {
570574
)),
571575
&CallDest::ExtName(ref name, RelocDistance::Far) => {
572576
insts.push((
573-
false,
577+
InstIsSafepoint::No,
574578
Inst::LoadExtName {
575-
rd: writable_spilltmp_reg(),
579+
rd: tmp,
576580
name: Box::new(name.clone()),
577581
offset: 0,
578582
srcloc: loc,
579583
},
580584
));
581585
insts.push((
582-
true,
586+
InstIsSafepoint::Yes,
583587
Inst::CallInd {
584588
info: Box::new(CallIndInfo {
585-
rn: spilltmp_reg(),
589+
rn: tmp.to_reg(),
586590
uses,
587591
defs,
588592
loc,
@@ -592,7 +596,7 @@ impl ABIMachineImpl for AArch64MachineImpl {
592596
));
593597
}
594598
&CallDest::Reg(reg) => insts.push((
595-
true,
599+
InstIsSafepoint::Yes,
596600
Inst::CallInd {
597601
info: Box::new(CallIndInfo {
598602
rn: *reg,
@@ -608,7 +612,7 @@ impl ABIMachineImpl for AArch64MachineImpl {
608612
insts
609613
}
610614

611-
fn get_spillslot_size(rc: RegClass, ty: Type) -> u32 {
615+
fn get_number_of_spillslots_for_value(rc: RegClass, ty: Type) -> u32 {
612616
// We allocate in terms of 8-byte slots.
613617
match (rc, ty) {
614618
(RegClass::I64, _) => 1,
@@ -698,9 +702,10 @@ fn get_callee_saves(
698702
}
699703
}
700704
}
701-
// Sort registers for deterministic code output.
702-
int_saves.sort_by_key(|r| r.to_reg().get_index());
703-
vec_saves.sort_by_key(|r| r.to_reg().get_index());
705+
// Sort registers for deterministic code output. We can do an unstable sort because the
706+
// registers will be unique (there are no dups).
707+
int_saves.sort_unstable_by_key(|r| r.to_reg().get_index());
708+
vec_saves.sort_unstable_by_key(|r| r.to_reg().get_index());
704709
(int_saves, vec_saves)
705710
}
706711

cranelift/codegen/src/isa/aarch64/inst/emit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ pub struct EmitState {
440440
}
441441

442442
impl MachInstEmitState<Inst> for EmitState {
443-
fn new(abi: &dyn ABIBody<I = Inst>) -> Self {
443+
fn new(abi: &dyn ABICallee<I = Inst>) -> Self {
444444
EmitState {
445445
virtual_sp_offset: 0,
446446
nominal_sp_to_fp: abi.frame_size() as i64,

cranelift/codegen/src/isa/aarch64/lower_inst.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1837,7 +1837,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
18371837
assert!(inputs.len() == sig.params.len());
18381838
assert!(outputs.len() == sig.returns.len());
18391839
(
1840-
AArch64ABICall::from_func(sig, &extname, dist, loc)?,
1840+
AArch64ABICaller::from_func(sig, &extname, dist, loc)?,
18411841
&inputs[..],
18421842
)
18431843
}
@@ -1846,7 +1846,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
18461846
let sig = ctx.call_sig(insn).unwrap();
18471847
assert!(inputs.len() - 1 == sig.params.len());
18481848
assert!(outputs.len() == sig.returns.len());
1849-
(AArch64ABICall::from_ptr(sig, ptr, loc, op)?, &inputs[1..])
1849+
(AArch64ABICaller::from_ptr(sig, ptr, loc, op)?, &inputs[1..])
18501850
}
18511851
_ => unreachable!(),
18521852
};

cranelift/codegen/src/isa/aarch64/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ impl AArch64Backend {
4747
func: &Function,
4848
flags: settings::Flags,
4949
) -> CodegenResult<VCode<inst::Inst>> {
50-
let abi = Box::new(abi::AArch64ABIBody::new(func, flags)?);
50+
let abi = Box::new(abi::AArch64ABICallee::new(func, flags)?);
5151
compile::compile::<AArch64Backend>(func, self, abi)
5252
}
5353
}

0 commit comments

Comments
 (0)