Cranelift: Remove the ABICaller trait (#4711)

* Cranelift: Remove the `ABICaller` trait

It has only one implementation: the `ABICallerImpl` struct. We can just use that
directly rather than having extra, unnecessary layers of generics and abstractions.

* Cranelift: Rename `ABICallerImpl` to `Caller`
This commit is contained in:
Nick Fitzgerald
2022-08-15 13:41:08 -07:00
committed by GitHub
parent 1d0f6fa4fb
commit e0d4934ef4
7 changed files with 53 additions and 112 deletions

View File

@@ -24,7 +24,7 @@ use smallvec::{smallvec, SmallVec};
pub(crate) type AArch64Callee = Callee<AArch64MachineDeps>; pub(crate) type AArch64Callee = Callee<AArch64MachineDeps>;
/// Support for the AArch64 ABI from the caller side (at a callsite). /// Support for the AArch64 ABI from the caller side (at a callsite).
pub(crate) type AArch64ABICaller = ABICallerImpl<AArch64MachineDeps>; pub(crate) type AArch64Caller = Caller<AArch64MachineDeps>;
/// This is the limit for the size of argument and return-value areas on the /// This is the limit for the size of argument and return-value areas on the
/// stack. We place a reasonable limit here to avoid integer overflow issues /// stack. We place a reasonable limit here to avoid integer overflow issues

View File

@@ -605,7 +605,7 @@ pub(crate) fn lower_insn_to_regs(
assert!(inputs.len() == sig.params.len()); assert!(inputs.len() == sig.params.len());
assert!(outputs.len() == sig.returns.len()); assert!(outputs.len() == sig.returns.len());
( (
AArch64ABICaller::from_func(sig, &extname, dist, caller_conv, flags)?, AArch64Caller::from_func(sig, &extname, dist, caller_conv, flags)?,
&inputs[..], &inputs[..],
) )
} }
@@ -615,7 +615,7 @@ pub(crate) fn lower_insn_to_regs(
assert!(inputs.len() - 1 == sig.params.len()); assert!(inputs.len() - 1 == sig.params.len());
assert!(outputs.len() == sig.returns.len()); assert!(outputs.len() == sig.returns.len());
( (
AArch64ABICaller::from_ptr(sig, ptr, op, caller_conv, flags)?, AArch64Caller::from_ptr(sig, ptr, op, caller_conv, flags)?,
&inputs[1..], &inputs[1..],
) )
} }

View File

@@ -24,7 +24,7 @@ static STACK_ARG_RET_SIZE_LIMIT: u64 = 128 * 1024 * 1024;
pub(crate) type X64Callee = Callee<X64ABIMachineSpec>; pub(crate) type X64Callee = Callee<X64ABIMachineSpec>;
/// Support for the x64 ABI from the caller side (at a callsite). /// Support for the x64 ABI from the caller side (at a callsite).
pub(crate) type X64ABICaller = ABICallerImpl<X64ABIMachineSpec>; pub(crate) type X64Caller = Caller<X64ABIMachineSpec>;
/// Implementation of ABI primitives for x64. /// Implementation of ABI primitives for x64.
pub struct X64ABIMachineSpec; pub struct X64ABIMachineSpec;

View File

