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:
@@ -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 {}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>) {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>) {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)> {
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user