@ -522,8 +522,8 @@ pub trait ABIMachineSpec {
/// Generate the usual frame-setup sequence for this architecture: e.g.,
/// Generate the usual frame-setup sequence for this architecture: e.g.,
/// `push rbp / mov rbp, rsp` on x86-64, or `stp fp, lr, [sp, #-16]!` on
/// `push rbp / mov rbp, rsp` on x86-64, or `stp fp, lr, [sp, #-16]!` on
/// AArch64.
/// AArch64. Return generated instructions and stack size of the setup area.
fn gen_prologue_frame_setup ( flags : & settings ::Flags ) -> SmallInstVec < Self ::I > ;
fn gen_prologue_frame_setup ( flags : & settings ::Flags ) -> ( SmallInstVec < Self ::I > , u32 ) ;
/// Generate the usual frame-restore sequence for this architecture.
/// Generate the usual frame-restore sequence for this architecture.
fn gen_epilogue_frame_restore ( flags : & settings ::Flags ) -> SmallInstVec < Self ::I > ;
fn gen_epilogue_frame_restore ( flags : & settings ::Flags ) -> SmallInstVec < Self ::I > ;
@ -1021,6 +1021,9 @@ pub struct Callee<M: ABIMachineSpec> {
/// Storage allocated for the fixed part of the stack frame. This is
/// Storage allocated for the fixed part of the stack frame. This is
/// usually the same as the total frame size below.
/// usually the same as the total frame size below.
fixed_frame_storage_size : u32 ,
fixed_frame_storage_size : u32 ,
/// Size of the area between the FP as defined in the prolog and caller's SP.
/// It will usually contain the saved FP/LR pair.
frame_setup_area_size : u32 ,
/// "Total frame size", as defined by "distance between FP and nominal SP".
/// "Total frame size", as defined by "distance between FP and nominal SP".
/// Some items are pushed below nominal SP, so the function may actually use
/// Some items are pushed below nominal SP, so the function may actually use
/// more stack than this would otherwise imply. It is simply the initial
/// more stack than this would otherwise imply. It is simply the initial
@ -1185,6 +1188,7 @@ impl<M: ABIMachineSpec> Callee<M> {
clobbered : vec ! [ ] ,
clobbered : vec ! [ ] ,
spillslots : None ,
spillslots : None ,
fixed_frame_storage_size : 0 ,
fixed_frame_storage_size : 0 ,
frame_setup_area_size : 0 ,
total_frame_size : None ,
total_frame_size : None ,
ret_area_ptr : None ,
ret_area_ptr : None ,
arg_temp_reg : vec ! [ ] ,
arg_temp_reg : vec ! [ ] ,
@ -1760,10 +1764,7 @@ impl<M: ABIMachineSpec> Callee<M> {
ty : Type ,
ty : Type ,
into_regs : ValueRegs < Writable < Reg > > ,
into_regs : ValueRegs < Writable < Reg > > ,
) -> SmallInstVec < M ::I > {
) -> SmallInstVec < M ::I > {
// Offset from beginning of spillslot area, which is at nominal SP + stackslots_size.
let sp_off = self . get_spillslot_offset ( slot ) ;
let islot = slot . index ( ) as i64 ;
let spill_off = islot * M ::word_bytes ( ) as i64 ;
let sp_off = self . stackslots_size as i64 + spill_off ;
trace ! ( "load_spillslot: slot {:?} -> sp_off {}" , slot , sp_off ) ;
trace ! ( "load_spillslot: slot {:?} -> sp_off {}" , slot , sp_off ) ;
gen_load_stack_multi ::< M > ( StackAMode ::NominalSPOffset ( sp_off , ty ) , into_regs , ty )
gen_load_stack_multi ::< M > ( StackAMode ::NominalSPOffset ( sp_off , ty ) , into_regs , ty )
@ -1776,10 +1777,7 @@ impl<M: ABIMachineSpec> Callee<M> {
ty : Type ,
ty : Type ,
from_regs : ValueRegs < Reg > ,
from_regs : ValueRegs < Reg > ,
) -> SmallInstVec < M ::I > {
) -> SmallInstVec < M ::I > {
// Offset from beginning of spillslot area, which is at nominal SP + stackslots_size.
let sp_off = self . get_spillslot_offset ( slot ) ;
let islot = slot . index ( ) as i64 ;
let spill_off = islot * M ::word_bytes ( ) as i64 ;
let sp_off = self . stackslots_size as i64 + spill_off ;
trace ! ( "store_spillslot: slot {:?} -> sp_off {}" , slot , sp_off ) ;
trace ! ( "store_spillslot: slot {:?} -> sp_off {}" , slot , sp_off ) ;
gen_store_stack_multi ::< M > ( StackAMode ::NominalSPOffset ( sp_off , ty ) , from_regs , ty )
gen_store_stack_multi ::< M > ( StackAMode ::NominalSPOffset ( sp_off , ty ) , from_regs , ty )
@ -1890,8 +1888,9 @@ impl<M: ABIMachineSpec> Callee<M> {
) ;
) ;
if self . setup_frame {
if self . setup_frame {
// set up frame
let ( setup_insts , setup_area_size ) = M ::gen_prologue_frame_setup ( & self . flags ) ;
insts . extend ( M ::gen_prologue_frame_setup ( & self . flags ) . into_iter ( ) ) ;
insts . extend ( setup_insts . into_iter ( ) ) ;
self . frame_setup_area_size = setup_area_size ;
}
}
// Leaf functions with zero stack don't need a stack check if one's
// Leaf functions with zero stack don't need a stack check if one's
@ -1992,14 +1991,20 @@ impl<M: ABIMachineSpec> Callee<M> {
}
}
/// Returns the full frame size for the given function, after prologue
/// Returns the full frame size for the given function, after prologue
/// emission has run. This comprises the spill slots and stack-storage slots
/// emission has run. This comprises the spill slots and stack-storage
/// (but not storage for clobbered callee-save registers, arguments pushed
/// slots as well as storage for clobbered callee-save registers, but
/// at callsites within this function, or other ephemeral pushes).
/// not arguments arguments pushed at callsites within this function,
/// or other ephemeral pushes.
pub fn frame_size ( & self ) -> u32 {
pub fn frame_size ( & self ) -> u32 {
self . total_frame_size
self . total_frame_size
. expect ( "frame size not computed before prologue generation" )
. expect ( "frame size not computed before prologue generation" )
}
}
/// Returns offset from the nominal SP to caller's SP.
pub fn nominal_sp_to_caller_sp_offset ( & self ) -> u32 {
self . frame_size ( ) + self . frame_setup_area_size
}
/// Returns the size of arguments expected on the stack.
/// Returns the size of arguments expected on the stack.
pub fn stack_args_size ( & self , sigs : & SigSet ) -> u32 {
pub fn stack_args_size ( & self , sigs : & SigSet ) -> u32 {
sigs [ self . sig ] . sized_stack_arg_space
sigs [ self . sig ] . sized_stack_arg_space
@ -2020,6 +2025,16 @@ impl<M: ABIMachineSpec> Callee<M> {
M ::get_number_of_spillslots_for_value ( rc , max , & self . isa_flags )
M ::get_number_of_spillslots_for_value ( rc , max , & self . isa_flags )
}
}
/// Get the spill slot offset relative to nominal SP.
pub fn get_spillslot_offset ( & self , slot : SpillSlot ) -> i64 {
// 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 ;
let sp_off = self . stackslots_size as i64 + spill_off ;
sp_off
}
/// Generate a spill.
/// Generate a spill.
pub fn gen_spill ( & self , to_slot : SpillSlot , from_reg : RealReg ) -> M ::I {
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 ( ) ) ;
let ty = M ::I ::canonical_type_for_rc ( Reg ::from ( from_reg ) . class ( ) ) ;