@@ -279,7 +279,7 @@ fn emit_vm_call(
let sig = libcall.signature(call_conv); let sig = libcall.signature(call_conv);
let caller_conv = ctx.abi().call_conv(); let caller_conv = ctx.abi().call_conv();
let mut abi = X64ABICaller::from_func(&sig, &extname, dist, caller_conv, flags)?; let mut abi = X64Caller::from_func(&sig, &extname, dist, caller_conv, flags)?;
abi.emit_stack_pre_adjust(ctx); abi.emit_stack_pre_adjust(ctx);

View File

@@ -24,14 +24,14 @@ use crate::{
settings::Flags, settings::Flags,
unwind::UnwindInst, unwind::UnwindInst,
x64::{ x64::{
abi::{X64ABICaller, X64ABIMachineSpec}, abi::{X64ABIMachineSpec, X64Caller},
inst::{args::*, regs, CallInfo}, inst::{args::*, regs, CallInfo},
settings::Flags as IsaFlags, settings::Flags as IsaFlags,
}, },
}, },
machinst::{ machinst::{
isle::*, valueregs, ABICaller, InsnInput, InsnOutput, Lower, MachAtomicRmwOp, MachInst, isle::*, valueregs, InsnInput, InsnOutput, Lower, MachAtomicRmwOp, MachInst, VCodeConstant,
VCodeConstant, VCodeConstantData, VCodeConstantData,
}, },
}; };
use regalloc2::PReg; use regalloc2::PReg;
@@ -673,7 +673,7 @@ impl Context for IsleContext<'_, '_, MInst, Flags, IsaFlags, 6> {
let sig = &self.lower_ctx.dfg().signatures[sig_ref]; let sig = &self.lower_ctx.dfg().signatures[sig_ref];
let num_rets = sig.returns.len(); let num_rets = sig.returns.len();
let abi = ABISig::from_func_sig::<X64ABIMachineSpec>(sig, self.flags).unwrap(); let abi = ABISig::from_func_sig::<X64ABIMachineSpec>(sig, self.flags).unwrap();
let caller = X64ABICaller::from_func(sig, &extname, dist, caller_conv, self.flags).unwrap(); let caller = X64Caller::from_func(sig, &extname, dist, caller_conv, self.flags).unwrap();
assert_eq!( assert_eq!(
inputs.len(&self.lower_ctx.dfg().value_lists) - off, inputs.len(&self.lower_ctx.dfg().value_lists) - off,
@@ -695,8 +695,7 @@ impl Context for IsleContext<'_, '_, MInst, Flags, IsaFlags, 6> {
let num_rets = sig.returns.len(); let num_rets = sig.returns.len();
let abi = ABISig::from_func_sig::<X64ABIMachineSpec>(sig, self.flags).unwrap(); let abi = ABISig::from_func_sig::<X64ABIMachineSpec>(sig, self.flags).unwrap();
let caller = let caller =
X64ABICaller::from_ptr(sig, ptr, Opcode::CallIndirect, caller_conv, self.flags) X64Caller::from_ptr(sig, ptr, Opcode::CallIndirect, caller_conv, self.flags).unwrap();
.unwrap();
assert_eq!( assert_eq!(
inputs.len(&self.lower_ctx.dfg().value_lists) - off, inputs.len(&self.lower_ctx.dfg().value_lists) - off,
@@ -807,7 +806,7 @@ impl IsleContext<'_, '_, MInst, Flags, IsaFlags, 6> {
&mut self, &mut self,
abi: ABISig, abi: ABISig,
num_rets: usize, num_rets: usize,
mut caller: X64ABICaller, mut caller: X64Caller,
(inputs, off): ValueSlice, (inputs, off): ValueSlice,
) -> InstOutput { ) -> InstOutput {
caller.emit_stack_pre_adjust(self.lower_ctx); caller.emit_stack_pre_adjust(self.lower_ctx);

View File

@@ -1,83 +1,7 @@
//! ABI definitions. //! ABI definitions.
use crate::machinst::*;
use smallvec::SmallVec; use smallvec::SmallVec;
/// A small vector of instructions (with some reasonable size); appropriate for /// A small vector of instructions (with some reasonable size); appropriate for
/// a small fixed sequence implementing one operation. /// a small fixed sequence implementing one operation.
pub type SmallInstVec<I> = SmallVec<[I; 4]>; pub type SmallInstVec<I> = SmallVec<[I; 4]>;
/// Trait implemented by an object that tracks ABI-related state and can
/// generate code while emitting a *call* to a function.
///
/// An instance of this trait returns information for a *particular*
/// callsite. It will usually be computed from the called function's
/// signature.
///
/// 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 {
/// The instruction type for the ISA associated with this ABI.
type I: VCodeInst;
/// Get the number of arguments expected.
fn num_args(&self) -> usize;
/// Emit a copy of an argument value from a source register, prior to the call.
/// For large arguments with associated stack buffer, this may load the address
/// of the buffer into the argument register, if required by the ABI.
fn emit_copy_regs_to_arg(&self, ctx: &mut Lower<Self::I>, idx: usize, from_reg: ValueRegs<Reg>);
/// Emit a copy of a large argument into its associated stack buffer, if any.
/// We must be careful to perform all these copies (as necessary) before setting
/// up the argument registers, since we may have to invoke memcpy(), which could
/// clobber any registers already set up. The back-end should call this routine
/// for all arguments before calling emit_copy_regs_to_arg for all arguments.
fn emit_copy_regs_to_buffer(
&self,
ctx: &mut Lower<Self::I>,
idx: usize,
from_reg: ValueRegs<Reg>,
);
/// Emit a copy a return value into a destination register, after the call returns.
fn emit_copy_retval_to_regs(
&self,
ctx: &mut Lower<Self::I>,
idx: usize,
into_reg: ValueRegs<Writable<Reg>>,
);
/// Emit code to pre-adjust the stack, prior to argument copies and call.
fn emit_stack_pre_adjust(&self, ctx: &mut Lower<Self::I>);
/// Emit code to post-adjust the satck, after call return and return-value copies.
fn emit_stack_post_adjust(&self, ctx: &mut Lower<Self::I>);
/// Accumulate outgoing arguments. This ensures that the caller (as
/// identified via the CTX argument) allocates enough space in the
/// prologue to hold all arguments and return values for this call.
/// There is no code emitted at the call site, everything is done
/// in the caller's function prologue.
fn accumulate_outgoing_args_size(&self, ctx: &mut Lower<Self::I>);
/// Emit the call itself.
///
/// The returned instruction should have proper use- and def-sets according
/// to the argument registers, return-value registers, and clobbered
/// registers for this function signature in this ABI.
///
/// (Arg registers are uses, and retval registers are defs. Clobbered
/// registers are also logically defs, but should never be read; their
/// values are "defined" (to the regalloc) but "undefined" in every other
/// sense.)
///
/// This function should only be called once, as it is allowed to re-use
/// parts of the ABICaller object in emitting instructions.
fn emit_call(&mut self, ctx: &mut Lower<Self::I>);
}

View File

@@ -1638,7 +1638,7 @@ impl<M: ABIMachineSpec> Callee<M> {
} }
/// ABI object for a callsite. /// ABI object for a callsite.
pub struct ABICallerImpl<M: ABIMachineSpec> { pub struct Caller<M: ABIMachineSpec> {
/// The called function's signature. /// The called function's signature.
sig: ABISig, sig: ABISig,
/// All uses for the callsite, i.e., function args. /// All uses for the callsite, i.e., function args.
@@ -1668,7 +1668,7 @@ pub enum CallDest {
Reg(Reg), Reg(Reg),
} }
impl<M: ABIMachineSpec> ABICallerImpl<M> { impl<M: ABIMachineSpec> Caller<M> {
/// Create a callsite ABI object for a call directly to the specified function. /// Create a callsite ABI object for a call directly to the specified function.
pub fn from_func( pub fn from_func(
sig: &ir::Signature, sig: &ir::Signature,
@@ -1676,11 +1676,11 @@ impl<M: ABIMachineSpec> ABICallerImpl<M> {
dist: RelocDistance, dist: RelocDistance,
caller_conv: isa::CallConv, caller_conv: isa::CallConv,
flags: &settings::Flags, flags: &settings::Flags,
) -> CodegenResult<ABICallerImpl<M>> { ) -> CodegenResult<Caller<M>> {
let ir_sig = ensure_struct_return_ptr_is_returned(sig); let ir_sig = ensure_struct_return_ptr_is_returned(sig);
let sig = ABISig::from_func_sig::<M>(&ir_sig, flags)?; let sig = ABISig::from_func_sig::<M>(&ir_sig, flags)?;
let (uses, defs, clobbers) = sig.call_uses_defs_clobbers::<M>(); let (uses, defs, clobbers) = sig.call_uses_defs_clobbers::<M>();
Ok(ABICallerImpl { Ok(Caller {
sig, sig,
uses, uses,
defs, defs,
@@ -1701,11 +1701,11 @@ impl<M: ABIMachineSpec> ABICallerImpl<M> {
opcode: ir::Opcode, opcode: ir::Opcode,
caller_conv: isa::CallConv, caller_conv: isa::CallConv,
flags: &settings::Flags, flags: &settings::Flags,
) -> CodegenResult<ABICallerImpl<M>> { ) -> CodegenResult<Caller<M>> {
let ir_sig = ensure_struct_return_ptr_is_returned(sig); let ir_sig = ensure_struct_return_ptr_is_returned(sig);
let sig = ABISig::from_func_sig::<M>(&ir_sig, flags)?; let sig = ABISig::from_func_sig::<M>(&ir_sig, flags)?;
let (uses, defs, clobbers) = sig.call_uses_defs_clobbers::<M>(); let (uses, defs, clobbers) = sig.call_uses_defs_clobbers::<M>();
Ok(ABICallerImpl { Ok(Caller {
sig, sig,
uses, uses,
defs, defs,
@@ -1730,10 +1730,9 @@ fn adjust_stack_and_nominal_sp<M: ABIMachineSpec>(ctx: &mut Lower<M::I>, off: i3
ctx.emit(M::gen_nominal_sp_adj(-amt)); ctx.emit(M::gen_nominal_sp_adj(-amt));
} }
impl<M: ABIMachineSpec> ABICaller for ABICallerImpl<M> { impl<M: ABIMachineSpec> Caller<M> {
type I = M::I; /// Get the number of arguments expected.
pub fn num_args(&self) -> usize {
fn num_args(&self) -> usize {
if self.sig.stack_ret_arg.is_some() { if self.sig.stack_ret_arg.is_some() {
self.sig.args.len() - 1 self.sig.args.len() - 1
} else { } else {
@@ -1741,24 +1740,26 @@ impl<M: ABIMachineSpec> ABICaller for ABICallerImpl<M> {
} }
} }
fn accumulate_outgoing_args_size(&self, ctx: &mut Lower<Self::I>) { /// Emit code to pre-adjust the stack, prior to argument copies and call.
let off = self.sig.sized_stack_arg_space + self.sig.sized_stack_ret_space; pub fn emit_stack_pre_adjust(&self, ctx: &mut Lower<M::I>) {
ctx.abi().accumulate_outgoing_args_size(off as u32);
}
fn emit_stack_pre_adjust(&self, ctx: &mut Lower<Self::I>) {
let off = self.sig.sized_stack_arg_space + self.sig.sized_stack_ret_space; let off = self.sig.sized_stack_arg_space + self.sig.sized_stack_ret_space;
adjust_stack_and_nominal_sp::<M>(ctx, off as i32, /* is_sub = */ true) adjust_stack_and_nominal_sp::<M>(ctx, off as i32, /* is_sub = */ true)
} }
fn emit_stack_post_adjust(&self, ctx: &mut Lower<Self::I>) { /// Emit code to post-adjust the satck, after call return and return-value copies.
pub fn emit_stack_post_adjust(&self, ctx: &mut Lower<M::I>) {
let off = self.sig.sized_stack_arg_space + self.sig.sized_stack_ret_space; let off = self.sig.sized_stack_arg_space + self.sig.sized_stack_ret_space;
adjust_stack_and_nominal_sp::<M>(ctx, off as i32, /* is_sub = */ false) adjust_stack_and_nominal_sp::<M>(ctx, off as i32, /* is_sub = */ false)
} }
fn emit_copy_regs_to_buffer( /// Emit a copy of a large argument into its associated stack buffer, if any.
/// We must be careful to perform all these copies (as necessary) before setting
/// up the argument registers, since we may have to invoke memcpy(), which could
/// clobber any registers already set up. The back-end should call this routine
/// for all arguments before calling emit_copy_regs_to_arg for all arguments.
pub fn emit_copy_regs_to_buffer(
&self, &self,
ctx: &mut Lower<Self::I>, ctx: &mut Lower<M::I>,
idx: usize, idx: usize,
from_regs: ValueRegs<Reg>, from_regs: ValueRegs<Reg>,
) { ) {
@@ -1788,9 +1789,12 @@ impl<M: ABIMachineSpec> ABICaller for ABICallerImpl<M> {
} }
} }
fn emit_copy_regs_to_arg( /// Emit a copy of an argument value from a source register, prior to the call.
/// For large arguments with associated stack buffer, this may load the address
/// of the buffer into the argument register, if required by the ABI.
pub fn emit_copy_regs_to_arg(
&self, &self,
ctx: &mut Lower<Self::I>, ctx: &mut Lower<M::I>,
idx: usize, idx: usize,
from_regs: ValueRegs<Reg>, from_regs: ValueRegs<Reg>,
) { ) {
@@ -1871,9 +1875,10 @@ impl<M: ABIMachineSpec> ABICaller for ABICallerImpl<M> {
} }
} }
fn emit_copy_retval_to_regs( /// Emit a copy a return value into a destination register, after the call returns.
pub fn emit_copy_retval_to_regs(
&self, &self,
ctx: &mut Lower<Self::I>, ctx: &mut Lower<M::I>,
idx: usize, idx: usize,
into_regs: ValueRegs<Writable<Reg>>, into_regs: ValueRegs<Writable<Reg>>,
) { ) {
@@ -1907,7 +1912,20 @@ impl<M: ABIMachineSpec> ABICaller for ABICallerImpl<M> {
} }
} }
fn emit_call(&mut self, ctx: &mut Lower<Self::I>) { /// Emit the call itself.
///
/// The returned instruction should have proper use- and def-sets according
/// to the argument registers, return-value registers, and clobbered
/// registers for this function signature in this ABI.
///
/// (Arg registers are uses, and retval registers are defs. Clobbered
/// registers are also logically defs, but should never be read; their
/// values are "defined" (to the regalloc) but "undefined" in every other
/// sense.)
///
/// This function should only be called once, as it is allowed to re-use
/// parts of the `Caller` object in emitting instructions.
pub fn emit_call(&mut self, ctx: &mut Lower<M::I>) {
let (uses, defs) = ( let (uses, defs) = (
mem::replace(&mut self.uses, Default::default()), mem::replace(&mut self.uses, Default::default()),
mem::replace(&mut self.defs, Default::default()), mem::replace(&mut self.defs, Default::default()),