From f0c60f46a8f9c590431f4954f94ae04b5bc85c99 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Mon, 15 Aug 2022 11:27:05 -0700 Subject: [PATCH] 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`. * Cranelift: Rename `ABICalleeImpl` to `AbiCallee` * Fix comments as per review * Rename `AbiCallee` to `Callee` --- cranelift/codegen/src/isa/aarch64/abi.rs | 4 +- .../codegen/src/isa/aarch64/inst/emit.rs | 2 +- cranelift/codegen/src/isa/aarch64/inst/mod.rs | 1 + cranelift/codegen/src/isa/aarch64/mod.rs | 2 +- cranelift/codegen/src/isa/s390x/abi.rs | 2 +- cranelift/codegen/src/isa/s390x/inst/emit.rs | 6 +- cranelift/codegen/src/isa/s390x/inst/mod.rs | 2 + cranelift/codegen/src/isa/s390x/mod.rs | 2 +- cranelift/codegen/src/isa/x64/abi.rs | 4 +- cranelift/codegen/src/isa/x64/inst/mod.rs | 4 +- cranelift/codegen/src/isa/x64/mod.rs | 2 +- cranelift/codegen/src/machinst/abi.rs | 173 +----------------- cranelift/codegen/src/machinst/abi_impl.rs | 168 ++++++++++------- cranelift/codegen/src/machinst/compile.rs | 2 +- cranelift/codegen/src/machinst/lower.rs | 9 +- cranelift/codegen/src/machinst/mod.rs | 8 +- cranelift/codegen/src/machinst/vcode.rs | 13 +- 17 files changed, 142 insertions(+), 262 deletions(-) diff --git a/cranelift/codegen/src/isa/aarch64/abi.rs b/cranelift/codegen/src/isa/aarch64/abi.rs index e5e6961a83..4004ae50b1 100644 --- a/cranelift/codegen/src/isa/aarch64/abi.rs +++ b/cranelift/codegen/src/isa/aarch64/abi.rs @@ -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; +pub(crate) type AArch64Callee = Callee; /// Support for the AArch64 ABI from the caller side (at a callsite). pub(crate) type AArch64ABICaller = ABICallerImpl; @@ -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 {} diff --git a/cranelift/codegen/src/isa/aarch64/inst/emit.rs b/cranelift/codegen/src/isa/aarch64/inst/emit.rs index 40e4d289ec..3c4baa63f9 100644 --- a/cranelift/codegen/src/isa/aarch64/inst/emit.rs +++ b/cranelift/codegen/src/isa/aarch64/inst/emit.rs @@ -630,7 +630,7 @@ pub struct EmitState { } impl MachInstEmitState for EmitState { - fn new(abi: &dyn ABICallee) -> Self { + fn new(abi: &Callee) -> Self { EmitState { virtual_sp_offset: 0, nominal_sp_to_fp: abi.frame_size() as i64, diff --git a/cranelift/codegen/src/isa/aarch64/inst/mod.rs b/cranelift/codegen/src/isa/aarch64/inst/mod.rs index 96a5c0b37b..fb4f4e3945 100644 --- a/cranelift/codegen/src/isa/aarch64/inst/mod.rs +++ b/cranelift/codegen/src/isa/aarch64/inst/mod.rs @@ -1060,6 +1060,7 @@ fn aarch64_get_operands 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 VReg>(&self, collector: &mut OperandCollector<'_, F>) { diff --git a/cranelift/codegen/src/isa/aarch64/mod.rs b/cranelift/codegen/src/isa/aarch64/mod.rs index 264c2d5053..694cc48ef8 100644 --- a/cranelift/codegen/src/isa/aarch64/mod.rs +++ b/cranelift/codegen/src/isa/aarch64/mod.rs @@ -60,7 +60,7 @@ impl AArch64Backend { flags: shared_settings::Flags, ) -> CodegenResult<(VCode, 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::(func, self, abi, &self.machine_env, emit_info) } } diff --git a/cranelift/codegen/src/isa/s390x/abi.rs b/cranelift/codegen/src/isa/s390x/abi.rs index ac9d90596d..2244055a2f 100644 --- a/cranelift/codegen/src/isa/s390x/abi.rs +++ b/cranelift/codegen/src/isa/s390x/abi.rs @@ -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; +pub type S390xCallee = Callee; /// ABI Register usage diff --git a/cranelift/codegen/src/isa/s390x/inst/emit.rs b/cranelift/codegen/src/isa/s390x/inst/emit.rs index 346fb306e0..bbbfb1f318 100644 --- a/cranelift/codegen/src/isa/s390x/inst/emit.rs +++ b/cranelift/codegen/src/isa/s390x/inst/emit.rs @@ -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 for EmitState { - fn new(abi: &dyn ABICallee) -> Self { + fn new(abi: &Callee) -> Self { EmitState { virtual_sp_offset: 0, initial_sp_offset: abi.frame_size() as i64, diff --git a/cranelift/codegen/src/isa/s390x/inst/mod.rs b/cranelift/codegen/src/isa/s390x/inst/mod.rs index d13a69f204..c557cfe202 100644 --- a/cranelift/codegen/src/isa/s390x/inst/mod.rs +++ b/cranelift/codegen/src/isa/s390x/inst/mod.rs @@ -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 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 VReg>(&self, collector: &mut OperandCollector<'_, F>) { diff --git a/cranelift/codegen/src/isa/s390x/mod.rs b/cranelift/codegen/src/isa/s390x/mod.rs index e2165c585c..36f241c67e 100644 --- a/cranelift/codegen/src/isa/s390x/mod.rs +++ b/cranelift/codegen/src/isa/s390x/mod.rs @@ -58,7 +58,7 @@ impl S390xBackend { func: &Function, ) -> CodegenResult<(VCode, 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::(func, self, abi, &self.machine_env, emit_info) } } diff --git a/cranelift/codegen/src/isa/x64/abi.rs b/cranelift/codegen/src/isa/x64/abi.rs index d0c1137f6f..718ee85b2d 100644 --- a/cranelift/codegen/src/isa/x64/abi.rs +++ b/cranelift/codegen/src/isa/x64/abi.rs @@ -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; +pub(crate) type X64Callee = Callee; /// Support for the x64 ABI from the caller side (at a callsite). pub(crate) type X64ABICaller = ABICallerImpl; /// Implementation of ABI primitives for x64. -pub(crate) struct X64ABIMachineSpec; +pub struct X64ABIMachineSpec; impl IsaFlags for x64_settings::Flags {} diff --git a/cranelift/codegen/src/isa/x64/inst/mod.rs b/cranelift/codegen/src/isa/x64/inst/mod.rs index fbe790a0f7..7019d1187b 100644 --- a/cranelift/codegen/src/isa/x64/inst/mod.rs +++ b/cranelift/codegen/src/isa/x64/inst/mod.rs @@ -2157,6 +2157,8 @@ fn x64_get_operands VReg>(inst: &Inst, collector: &mut OperandCol // Instructions: misc functions and external interface impl MachInst for Inst { + type ABIMachineSpec = X64ABIMachineSpec; + fn get_operands VReg>(&self, collector: &mut OperandCollector<'_, F>) { x64_get_operands(&self, collector) } @@ -2460,7 +2462,7 @@ impl MachInstEmit for Inst { } impl MachInstEmitState for EmitState { - fn new(abi: &dyn ABICallee) -> Self { + fn new(abi: &Callee) -> Self { EmitState { virtual_sp_offset: 0, nominal_sp_to_fp: abi.frame_size() as i64, diff --git a/cranelift/codegen/src/isa/x64/mod.rs b/cranelift/codegen/src/isa/x64/mod.rs index 1205b661af..c6093e5b71 100644 --- a/cranelift/codegen/src/isa/x64/mod.rs +++ b/cranelift/codegen/src/isa/x64/mod.rs @@ -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::(&func, self, abi, &self.reg_env, emit_info) } } diff --git a/cranelift/codegen/src/machinst/abi.rs b/cranelift/codegen/src/machinst/abi.rs index 0fb8ac8511..6762988128 100644 --- a/cranelift/codegen/src/machinst/abi.rs +++ b/cranelift/codegen/src/machinst/abi.rs @@ -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 = 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; - - /// 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>); - - /// 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; - - /// The offsets of all dynamic stack slots (not spill slots) for debuginfo purposes. - fn dynamic_stackslot_offsets(&self) -> &PrimaryMap; - - /// 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>, - ) -> SmallInstVec; - - /// 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; - - /// 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>, - ) -> SmallInstVec; - - /// 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>); - - /// Get the address of a sized stackslot. - fn sized_stackslot_addr( - &self, - slot: StackSlot, - offset: u32, - into_reg: Writable, - ) -> Self::I; - - /// Get the address of a dynamic stackslot. - fn dynamic_stackslot_addr(&self, slot: DynamicStackSlot, into_reg: Writable) -> Self::I; - - /// Load from a spillslot. - fn load_spillslot( - &self, - slot: SpillSlot, - ty: Type, - into_reg: ValueRegs>, - ) -> SmallInstVec; - - /// Store to a spillslot. - fn store_spillslot( - &self, - slot: SpillSlot, - ty: Type, - from_reg: ValueRegs, - ) -> SmallInstVec; - - /// 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: &::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; - - /// 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; - - /// 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, 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 { diff --git a/cranelift/codegen/src/machinst/abi_impl.rs b/cranelift/codegen/src/machinst/abi_impl.rs index d248daab31..a650c0176d 100644 --- a/cranelift/codegen/src/machinst/abi_impl.rs +++ b/cranelift/codegen/src/machinst/abi_impl.rs @@ -697,7 +697,7 @@ impl ABISig { } /// ABI object for a function body. -pub struct ABICalleeImpl { +pub struct Callee { /// 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 ABICalleeImpl { +impl Callee { /// Create a new body ABI instance. pub fn new(f: &ir::Function, isa: &dyn TargetIsa, isa_flags: &M::F) -> CodegenResult { trace!("ABI: func signature {:?}", f.signature); @@ -1048,14 +1048,18 @@ fn ensure_struct_return_ptr_is_returned(sig: &ir::Signature) -> ir::Signature { sig } -impl ABICallee for ABICalleeImpl { - type I = M::I; - - fn signature(&self) -> &ir::Signature { +/// ### Pre-Regalloc Functions +/// +/// These methods of `Callee` may only be called before regalloc. +impl Callee { + /// Access the (possibly legalized) signature. + pub fn signature(&self) -> &ir::Signature { &self.ir_sig } - fn temps_needed(&self) -> Vec { + /// 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 { let mut temp_tys = vec![]; for arg in &self.sig.args { match arg { @@ -1074,7 +1078,10 @@ impl ABICallee for ABICalleeImpl { temp_tys } - fn init(&mut self, temps: Vec>) { + /// 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>) { let mut temps_iter = temps.into_iter(); for arg in &self.sig.args { let temp = match arg { @@ -1091,45 +1098,40 @@ impl ABICallee for ABICalleeImpl { } } - 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 { + /// The offsets of all sized stack slots (not spill slots) for debuginfo purposes. + pub fn sized_stackslot_offsets(&self) -> &PrimaryMap { &self.sized_stackslots } - fn dynamic_stackslot_offsets(&self) -> &PrimaryMap { + /// The offsets of all dynamic stack slots (not spill slots) for debuginfo purposes. + pub fn dynamic_stackslot_offsets(&self) -> &PrimaryMap { &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>, - ) -> SmallInstVec { + ) -> SmallInstVec { let mut insts = smallvec![]; let mut copy_arg_slot_to_reg = |slot: &ABIArgSlot, into_reg: &Writable| { match slot { @@ -1219,15 +1221,19 @@ impl ABICallee for ABICalleeImpl { 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>, - ) -> SmallInstVec { + ) -> SmallInstVec { let mut ret = smallvec![]; let word_bits = M::word_bits() as u8; match &self.sig.rets[idx] { @@ -1313,7 +1319,12 @@ impl ABICallee for ABICalleeImpl { ret } - fn gen_retval_area_setup(&self) -> Option { + /// 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 { 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 ABICallee for ABICalleeImpl { } } - 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 ABICallee for ABICalleeImpl { 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>) { - 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, - ) -> 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 ABICallee for ABICalleeImpl { } /// Produce an instruction that computes a dynamic stackslot address. - fn dynamic_stackslot_addr(&self, slot: DynamicStackSlot, into_reg: Writable) -> Self::I { + pub fn dynamic_stackslot_addr(&self, slot: DynamicStackSlot, into_reg: Writable) -> 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 ABICallee for ABICalleeImpl { ) } - 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>, - ) -> SmallInstVec { + ) -> SmallInstVec { // 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 ABICallee for ABICalleeImpl { } /// Store to a spillslot. - fn store_spillslot( + pub fn store_spillslot( &self, slot: SpillSlot, ty: Type, from_regs: ValueRegs, - ) -> SmallInstVec { + ) -> SmallInstVec { // 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 ABICallee for ABICalleeImpl { gen_store_stack_multi::(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 Callee { + /// 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>) { + 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: &::State, + state: &::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 ABICallee for ABICalleeImpl { StackMap::from_slice(&bits[..]) } - fn gen_prologue(&mut self) -> SmallInstVec { + /// 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 { 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 ABICallee for ABICalleeImpl { insts } - fn gen_epilogue(&self) -> SmallInstVec { + /// 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 { let mut insts = smallvec![]; // Restore clobbered registers. @@ -1555,16 +1585,22 @@ impl ABICallee for ABICalleeImpl { 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 ABICallee for ABICalleeImpl { 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, 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, from_slot: SpillSlot) -> M::I { + let ty = M::I::canonical_type_for_rc(to_reg.to_reg().class()); self.load_spillslot( from_slot, ty, diff --git a/cranelift/codegen/src/machinst/compile.rs b/cranelift/codegen/src/machinst/compile.rs index 9e4e79b0c8..003061cdf1 100644 --- a/cranelift/codegen/src/machinst/compile.rs +++ b/cranelift/codegen/src/machinst/compile.rs @@ -14,7 +14,7 @@ use regalloc2::{self, MachineEnv}; pub fn compile( f: &Function, b: &B, - abi: Box>, + abi: Callee<<::MInst as MachInst>::ABIMachineSpec>, machine_env: &MachineEnv, emit_info: ::Info, ) -> CodegenResult<(VCode, regalloc2::Output)> { diff --git a/cranelift/codegen/src/machinst/lower.rs b/cranelift/codegen/src/machinst/lower.rs index 73e68c5afd..7ec52eea4a 100644 --- a/cranelift/codegen/src/machinst/lower.rs +++ b/cranelift/codegen/src/machinst/lower.rs @@ -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>, + abi: Callee, emit_info: I::Info, block_order: BlockLoweringOrder, ) -> CodegenResult> { @@ -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 { + /// Get the `Callee`. + pub fn abi(&mut self) -> &mut Callee { self.vcode.abi() } diff --git a/cranelift/codegen/src/machinst/mod.rs b/cranelift/codegen/src/machinst/mod.rs index a91dd9ef77..52d3557e3c 100644 --- a/cranelift/codegen/src/machinst/mod.rs +++ b/cranelift/codegen/src/machinst/mod.rs @@ -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; + /// Return the registers referenced by this machine instruction along with /// the modes of reference (use, def, modify). fn get_operands 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: Default + Clone + Debug { +pub trait MachInstEmitState: Default + Clone + Debug { /// Create a new emission state given the ABI object. - fn new(abi: &dyn ABICallee) -> Self; + fn new(abi: &Callee) -> Self; /// Update the emission state before emitting an instruction that is a /// safepoint. fn pre_safepoint(&mut self, _stack_map: StackMap) {} diff --git a/cranelift/codegen/src/machinst/vcode.rs b/cranelift/codegen/src/machinst/vcode.rs index c6e37b8517..bcb0e02721 100644 --- a/cranelift/codegen/src/machinst/vcode.rs +++ b/cranelift/codegen/src/machinst/vcode.rs @@ -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 { block_order: BlockLoweringOrder, /// ABI object. - abi: Box>, + abi: Callee, /// 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 VCodeBuilder { /// Create a new VCodeBuilder. pub fn new( - abi: Box>, + abi: Callee, emit_info: I::Info, block_order: BlockLoweringOrder, constants: VCodeConstants, @@ -301,8 +300,8 @@ impl VCodeBuilder { } /// Access the ABI object. - pub fn abi(&mut self) -> &mut dyn ABICallee { - &mut *self.vcode.abi + pub fn abi(&mut self) -> &mut Callee { + &mut self.vcode.abi } /// Access to the BlockLoweringOrder object. @@ -626,7 +625,7 @@ fn is_reftype(ty: Type) -> bool { impl VCode { /// New empty VCode. fn new( - abi: Box>, + abi: Callee, emit_info: I::Info, block_order: BlockLoweringOrder, constants: VCodeConstants, @@ -797,7 +796,7 @@ impl VCode { 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();