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