Merge pull request #2838 from uweigand/optionalfp

Allow unwind support to work without a frame pointer
This commit is contained in:
Chris Fallin
2021-04-14 10:58:51 -07:00
committed by GitHub
6 changed files with 47 additions and 15 deletions

View File

@@ -56,8 +56,8 @@ impl crate::isa::unwind::systemv::RegisterMapper<Reg> for RegisterMapper {
fn sp(&self) -> u16 { fn sp(&self) -> u16 {
regs::stack_reg().get_hw_encoding().into() regs::stack_reg().get_hw_encoding().into()
} }
fn fp(&self) -> u16 { fn fp(&self) -> Option<u16> {
regs::fp_reg().get_hw_encoding().into() Some(regs::fp_reg().get_hw_encoding().into())
} }
fn lr(&self) -> Option<u16> { fn lr(&self) -> Option<u16> {
Some(regs::link_reg().get_hw_encoding().into()) Some(regs::link_reg().get_hw_encoding().into())

View File

@@ -225,6 +225,11 @@ pub enum UnwindInst {
/// the clobber area. /// the clobber area.
offset_downward_to_clobbers: u32, 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 /// The stack slot at the given offset from the clobber-area base has been
/// used to save the given register. /// used to save the given register.
/// ///

View File

@@ -122,8 +122,10 @@ pub(crate) trait RegisterMapper<Reg> {
fn map(&self, reg: Reg) -> Result<Register, RegisterMappingError>; fn map(&self, reg: Reg) -> Result<Register, RegisterMappingError>;
/// Gets stack pointer register. /// Gets stack pointer register.
fn sp(&self) -> Register; fn sp(&self) -> Register;
/// Gets the frame pointer register. /// Gets the frame pointer register, if any.
fn fp(&self) -> Register; fn fp(&self) -> Option<Register> {
None
}
/// Gets the link register, if any. /// Gets the link register, if any.
fn lr(&self) -> Option<Register> { fn lr(&self) -> Option<Register> {
None None
@@ -151,6 +153,7 @@ pub(crate) fn create_unwind_info_from_insts<MR: RegisterMapper<regalloc::Reg>>(
) -> CodegenResult<UnwindInfo> { ) -> CodegenResult<UnwindInfo> {
let mut instructions = vec![]; let mut instructions = vec![];
let mut cfa_offset = 0;
let mut clobber_offset_to_cfa = 0; let mut clobber_offset_to_cfa = 0;
for &(instruction_offset, ref inst) in insts { for &(instruction_offset, ref inst) in insts {
match inst { match inst {
@@ -163,10 +166,14 @@ pub(crate) fn create_unwind_info_from_insts<MR: RegisterMapper<regalloc::Reg>>(
instruction_offset, instruction_offset,
CallFrameInstruction::CfaOffset(offset_upward_to_caller_sp as i32), 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(( instructions.push((
instruction_offset, 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 // If there is a link register on this architecture, note that
// we saved it as well. // 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 // 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 // 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 // been set to the current SP, so we do not need to change the
// offset, only the register. // offset, only the register. (This is done only if the target
instructions.push(( // defines a frame pointer register.)
instruction_offset, if let Some(fp) = mr.fp() {
CallFrameInstruction::CfaRegister(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 // Record distance from CFA downward to clobber area so we can
// express clobber offsets later in terms of CFA. // express clobber offsets later in terms of CFA.
clobber_offset_to_cfa = offset_upward_to_caller_sp + offset_downward_to_clobbers; 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 { &UnwindInst::SaveReg {
clobber_offset, clobber_offset,
reg, reg,

View File

@@ -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)?; frame_register_offset = ensure_unwind_offset(offset_downward_to_clobbers)?;
unwind_codes.push(UnwindCode::SetFPReg { instruction_offset }); unwind_codes.push(UnwindCode::SetFPReg { instruction_offset });
} }
&UnwindInst::StackAlloc { size } => {
unwind_codes.push(UnwindCode::StackAlloc {
instruction_offset,
size,
});
}
&UnwindInst::SaveReg { &UnwindInst::SaveReg {
clobber_offset, clobber_offset,
reg, reg,

View File

@@ -89,8 +89,8 @@ impl crate::isa::unwind::systemv::RegisterMapper<Reg> for RegisterMapper {
fn sp(&self) -> u16 { fn sp(&self) -> u16 {
X86_64::RSP.0 X86_64::RSP.0
} }
fn fp(&self) -> u16 { fn fp(&self) -> Option<u16> {
X86_64::RBP.0 Some(X86_64::RBP.0)
} }
} }

View File

@@ -121,8 +121,8 @@ pub(crate) fn create_unwind_info(
fn sp(&self) -> u16 { fn sp(&self) -> u16 {
X86_64::RSP.0 X86_64::RSP.0
} }
fn fp(&self) -> u16 { fn fp(&self) -> Option<u16> {
X86_64::RBP.0 Some(X86_64::RBP.0)
} }
} }
let map = RegisterMapper(isa); let map = RegisterMapper(isa);