Merge pull request #2356 from uweigand/abi-outgoingargs
machinst ABI: Support for accumulating outgoing args
This commit is contained in:
@@ -513,6 +513,7 @@ impl ABIMachineSpec for AArch64MachineDeps {
|
|||||||
_: &settings::Flags,
|
_: &settings::Flags,
|
||||||
clobbers: &Set<Writable<RealReg>>,
|
clobbers: &Set<Writable<RealReg>>,
|
||||||
fixed_frame_storage_size: u32,
|
fixed_frame_storage_size: u32,
|
||||||
|
_outgoing_args_size: u32,
|
||||||
) -> (u64, SmallVec<[Inst; 16]>) {
|
) -> (u64, SmallVec<[Inst; 16]>) {
|
||||||
let mut insts = SmallVec::new();
|
let mut insts = SmallVec::new();
|
||||||
let (clobbered_int, clobbered_vec) = get_regs_saved_in_prologue(call_conv, clobbers);
|
let (clobbered_int, clobbered_vec) = get_regs_saved_in_prologue(call_conv, clobbers);
|
||||||
@@ -565,6 +566,7 @@ impl ABIMachineSpec for AArch64MachineDeps {
|
|||||||
flags: &settings::Flags,
|
flags: &settings::Flags,
|
||||||
clobbers: &Set<Writable<RealReg>>,
|
clobbers: &Set<Writable<RealReg>>,
|
||||||
_fixed_frame_storage_size: u32,
|
_fixed_frame_storage_size: u32,
|
||||||
|
_outgoing_args_size: u32,
|
||||||
) -> SmallVec<[Inst; 16]> {
|
) -> SmallVec<[Inst; 16]> {
|
||||||
let mut insts = SmallVec::new();
|
let mut insts = SmallVec::new();
|
||||||
let (clobbered_int, clobbered_vec) = get_regs_saved_in_prologue(call_conv, clobbers);
|
let (clobbered_int, clobbered_vec) = get_regs_saved_in_prologue(call_conv, clobbers);
|
||||||
|
|||||||
@@ -313,6 +313,7 @@ impl ABIMachineSpec for Arm32MachineDeps {
|
|||||||
_flags: &settings::Flags,
|
_flags: &settings::Flags,
|
||||||
clobbers: &Set<Writable<RealReg>>,
|
clobbers: &Set<Writable<RealReg>>,
|
||||||
fixed_frame_storage_size: u32,
|
fixed_frame_storage_size: u32,
|
||||||
|
_outgoing_args_size: u32,
|
||||||
) -> (u64, SmallVec<[Inst; 16]>) {
|
) -> (u64, SmallVec<[Inst; 16]>) {
|
||||||
let mut insts = SmallVec::new();
|
let mut insts = SmallVec::new();
|
||||||
if fixed_frame_storage_size > 0 {
|
if fixed_frame_storage_size > 0 {
|
||||||
@@ -342,6 +343,7 @@ impl ABIMachineSpec for Arm32MachineDeps {
|
|||||||
_flags: &settings::Flags,
|
_flags: &settings::Flags,
|
||||||
clobbers: &Set<Writable<RealReg>>,
|
clobbers: &Set<Writable<RealReg>>,
|
||||||
_fixed_frame_storage_size: u32,
|
_fixed_frame_storage_size: u32,
|
||||||
|
_outgoing_args_size: u32,
|
||||||
) -> SmallVec<[Inst; 16]> {
|
) -> SmallVec<[Inst; 16]> {
|
||||||
let mut insts = SmallVec::new();
|
let mut insts = SmallVec::new();
|
||||||
let clobbered_vec = get_callee_saves(clobbers);
|
let clobbered_vec = get_callee_saves(clobbers);
|
||||||
|
|||||||
@@ -395,6 +395,7 @@ impl ABIMachineSpec for X64ABIMachineSpec {
|
|||||||
_: &settings::Flags,
|
_: &settings::Flags,
|
||||||
clobbers: &Set<Writable<RealReg>>,
|
clobbers: &Set<Writable<RealReg>>,
|
||||||
fixed_frame_storage_size: u32,
|
fixed_frame_storage_size: u32,
|
||||||
|
_outgoing_args_size: u32,
|
||||||
) -> (u64, SmallVec<[Self::I; 16]>) {
|
) -> (u64, SmallVec<[Self::I; 16]>) {
|
||||||
let mut insts = SmallVec::new();
|
let mut insts = SmallVec::new();
|
||||||
// Find all clobbered registers that are callee-save. These are only I64
|
// Find all clobbered registers that are callee-save. These are only I64
|
||||||
@@ -443,6 +444,7 @@ impl ABIMachineSpec for X64ABIMachineSpec {
|
|||||||
flags: &settings::Flags,
|
flags: &settings::Flags,
|
||||||
clobbers: &Set<Writable<RealReg>>,
|
clobbers: &Set<Writable<RealReg>>,
|
||||||
_fixed_frame_storage_size: u32,
|
_fixed_frame_storage_size: u32,
|
||||||
|
_outgoing_args_size: u32,
|
||||||
) -> SmallVec<[Self::I; 16]> {
|
) -> SmallVec<[Self::I; 16]> {
|
||||||
let mut insts = SmallVec::new();
|
let mut insts = SmallVec::new();
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,12 @@ pub trait ABICallee {
|
|||||||
/// lowering context exists.
|
/// lowering context exists.
|
||||||
fn init(&mut self, maybe_tmp: Option<Writable<Reg>>);
|
fn init(&mut self, maybe_tmp: Option<Writable<Reg>>);
|
||||||
|
|
||||||
|
/// 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.
|
/// Get the settings controlling this function's compilation.
|
||||||
fn flags(&self) -> &settings::Flags;
|
fn flags(&self) -> &settings::Flags;
|
||||||
|
|
||||||
@@ -203,6 +209,13 @@ pub trait ABICaller {
|
|||||||
/// Emit code to post-adjust the satck, after call return and return-value copies.
|
/// Emit code to post-adjust the satck, after call return and return-value copies.
|
||||||
fn emit_stack_post_adjust<C: LowerCtx<I = Self::I>>(&self, ctx: &mut C);
|
fn emit_stack_post_adjust<C: LowerCtx<I = Self::I>>(&self, ctx: &mut C);
|
||||||
|
|
||||||
|
/// 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<C: LowerCtx<I = Self::I>>(&self, ctx: &mut C);
|
||||||
|
|
||||||
/// Emit the call itself.
|
/// Emit the call itself.
|
||||||
///
|
///
|
||||||
/// The returned instruction should have proper use- and def-sets according
|
/// The returned instruction should have proper use- and def-sets according
|
||||||
|
|||||||
@@ -329,6 +329,7 @@ pub trait ABIMachineSpec {
|
|||||||
flags: &settings::Flags,
|
flags: &settings::Flags,
|
||||||
clobbers: &Set<Writable<RealReg>>,
|
clobbers: &Set<Writable<RealReg>>,
|
||||||
fixed_frame_storage_size: u32,
|
fixed_frame_storage_size: u32,
|
||||||
|
outgoing_args_size: u32,
|
||||||
) -> (u64, SmallVec<[Self::I; 16]>);
|
) -> (u64, SmallVec<[Self::I; 16]>);
|
||||||
|
|
||||||
/// Generate a clobber-restore sequence. This sequence should perform the
|
/// Generate a clobber-restore sequence. This sequence should perform the
|
||||||
@@ -340,6 +341,7 @@ pub trait ABIMachineSpec {
|
|||||||
flags: &settings::Flags,
|
flags: &settings::Flags,
|
||||||
clobbers: &Set<Writable<RealReg>>,
|
clobbers: &Set<Writable<RealReg>>,
|
||||||
fixed_frame_storage_size: u32,
|
fixed_frame_storage_size: u32,
|
||||||
|
outgoing_args_size: u32,
|
||||||
) -> SmallVec<[Self::I; 16]>;
|
) -> SmallVec<[Self::I; 16]>;
|
||||||
|
|
||||||
/// Generate a call instruction/sequence. This method is provided one
|
/// Generate a call instruction/sequence. This method is provided one
|
||||||
@@ -435,6 +437,8 @@ pub struct ABICalleeImpl<M: ABIMachineSpec> {
|
|||||||
stackslots: Vec<u32>,
|
stackslots: Vec<u32>,
|
||||||
/// Total stack size of all stackslots.
|
/// Total stack size of all stackslots.
|
||||||
stackslots_size: u32,
|
stackslots_size: u32,
|
||||||
|
/// Stack size to be reserved for outgoing arguments.
|
||||||
|
outgoing_args_size: u32,
|
||||||
/// Clobbered registers, from regalloc.
|
/// Clobbered registers, from regalloc.
|
||||||
clobbered: Set<Writable<RealReg>>,
|
clobbered: Set<Writable<RealReg>>,
|
||||||
/// Total number of spillslots, from regalloc.
|
/// Total number of spillslots, from regalloc.
|
||||||
@@ -527,6 +531,7 @@ impl<M: ABIMachineSpec> ABICalleeImpl<M> {
|
|||||||
sig,
|
sig,
|
||||||
stackslots,
|
stackslots,
|
||||||
stackslots_size: stack_offset,
|
stackslots_size: stack_offset,
|
||||||
|
outgoing_args_size: 0,
|
||||||
clobbered: Set::empty(),
|
clobbered: Set::empty(),
|
||||||
spillslots: None,
|
spillslots: None,
|
||||||
fixed_frame_storage_size: 0,
|
fixed_frame_storage_size: 0,
|
||||||
@@ -690,6 +695,12 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
fn flags(&self) -> &settings::Flags {
|
||||||
&self.flags
|
&self.flags
|
||||||
}
|
}
|
||||||
@@ -978,11 +989,13 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
|
|||||||
&self.flags,
|
&self.flags,
|
||||||
&self.clobbered,
|
&self.clobbered,
|
||||||
self.fixed_frame_storage_size,
|
self.fixed_frame_storage_size,
|
||||||
|
self.outgoing_args_size,
|
||||||
);
|
);
|
||||||
insts.extend(clobber_insts);
|
insts.extend(clobber_insts);
|
||||||
|
|
||||||
if clobber_size > 0 {
|
let sp_adj = self.outgoing_args_size as i32 + clobber_size as i32;
|
||||||
insts.push(M::gen_nominal_sp_adj(clobber_size as i32));
|
if sp_adj > 0 {
|
||||||
|
insts.push(M::gen_nominal_sp_adj(sp_adj));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.total_frame_size = Some(total_stacksize);
|
self.total_frame_size = Some(total_stacksize);
|
||||||
@@ -998,6 +1011,7 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> {
|
|||||||
&self.flags,
|
&self.flags,
|
||||||
&self.clobbered,
|
&self.clobbered,
|
||||||
self.fixed_frame_storage_size,
|
self.fixed_frame_storage_size,
|
||||||
|
self.outgoing_args_size,
|
||||||
));
|
));
|
||||||
|
|
||||||
// N.B.: we do *not* emit a nominal SP adjustment here, because (i) there will be no
|
// N.B.: we do *not* emit a nominal SP adjustment here, because (i) there will be no
|
||||||
@@ -1180,6 +1194,11 @@ impl<M: ABIMachineSpec> ABICaller for ABICallerImpl<M> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn accumulate_outgoing_args_size<C: LowerCtx<I = Self::I>>(&self, ctx: &mut C) {
|
||||||
|
let off = self.sig.stack_arg_space + self.sig.stack_ret_space;
|
||||||
|
ctx.abi().accumulate_outgoing_args_size(off as u32);
|
||||||
|
}
|
||||||
|
|
||||||
fn emit_stack_pre_adjust<C: LowerCtx<I = Self::I>>(&self, ctx: &mut C) {
|
fn emit_stack_pre_adjust<C: LowerCtx<I = Self::I>>(&self, ctx: &mut C) {
|
||||||
let off = self.sig.stack_arg_space + self.sig.stack_ret_space;
|
let off = self.sig.stack_arg_space + self.sig.stack_ret_space;
|
||||||
adjust_stack_and_nominal_sp::<M, C>(ctx, off as i32, /* is_sub = */ true)
|
adjust_stack_and_nominal_sp::<M, C>(ctx, off as i32, /* is_sub = */ true)
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ pub trait LowerCtx {
|
|||||||
// Function-level queries:
|
// Function-level queries:
|
||||||
|
|
||||||
/// Get the `ABICallee`.
|
/// Get the `ABICallee`.
|
||||||
fn abi(&mut self) -> &dyn ABICallee<I = Self::I>;
|
fn abi(&mut self) -> &mut dyn ABICallee<I = Self::I>;
|
||||||
/// Get the (virtual) register that receives the return value. A return
|
/// Get the (virtual) register that receives the return value. A return
|
||||||
/// instruction should lower into a sequence that fills this register. (Why
|
/// instruction should lower into a sequence that fills this register. (Why
|
||||||
/// not allow the backend to specify its own result register for the return?
|
/// not allow the backend to specify its own result register for the return?
|
||||||
@@ -850,7 +850,7 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
|
|||||||
impl<'func, I: VCodeInst> LowerCtx for Lower<'func, I> {
|
impl<'func, I: VCodeInst> LowerCtx for Lower<'func, I> {
|
||||||
type I = I;
|
type I = I;
|
||||||
|
|
||||||
fn abi(&mut self) -> &dyn ABICallee<I = I> {
|
fn abi(&mut self) -> &mut dyn ABICallee<I = I> {
|
||||||
self.vcode.abi()
|
self.vcode.abi()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user