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