Merge pull request #2838 from uweigand/optionalfp
Allow unwind support to work without a frame pointer
This commit is contained in:
@@ -56,8 +56,8 @@ impl crate::isa::unwind::systemv::RegisterMapper<Reg> for RegisterMapper {
|
||||
fn sp(&self) -> u16 {
|
||||
regs::stack_reg().get_hw_encoding().into()
|
||||
}
|
||||
fn fp(&self) -> u16 {
|
||||
regs::fp_reg().get_hw_encoding().into()
|
||||
fn fp(&self) -> Option<u16> {
|
||||
Some(regs::fp_reg().get_hw_encoding().into())
|
||||
}
|
||||
fn lr(&self) -> Option<u16> {
|
||||
Some(regs::link_reg().get_hw_encoding().into())
|
||||
|
||||
@@ -225,6 +225,11 @@ pub enum UnwindInst {
|
||||
/// the clobber area.
|
||||
offset_downward_to_clobbers: u32,
|
||||
},
|
||||
/// The stack pointer was adjusted to allocate the stack.
|
||||
StackAlloc {
|
||||
/// Size to allocate.
|
||||
size: u32,
|
||||
},
|
||||
/// The stack slot at the given offset from the clobber-area base has been
|
||||
/// used to save the given register.
|
||||
///
|
||||
|
||||
@@ -122,8 +122,10 @@ pub(crate) trait RegisterMapper<Reg> {
|
||||
fn map(&self, reg: Reg) -> Result<Register, RegisterMappingError>;
|
||||
/// Gets stack pointer register.
|
||||
fn sp(&self) -> Register;
|
||||
/// Gets the frame pointer register.
|
||||
fn fp(&self) -> Register;
|
||||
/// Gets the frame pointer register, if any.
|
||||
fn fp(&self) -> Option<Register> {
|
||||
None
|
||||
}
|
||||
/// Gets the link register, if any.
|
||||
fn lr(&self) -> Option<Register> {
|
||||
None
|
||||
@@ -151,6 +153,7 @@ pub(crate) fn create_unwind_info_from_insts<MR: RegisterMapper<regalloc::Reg>>(
|
||||
) -> CodegenResult<UnwindInfo> {
|
||||
let mut instructions = vec![];
|
||||
|
||||
let mut cfa_offset = 0;
|
||||
let mut clobber_offset_to_cfa = 0;
|
||||
for &(instruction_offset, ref inst) in insts {
|
||||
match inst {
|
||||
@@ -163,10 +166,14 @@ pub(crate) fn create_unwind_info_from_insts<MR: RegisterMapper<regalloc::Reg>>(
|
||||
instruction_offset,
|
||||
CallFrameInstruction::CfaOffset(offset_upward_to_caller_sp as i32),
|
||||
));
|
||||
// Note that we saved the old FP value on the stack.
|
||||
// Note that we saved the old FP value on the stack. Use of this
|
||||
// operation implies that the target defines a FP register.
|
||||
instructions.push((
|
||||
instruction_offset,
|
||||
CallFrameInstruction::Offset(mr.fp(), -(offset_upward_to_caller_sp as i32)),
|
||||
CallFrameInstruction::Offset(
|
||||
mr.fp().unwrap(),
|
||||
-(offset_upward_to_caller_sp as i32),
|
||||
),
|
||||
));
|
||||
// If there is a link register on this architecture, note that
|
||||
// we saved it as well.
|
||||
@@ -188,15 +195,29 @@ pub(crate) fn create_unwind_info_from_insts<MR: RegisterMapper<regalloc::Reg>>(
|
||||
// Define CFA in terms of FP. Note that we assume it was already
|
||||
// defined correctly in terms of the current SP, and FP has just
|
||||
// been set to the current SP, so we do not need to change the
|
||||
// offset, only the register.
|
||||
instructions.push((
|
||||
instruction_offset,
|
||||
CallFrameInstruction::CfaRegister(mr.fp()),
|
||||
));
|
||||
// offset, only the register. (This is done only if the target
|
||||
// defines a frame pointer register.)
|
||||
if let Some(fp) = mr.fp() {
|
||||
instructions.push((instruction_offset, CallFrameInstruction::CfaRegister(fp)));
|
||||
}
|
||||
// Record initial CFA offset. This will be used with later
|
||||
// StackAlloc calls if we do not have a frame pointer.
|
||||
cfa_offset = offset_upward_to_caller_sp;
|
||||
// Record distance from CFA downward to clobber area so we can
|
||||
// express clobber offsets later in terms of CFA.
|
||||
clobber_offset_to_cfa = offset_upward_to_caller_sp + offset_downward_to_clobbers;
|
||||
}
|
||||
&UnwindInst::StackAlloc { size } => {
|
||||
// If we do not use a frame pointer, we need to update the
|
||||
// CFA offset whenever the stack pointer changes.
|
||||
if mr.fp().is_none() {
|
||||
cfa_offset += size;
|
||||
instructions.push((
|
||||
instruction_offset,
|
||||
CallFrameInstruction::CfaOffset(cfa_offset as i32),
|
||||
));
|
||||
}
|
||||
}
|
||||
&UnwindInst::SaveReg {
|
||||
clobber_offset,
|
||||
reg,
|
||||
|
||||
@@ -356,6 +356,12 @@ pub(crate) fn create_unwind_info_from_insts<MR: RegisterMapper<regalloc::Reg>>(
|
||||
frame_register_offset = ensure_unwind_offset(offset_downward_to_clobbers)?;
|
||||
unwind_codes.push(UnwindCode::SetFPReg { instruction_offset });
|
||||
}
|
||||
&UnwindInst::StackAlloc { size } => {
|
||||
unwind_codes.push(UnwindCode::StackAlloc {
|
||||
instruction_offset,
|
||||
size,
|
||||
});
|
||||
}
|
||||
&UnwindInst::SaveReg {
|
||||
clobber_offset,
|
||||
reg,
|
||||
|
||||
@@ -89,8 +89,8 @@ impl crate::isa::unwind::systemv::RegisterMapper<Reg> for RegisterMapper {
|
||||
fn sp(&self) -> u16 {
|
||||
X86_64::RSP.0
|
||||
}
|
||||
fn fp(&self) -> u16 {
|
||||
X86_64::RBP.0
|
||||
fn fp(&self) -> Option<u16> {
|
||||
Some(X86_64::RBP.0)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -121,8 +121,8 @@ pub(crate) fn create_unwind_info(
|
||||
fn sp(&self) -> u16 {
|
||||
X86_64::RSP.0
|
||||
}
|
||||
fn fp(&self) -> u16 {
|
||||
X86_64::RBP.0
|
||||
fn fp(&self) -> Option<u16> {
|
||||
Some(X86_64::RBP.0)
|
||||
}
|
||||
}
|
||||
let map = RegisterMapper(isa);
|
||||
|
||||
Reference in New Issue
Block a user