Cranelift: Remove ABICallee trait (#4701)

* Cranelift: Remove `ABICallee` trait

It has only one implementation: the `ABICalleeImpl` struct. By using that
directly we can avoid unnecessary layers of generics and abstractions as well as
a couple `Box`es that were previously putting the single implementation into a
`Box<dyn>`.

* Cranelift: Rename `ABICalleeImpl` to `AbiCallee`

* Fix comments as per review

* Rename `AbiCallee` to `Callee`
This commit is contained in:
Nick Fitzgerald
2022-08-15 11:27:05 -07:00
committed by GitHub
parent 863cbc345c
commit f0c60f46a8
17 changed files with 142 additions and 262 deletions

View File

@@ -21,7 +21,7 @@ use smallvec::{smallvec, SmallVec};
// these ABIs are very similar.
/// Support for the AArch64 ABI from the callee side (within a function body).
pub(crate) type AArch64ABICallee = ABICalleeImpl<AArch64MachineDeps>;
pub(crate) type AArch64Callee = Callee<AArch64MachineDeps>;
/// Support for the AArch64 ABI from the caller side (at a callsite).
pub(crate) type AArch64ABICaller = ABICallerImpl<AArch64MachineDeps>;
@@ -65,7 +65,7 @@ fn saved_reg_stack_size(
/// AArch64-specific ABI behavior. This struct just serves as an implementation
/// point for the trait; it is never actually instantiated.
pub(crate) struct AArch64MachineDeps;
pub struct AArch64MachineDeps;
impl IsaFlags for aarch64_settings::Flags {}

View File

@@ -630,7 +630,7 @@ pub struct EmitState {
}
impl MachInstEmitState<Inst> for EmitState {
fn new(abi: &dyn ABICallee<I = Inst>) -> Self {
fn new(abi: &Callee<AArch64MachineDeps>) -> Self {
EmitState {
virtual_sp_offset: 0,
nominal_sp_to_fp: abi.frame_size() as i64,

View File

@@ -1060,6 +1060,7 @@ fn aarch64_get_operands<F: Fn(VReg) -> VReg>(inst: &Inst, collector: &mut Operan
// Instructions: misc functions and external interface
impl MachInst for Inst {
type ABIMachineSpec = AArch64MachineDeps;
type LabelUse = LabelUse;
fn get_operands<F: Fn(VReg) -> VReg>(&self, collector: &mut OperandCollector<'_, F>) {

View File

@@ -60,7 +60,7 @@ impl AArch64Backend {
flags: shared_settings::Flags,
) -> CodegenResult<(VCode<inst::Inst>, regalloc2::Output)> {
let emit_info = EmitInfo::new(flags.clone());
let abi = Box::new(abi::AArch64ABICallee::new(func, self, &self.isa_flags)?);
let abi = abi::AArch64Callee::new(func, self, &self.isa_flags)?;
compile::compile::<AArch64Backend>(func, self, abi, &self.machine_env, emit_info)
}
}

View File

@@ -87,7 +87,7 @@ use std::convert::TryFrom;
// We use a generic implementation that factors out ABI commonalities.
/// Support for the S390x ABI from the callee side (within a function body).
pub type S390xABICallee = ABICalleeImpl<S390xMachineDeps>;
pub type S390xCallee = Callee<S390xMachineDeps>;
/// ABI Register usage

View File

@@ -1,8 +1,8 @@
//! S390x ISA: binary code emission.
use crate::binemit::{Reloc, StackMap};
use crate::ir::TrapCode;
use crate::ir::{MemFlags, RelSourceLoc};
use crate::ir::{MemFlags, RelSourceLoc, TrapCode};
use crate::isa::s390x::abi::S390xMachineDeps;
use crate::isa::s390x::inst::*;
use crate::isa::s390x::settings as s390x_settings;
use crate::machinst::reg::count_operands;
@@ -1260,7 +1260,7 @@ pub struct EmitState {
}
impl MachInstEmitState<Inst> for EmitState {
fn new(abi: &dyn ABICallee<I = Inst>) -> Self {
fn new(abi: &Callee<S390xMachineDeps>) -> Self {
EmitState {
virtual_sp_offset: 0,
initial_sp_offset: abi.frame_size() as i64,

View File

@@ -2,6 +2,7 @@
use crate::binemit::{Addend, CodeOffset, Reloc};
use crate::ir::{types, ExternalName, Opcode, Type};
use crate::isa::s390x::abi::S390xMachineDeps;
use crate::isa::CallConv;
use crate::machinst::*;
use crate::{settings, CodegenError, CodegenResult};
@@ -977,6 +978,7 @@ fn s390x_get_operands<F: Fn(VReg) -> VReg>(inst: &Inst, collector: &mut OperandC
// Instructions: misc functions and external interface
impl MachInst for Inst {
type ABIMachineSpec = S390xMachineDeps;
type LabelUse = LabelUse;
fn get_operands<F: Fn(VReg) -> VReg>(&self, collector: &mut OperandCollector<'_, F>) {

View File

@@ -58,7 +58,7 @@ impl S390xBackend {
func: &Function,
) -> CodegenResult<(VCode<inst::Inst>, regalloc2::Output)> {
let emit_info = EmitInfo::new(self.isa_flags.clone());
let abi = Box::new(abi::S390xABICallee::new(func, self, &self.isa_flags)?);
let abi = abi::S390xCallee::new(func, self, &self.isa_flags)?;
compile::compile::<S390xBackend>(func, self, abi, &self.machine_env, emit_info)
}
}

View File

@@ -21,13 +21,13 @@ use std::convert::TryFrom;
static STACK_ARG_RET_SIZE_LIMIT: u64 = 128 * 1024 * 1024;
/// Support for the x64 ABI from the callee side (within a function body).
pub(crate) type X64ABICallee = ABICalleeImpl<X64ABIMachineSpec>;
pub(crate) type X64Callee = Callee<X64ABIMachineSpec>;
/// Support for the x64 ABI from the caller side (at a callsite).
pub(crate) type X64ABICaller = ABICallerImpl<X64ABIMachineSpec>;
/// Implementation of ABI primitives for x64.
pub(crate) struct X64ABIMachineSpec;
pub struct X64ABIMachineSpec;
impl IsaFlags for x64_settings::Flags {}

View File

@@ -2157,6 +2157,8 @@ fn x64_get_operands<F: Fn(VReg) -> VReg>(inst: &Inst, collector: &mut OperandCol
// Instructions: misc functions and external interface
impl MachInst for Inst {
type ABIMachineSpec = X64ABIMachineSpec;
fn get_operands<F: Fn(VReg) -> VReg>(&self, collector: &mut OperandCollector<'_, F>) {
x64_get_operands(&self, collector)
}
@@ -2460,7 +2462,7 @@ impl MachInstEmit for Inst {
}
impl MachInstEmitState<Inst> for EmitState {
fn new(abi: &dyn ABICallee<I = Inst>) -> Self {
fn new(abi: &Callee<X64ABIMachineSpec>) -> Self {
EmitState {
virtual_sp_offset: 0,
nominal_sp_to_fp: abi.frame_size() as i64,

View File

@@ -53,7 +53,7 @@ impl X64Backend {
// 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(), self.x64_flags.clone());
let abi = Box::new(abi::X64ABICallee::new(&func, self, &self.x64_flags)?);
let abi = abi::X64Callee::new(&func, self, &self.x64_flags)?;
compile::compile::<Self>(&func, self, abi, &self.reg_env, emit_info)
}
}

View File

@@ -1,175 +1,12 @@
//! ABI definitions.
use crate::binemit::StackMap;
use crate::ir::{DynamicStackSlot, Signature, StackSlot};
use crate::isa::CallConv;
use crate::machinst::*;
use crate::settings;
use smallvec::SmallVec;
/// A small vector of instructions (with some reasonable size); appropriate for
/// a small fixed sequence implementing one operation.
pub type SmallInstVec<I> = SmallVec<[I; 4]>;
/// Trait implemented by an object that tracks ABI-related state (e.g., stack
/// layout) and can generate code while emitting the *body* of a function.
pub trait ABICallee {
/// The instruction type for the ISA associated with this ABI.
type I: VCodeInst;
/// Does the ABI-body code need temp registers (and if so, of what type)?
/// They will be provided to `init()` as the `temps` arg if so.
fn temps_needed(&self) -> Vec<Type>;
/// Initialize. This is called after the ABICallee is constructed because it
/// may be provided with a vector of temp vregs, which can only be allocated
/// once the lowering context exists.
fn init(&mut self, temps: Vec<Writable<Reg>>);
/// Access the (possibly legalized) signature.
fn signature(&self) -> &Signature;
/// Accumulate outgoing arguments. This ensures that at least SIZE bytes
/// are allocated in the prologue to be available for use in function calls
/// to hold arguments and/or return values. If this function is called
/// multiple times, the maximum of all SIZE values will be available.
fn accumulate_outgoing_args_size(&mut self, size: u32);
/// Get the settings controlling this function's compilation.
fn flags(&self) -> &settings::Flags;
/// Get the calling convention implemented by this ABI object.
fn call_conv(&self) -> CallConv;
/// Number of arguments.
fn num_args(&self) -> usize;
/// Number of return values.
fn num_retvals(&self) -> usize;
/// Number of sized stack slots (not spill slots).
fn num_sized_stackslots(&self) -> usize;
/// The offsets of all sized stack slots (not spill slots) for debuginfo purposes.
fn sized_stackslot_offsets(&self) -> &PrimaryMap<StackSlot, u32>;
/// The offsets of all dynamic stack slots (not spill slots) for debuginfo purposes.
fn dynamic_stackslot_offsets(&self) -> &PrimaryMap<DynamicStackSlot, u32>;
/// All the defined dynamic types.
fn dynamic_type_size(&self, ty: Type) -> u32;
/// Generate an instruction which copies an argument to a destination
/// register.
fn gen_copy_arg_to_regs(
&self,
idx: usize,
into_reg: ValueRegs<Writable<Reg>>,
) -> SmallInstVec<Self::I>;
/// Is the given argument needed in the body (as opposed to, e.g., serving
/// only as a special ABI-specific placeholder)? This controls whether
/// lowering will copy it to a virtual reg use by CLIF instructions.
fn arg_is_needed_in_body(&self, idx: usize) -> bool;
/// Generate any setup instruction needed to save values to the
/// return-value area. This is usually used when were are multiple return
/// values or an otherwise large return value that must be passed on the
/// stack; typically the ABI specifies an extra hidden argument that is a
/// pointer to that memory.
fn gen_retval_area_setup(&self) -> Option<Self::I>;
/// Generate an instruction which copies a source register to a return value slot.
fn gen_copy_regs_to_retval(
&self,
idx: usize,
from_reg: ValueRegs<Writable<Reg>>,
) -> SmallInstVec<Self::I>;
/// Generate a return instruction.
fn gen_ret(&self) -> Self::I;
// -----------------------------------------------------------------
// Every function above this line may only be called pre-regalloc.
// Every function below this line may only be called post-regalloc.
// `spillslots()` must be called before any other post-regalloc
// function.
// ----------------------------------------------------------------
/// Update with the number of spillslots, post-regalloc.
fn set_num_spillslots(&mut self, slots: usize);
/// Update with the clobbered registers, post-regalloc.
fn set_clobbered(&mut self, clobbered: Vec<Writable<RealReg>>);
/// Get the address of a sized stackslot.
fn sized_stackslot_addr(
&self,
slot: StackSlot,
offset: u32,
into_reg: Writable<Reg>,
) -> Self::I;
/// Get the address of a dynamic stackslot.
fn dynamic_stackslot_addr(&self, slot: DynamicStackSlot, into_reg: Writable<Reg>) -> Self::I;
/// Load from a spillslot.
fn load_spillslot(
&self,
slot: SpillSlot,
ty: Type,
into_reg: ValueRegs<Writable<Reg>>,
) -> SmallInstVec<Self::I>;
/// Store to a spillslot.
fn store_spillslot(
&self,
slot: SpillSlot,
ty: Type,
from_reg: ValueRegs<Reg>,
) -> SmallInstVec<Self::I>;
/// Generate a stack map, given a list of spillslots and the emission state
/// at a given program point (prior to emission fo the safepointing
/// instruction).
fn spillslots_to_stack_map(
&self,
slots: &[SpillSlot],
state: &<Self::I as MachInstEmit>::State,
) -> StackMap;
/// Generate a prologue, post-regalloc. This should include any stack
/// frame or other setup necessary to use the other methods (`load_arg`,
/// `store_retval`, and spillslot accesses.) `self` is mutable so that we
/// can store information in it which will be useful when creating the
/// epilogue.
fn gen_prologue(&mut self) -> SmallInstVec<Self::I>;
/// Generate an epilogue, post-regalloc. Note that this must generate the
/// actual return instruction (rather than emitting this in the lowering
/// logic), because the epilogue code comes before the return and the two are
/// likely closely related.
fn gen_epilogue(&self) -> SmallInstVec<Self::I>;
/// Returns the full frame size for the given function, after prologue
/// emission has run. This comprises the spill slots and stack-storage slots
/// (but not storage for clobbered callee-save registers, arguments pushed
/// at callsites within this function, or other ephemeral pushes).
fn frame_size(&self) -> u32;
/// Returns the size of arguments expected on the stack.
fn stack_args_size(&self) -> u32;
/// Get the spill-slot size.
fn get_spillslot_size(&self, rc: RegClass) -> u32;
/// Generate a spill.
fn gen_spill(&self, to_slot: SpillSlot, from_reg: RealReg) -> Self::I;
/// Generate a reload (fill).
fn gen_reload(&self, to_reg: Writable<RealReg>, from_slot: SpillSlot) -> Self::I;
}
/// Trait implemented by an object that tracks ABI-related state and can
/// generate code while emitting a *call* to a function.
///
@@ -177,11 +14,11 @@ pub trait ABICallee {
/// callsite. It will usually be computed from the called function's
/// signature.
///
/// Unlike `ABICallee` above, methods on this trait are not invoked directly
/// by the machine-independent code. Rather, the machine-specific lowering
/// code will typically create an `ABICaller` when creating machine instructions
/// for an IR call instruction inside `lower()`, directly emit the arg and
/// and retval copies, and attach the register use/def info to the call.
/// Unlike `Callee`, methods on this trait are not invoked directly by the
/// machine-independent code. Rather, the machine-specific lowering code will
/// typically create an `ABICaller` when creating machine instructions for an IR
/// call instruction inside `lower()`, directly emit the arg and and retval
/// copies, and attach the register use/def info to the call.
///
/// This trait is thus provided for convenience to the backends.
pub trait ABICaller {

View File

@@ -697,7 +697,7 @@ impl ABISig {
}
/// ABI object for a function body.
pub struct ABICalleeImpl<M: ABIMachineSpec> {
pub struct Callee<M: ABIMachineSpec> {
/// CLIF-level signature, possibly normalized.
ir_sig: ir::Signature,
/// Signature: arg and retval regs.
@@ -772,7 +772,7 @@ fn get_special_purpose_param_register(
}
}
impl<M: ABIMachineSpec> ABICalleeImpl<M> {
impl<M: ABIMachineSpec> Callee<M> {
/// Create a new body ABI instance.
pub fn new(f: &ir::Function, isa: &dyn TargetIsa, isa_flags: &M::F) -> CodegenResult<Self> {
trace!("ABI: func signature {:?}", f.signature);
@@ -1048,14 +1048,18 @@ fn ensure_struct_return_ptr_is_returned(sig: &ir::Signature) -> ir::Signature {
sig
}
impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
type I = M::I;
fn signature(&self) -> &ir::Signature {
/// ### Pre-Regalloc Functions
///
/// These methods of `Callee` may only be called before regalloc.
impl<M: ABIMachineSpec> Callee<M> {
/// Access the (possibly legalized) signature.
pub fn signature(&self) -> &ir::Signature {
&self.ir_sig
}
fn temps_needed(&self) -> Vec<Type> {
/// Does the ABI-body code need temp registers (and if so, of what type)?
/// They will be provided to `init()` as the `temps` arg if so.
pub fn temps_needed(&self) -> Vec<Type> {
let mut temp_tys = vec![];
for arg in &self.sig.args {
match arg {
@@ -1074,7 +1078,10 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
temp_tys
}
fn init(&mut self, temps: Vec<Writable<Reg>>) {
/// Initialize. This is called after the Callee is constructed because it
/// may be provided with a vector of temp vregs, which can only be allocated
/// once the lowering context exists.
pub fn init(&mut self, temps: Vec<Writable<Reg>>) {
let mut temps_iter = temps.into_iter();
for arg in &self.sig.args {
let temp = match arg {
@@ -1091,45 +1098,40 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
}
}
fn accumulate_outgoing_args_size(&mut self, size: u32) {
/// Accumulate outgoing arguments.
///
/// This ensures that at least `size` bytes are allocated in the prologue to
/// be available for use in function calls to hold arguments and/or return
/// values. If this function is called multiple times, the maximum of all
/// `size` values will be available.
pub fn accumulate_outgoing_args_size(&mut self, size: u32) {
if size > self.outgoing_args_size {
self.outgoing_args_size = size;
}
}
fn flags(&self) -> &settings::Flags {
&self.flags
}
fn call_conv(&self) -> isa::CallConv {
/// Get the calling convention implemented by this ABI object.
pub fn call_conv(&self) -> isa::CallConv {
self.sig.call_conv
}
fn num_args(&self) -> usize {
self.sig.args.len()
}
fn num_retvals(&self) -> usize {
self.sig.rets.len()
}
fn num_sized_stackslots(&self) -> usize {
self.sized_stackslots.len()
}
fn sized_stackslot_offsets(&self) -> &PrimaryMap<StackSlot, u32> {
/// The offsets of all sized stack slots (not spill slots) for debuginfo purposes.
pub fn sized_stackslot_offsets(&self) -> &PrimaryMap<StackSlot, u32> {
&self.sized_stackslots
}
fn dynamic_stackslot_offsets(&self) -> &PrimaryMap<DynamicStackSlot, u32> {
/// The offsets of all dynamic stack slots (not spill slots) for debuginfo purposes.
pub fn dynamic_stackslot_offsets(&self) -> &PrimaryMap<DynamicStackSlot, u32> {
&self.dynamic_stackslots
}
fn gen_copy_arg_to_regs(
/// Generate an instruction which copies an argument to a destination
/// register.
pub fn gen_copy_arg_to_regs(
&self,
idx: usize,
into_regs: ValueRegs<Writable<Reg>>,
) -> SmallInstVec<Self::I> {
) -> SmallInstVec<M::I> {
let mut insts = smallvec![];
let mut copy_arg_slot_to_reg = |slot: &ABIArgSlot, into_reg: &Writable<Reg>| {
match slot {
@@ -1219,15 +1221,19 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
insts
}
fn arg_is_needed_in_body(&self, _idx: usize) -> bool {
/// Is the given argument needed in the body (as opposed to, e.g., serving
/// only as a special ABI-specific placeholder)? This controls whether
/// lowering will copy it to a virtual reg use by CLIF instructions.
pub fn arg_is_needed_in_body(&self, _idx: usize) -> bool {
true
}
fn gen_copy_regs_to_retval(
/// Generate an instruction which copies a source register to a return value slot.
pub fn gen_copy_regs_to_retval(
&self,
idx: usize,
from_regs: ValueRegs<Writable<Reg>>,
) -> SmallInstVec<Self::I> {
) -> SmallInstVec<M::I> {
let mut ret = smallvec![];
let word_bits = M::word_bits() as u8;
match &self.sig.rets[idx] {
@@ -1313,7 +1319,12 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
ret
}
fn gen_retval_area_setup(&self) -> Option<Self::I> {
/// Generate any setup instruction needed to save values to the
/// return-value area. This is usually used when were are multiple return
/// values or an otherwise large return value that must be passed on the
/// stack; typically the ABI specifies an extra hidden argument that is a
/// pointer to that memory.
pub fn gen_retval_area_setup(&self) -> Option<M::I> {
if let Some(i) = self.sig.stack_ret_arg {
let insts = self.gen_copy_arg_to_regs(i, ValueRegs::one(self.ret_area_ptr.unwrap()));
let inst = insts.into_iter().next().unwrap();
@@ -1329,7 +1340,8 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
}
}
fn gen_ret(&self) -> Self::I {
/// Generate a return instruction.
pub fn gen_ret(&self) -> M::I {
let mut rets = vec![];
for ret in &self.sig.rets {
match ret {
@@ -1348,21 +1360,13 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
M::gen_ret(self.setup_frame, &self.isa_flags, rets)
}
fn set_num_spillslots(&mut self, slots: usize) {
self.spillslots = Some(slots);
}
fn set_clobbered(&mut self, clobbered: Vec<Writable<RealReg>>) {
self.clobbered = clobbered;
}
/// Produce an instruction that computes a sized stackslot address.
fn sized_stackslot_addr(
pub fn sized_stackslot_addr(
&self,
slot: StackSlot,
offset: u32,
into_reg: Writable<Reg>,
) -> Self::I {
) -> M::I {
// Offset from beginning of stackslot area, which is at nominal SP (see
// [MemArg::NominalSPOffset] for more details on nominal SP tracking).
let stack_off = self.sized_stackslots[slot] as i64;
@@ -1371,7 +1375,7 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
}
/// Produce an instruction that computes a dynamic stackslot address.
fn dynamic_stackslot_addr(&self, slot: DynamicStackSlot, into_reg: Writable<Reg>) -> Self::I {
pub fn dynamic_stackslot_addr(&self, slot: DynamicStackSlot, into_reg: Writable<Reg>) -> M::I {
let stack_off = self.dynamic_stackslots[slot] as i64;
M::gen_get_stack_addr(
StackAMode::NominalSPOffset(stack_off, I64X2XN),
@@ -1380,17 +1384,13 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
)
}
fn dynamic_type_size(&self, ty: Type) -> u32 {
self.dynamic_type_sizes[&ty]
}
/// Load from a spillslot.
fn load_spillslot(
pub fn load_spillslot(
&self,
slot: SpillSlot,
ty: Type,
into_regs: ValueRegs<Writable<Reg>>,
) -> SmallInstVec<Self::I> {
) -> SmallInstVec<M::I> {
// Offset from beginning of spillslot area, which is at nominal SP + stackslots_size.
let islot = slot.index() as i64;
let spill_off = islot * M::word_bytes() as i64;
@@ -1401,12 +1401,12 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
}
/// Store to a spillslot.
fn store_spillslot(
pub fn store_spillslot(
&self,
slot: SpillSlot,
ty: Type,
from_regs: ValueRegs<Reg>,
) -> SmallInstVec<Self::I> {
) -> SmallInstVec<M::I> {
// Offset from beginning of spillslot area, which is at nominal SP + stackslots_size.
let islot = slot.index() as i64;
let spill_off = islot * M::word_bytes() as i64;
@@ -1415,11 +1415,30 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
gen_store_stack_multi::<M>(StackAMode::NominalSPOffset(sp_off, ty), from_regs, ty)
}
}
fn spillslots_to_stack_map(
/// ### Post-Regalloc Functions
///
/// These methods of `Callee` may only be called after
/// regalloc.
impl<M: ABIMachineSpec> Callee<M> {
/// Update with the number of spillslots, post-regalloc.
pub fn set_num_spillslots(&mut self, slots: usize) {
self.spillslots = Some(slots);
}
/// Update with the clobbered registers, post-regalloc.
pub fn set_clobbered(&mut self, clobbered: Vec<Writable<RealReg>>) {
self.clobbered = clobbered;
}
/// Generate a stack map, given a list of spillslots and the emission state
/// at a given program point (prior to emission of the safepointing
/// instruction).
pub fn spillslots_to_stack_map(
&self,
slots: &[SpillSlot],
state: &<Self::I as MachInstEmit>::State,
state: &<M::I as MachInstEmit>::State,
) -> StackMap {
let virtual_sp_offset = M::get_virtual_sp_offset_from_state(state);
let nominal_sp_to_fp = M::get_nominal_sp_to_fp(state);
@@ -1446,7 +1465,13 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
StackMap::from_slice(&bits[..])
}
fn gen_prologue(&mut self) -> SmallInstVec<Self::I> {
/// Generate a prologue, post-regalloc.
///
/// This should include any stack frame or other setup necessary to use the
/// other methods (`load_arg`, `store_retval`, and spillslot accesses.)
/// `self` is mutable so that we can store information in it which will be
/// useful when creating the epilogue.
pub fn gen_prologue(&mut self) -> SmallInstVec<M::I> {
let bytes = M::word_bytes();
let total_stacksize = self.stackslots_size + bytes * self.spillslots.unwrap() as u32;
let mask = M::stack_align(self.call_conv) - 1;
@@ -1523,7 +1548,12 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
insts
}
fn gen_epilogue(&self) -> SmallInstVec<M::I> {
/// Generate an epilogue, post-regalloc.
///
/// Note that this must generate the actual return instruction (rather than
/// emitting this in the lowering logic), because the epilogue code comes
/// before the return and the two are likely closely related.
pub fn gen_epilogue(&self) -> SmallInstVec<M::I> {
let mut insts = smallvec![];
// Restore clobbered registers.
@@ -1555,16 +1585,22 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
insts
}
fn frame_size(&self) -> u32 {
/// Returns the full frame size for the given function, after prologue
/// emission has run. This comprises the spill slots and stack-storage slots
/// (but not storage for clobbered callee-save registers, arguments pushed
/// at callsites within this function, or other ephemeral pushes).
pub fn frame_size(&self) -> u32 {
self.total_frame_size
.expect("frame size not computed before prologue generation")
}
fn stack_args_size(&self) -> u32 {
/// Returns the size of arguments expected on the stack.
pub fn stack_args_size(&self) -> u32 {
self.sig.sized_stack_arg_space as u32
}
fn get_spillslot_size(&self, rc: RegClass) -> u32 {
/// Get the spill-slot size.
pub fn get_spillslot_size(&self, rc: RegClass) -> u32 {
let max = if self.dynamic_type_sizes.len() == 0 {
16
} else {
@@ -1578,16 +1614,18 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
M::get_number_of_spillslots_for_value(rc, max)
}
fn gen_spill(&self, to_slot: SpillSlot, from_reg: RealReg) -> Self::I {
let ty = Self::I::canonical_type_for_rc(Reg::from(from_reg).class());
/// Generate a spill.
pub fn gen_spill(&self, to_slot: SpillSlot, from_reg: RealReg) -> M::I {
let ty = M::I::canonical_type_for_rc(Reg::from(from_reg).class());
self.store_spillslot(to_slot, ty, ValueRegs::one(Reg::from(from_reg)))
.into_iter()
.next()
.unwrap()
}
fn gen_reload(&self, to_reg: Writable<RealReg>, from_slot: SpillSlot) -> Self::I {
let ty = Self::I::canonical_type_for_rc(to_reg.to_reg().class());
/// Generate a reload (fill).
pub fn gen_reload(&self, to_reg: Writable<RealReg>, from_slot: SpillSlot) -> M::I {
let ty = M::I::canonical_type_for_rc(to_reg.to_reg().class());
self.load_spillslot(
from_slot,
ty,

View File

@@ -14,7 +14,7 @@ use regalloc2::{self, MachineEnv};
pub fn compile<B: LowerBackend + TargetIsa>(
f: &Function,
b: &B,
abi: Box<dyn ABICallee<I = B::MInst>>,
abi: Callee<<<B as LowerBackend>::MInst as MachInst>::ABIMachineSpec>,
machine_env: &MachineEnv,
emit_info: <B::MInst as MachInstEmit>::Info,
) -> CodegenResult<(VCode<B::MInst>, regalloc2::Output)> {

View File

@@ -17,12 +17,11 @@ use crate::ir::{
};
use crate::ir::{ExternalName, RelSourceLoc};
use crate::machinst::{
non_writable_value_regs, writable_value_regs, ABICallee, BlockIndex, BlockLoweringOrder,
non_writable_value_regs, writable_value_regs, BlockIndex, BlockLoweringOrder, Callee,
LoweredBlock, MachLabel, Reg, VCode, VCodeBuilder, VCodeConstant, VCodeConstantData,
VCodeConstants, VCodeInst, ValueRegs, Writable,
};
use crate::{trace, CodegenResult};
use alloc::boxed::Box;
use alloc::vec::Vec;
use core::convert::TryInto;
use regalloc2::VReg;
@@ -345,7 +344,7 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
/// Prepare a new lowering context for the given IR function.
pub fn new(
f: &'func Function,
abi: Box<dyn ABICallee<I = I>>,
abi: Callee<I::ABIMachineSpec>,
emit_info: I::Info,
block_order: BlockLoweringOrder,
) -> CodegenResult<Lower<'func, I>> {
@@ -1008,8 +1007,8 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
&self.f.dfg
}
/// Get the `ABICallee`.
pub fn abi(&mut self) -> &mut dyn ABICallee<I = I> {
/// Get the `Callee`.
pub fn abi(&mut self) -> &mut Callee<I::ABIMachineSpec> {
self.vcode.abi()
}

View File

@@ -50,7 +50,6 @@ use crate::ir::{DynamicStackSlot, RelSourceLoc, StackSlot, Type};
use crate::result::CodegenResult;
use crate::settings::Flags;
use crate::value_label::ValueLabelsRanges;
use alloc::boxed::Box;
use alloc::vec::Vec;
use core::fmt::Debug;
use cranelift_entity::PrimaryMap;
@@ -89,6 +88,9 @@ pub mod reg;
/// A machine instruction.
pub trait MachInst: Clone + Debug {
/// The ABI machine spec for this `MachInst`.
type ABIMachineSpec: ABIMachineSpec<I = Self>;
/// Return the registers referenced by this machine instruction along with
/// the modes of reference (use, def, modify).
fn get_operands<F: Fn(VReg) -> VReg>(&self, collector: &mut OperandCollector<'_, F>);
@@ -260,9 +262,9 @@ pub trait MachInstEmit: MachInst {
/// A trait describing the emission state carried between MachInsts when
/// emitting a function body.
pub trait MachInstEmitState<I: MachInst>: Default + Clone + Debug {
pub trait MachInstEmitState<I: VCodeInst>: Default + Clone + Debug {
/// Create a new emission state given the ABI object.
fn new(abi: &dyn ABICallee<I = I>) -> Self;
fn new(abi: &Callee<I::ABIMachineSpec>) -> Self;
/// Update the emission state before emitting an instruction that is a
/// safepoint.
fn pre_safepoint(&mut self, _stack_map: StackMap) {}

View File

@@ -30,7 +30,6 @@ use regalloc2::{
RegClass, VReg,
};
use alloc::boxed::Box;
use alloc::vec::Vec;
use cranelift_entity::{entity_impl, Keys, PrimaryMap};
use std::collections::hash_map::Entry;
@@ -159,7 +158,7 @@ pub struct VCode<I: VCodeInst> {
block_order: BlockLoweringOrder,
/// ABI object.
abi: Box<dyn ABICallee<I = I>>,
abi: Callee<I::ABIMachineSpec>,
/// Constant information used during code emission. This should be
/// immutable across function compilations within the same module.
@@ -280,7 +279,7 @@ pub enum VCodeBuildDirection {
impl<I: VCodeInst> VCodeBuilder<I> {
/// Create a new VCodeBuilder.
pub fn new(
abi: Box<dyn ABICallee<I = I>>,
abi: Callee<I::ABIMachineSpec>,
emit_info: I::Info,
block_order: BlockLoweringOrder,
constants: VCodeConstants,
@@ -301,8 +300,8 @@ impl<I: VCodeInst> VCodeBuilder<I> {
}
/// Access the ABI object.
pub fn abi(&mut self) -> &mut dyn ABICallee<I = I> {
&mut *self.vcode.abi
pub fn abi(&mut self) -> &mut Callee<I::ABIMachineSpec> {
&mut self.vcode.abi
}
/// Access to the BlockLoweringOrder object.
@@ -626,7 +625,7 @@ fn is_reftype(ty: Type) -> bool {
impl<I: VCodeInst> VCode<I> {
/// New empty VCode.
fn new(
abi: Box<dyn ABICallee<I = I>>,
abi: Callee<I::ABIMachineSpec>,
emit_info: I::Info,
block_order: BlockLoweringOrder,
constants: VCodeConstants,
@@ -797,7 +796,7 @@ impl<I: VCodeInst> VCode<I> {
let mut cur_srcloc = None;
let mut last_offset = None;
let mut inst_offsets = vec![];
let mut state = I::State::new(&*self.abi);
let mut state = I::State::new(&self.abi);
let mut disasm = String::new();