cranelift: refactor unwind logic to accommodate multiple backends (#2357)

*    Make cranelift_codegen::isa::unwind::input public
*    Move UnwindCode's common offset field out of the structure
*    Make MachCompileResult::unwind_info more generic
*    Record initial stack pointer offset
This commit is contained in:
Yury Delendik
2020-11-05 16:57:40 -06:00
committed by GitHub
parent df59ffb1b6
commit f60c0f3ec3
15 changed files with 396 additions and 351 deletions

View File

@@ -253,13 +253,16 @@ impl Context {
&self,
isa: &dyn TargetIsa,
) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
if self.mach_compile_result.is_some() {
return Ok(self
.mach_compile_result
.as_ref()
.unwrap()
.unwind_info
.clone());
if let Some(backend) = isa.get_mach_backend() {
use crate::isa::CallConv;
use crate::machinst::UnwindInfoKind;
let unwind_info_kind = match self.func.signature.call_conv {
CallConv::Fast | CallConv::Cold | CallConv::SystemV => UnwindInfoKind::SystemV,
CallConv::WindowsFastcall => UnwindInfoKind::Windows,
_ => UnwindInfoKind::None,
};
let result = self.mach_compile_result.as_ref().unwrap();
return backend.emit_unwind_info(result, unwind_info_kind);
}
isa.create_unwind_info(&self.func)
}

View File

@@ -1,5 +1,5 @@
use super::*;
use crate::isa::unwind::UnwindInfo;
use crate::isa::unwind::input::UnwindInfo;
use crate::result::CodegenResult;
pub struct AArch64UnwindInfo;
@@ -7,8 +7,7 @@ pub struct AArch64UnwindInfo;
impl UnwindInfoGenerator<Inst> for AArch64UnwindInfo {
fn create_unwind_info(
_context: UnwindInfoContext<Inst>,
_kind: UnwindInfoKind,
) -> CodegenResult<Option<UnwindInfo>> {
) -> CodegenResult<Option<UnwindInfo<Reg>>> {
// TODO
Ok(None)
}

View File

@@ -1,5 +1,5 @@
use super::*;
use crate::isa::unwind::UnwindInfo;
use crate::isa::unwind::input::UnwindInfo;
use crate::result::CodegenResult;
pub struct Arm32UnwindInfo;
@@ -7,8 +7,7 @@ pub struct Arm32UnwindInfo;
impl UnwindInfoGenerator<Inst> for Arm32UnwindInfo {
fn create_unwind_info(
_context: UnwindInfoContext<Inst>,
_kind: UnwindInfoKind,
) -> CodegenResult<Option<UnwindInfo>> {
) -> CodegenResult<Option<UnwindInfo<Reg>>> {
// TODO
Ok(None)
}

View File

@@ -21,51 +21,68 @@ pub enum UnwindInfo {
SystemV(systemv::UnwindInfo),
}
pub(crate) mod input {
/// Intermediate representation for the unwind information
/// generated by a backend.
pub mod input {
use crate::binemit::CodeOffset;
use alloc::vec::Vec;
#[cfg(feature = "enable-serde")]
use serde::{Deserialize, Serialize};
/// Elementary operation in the unwind operations.
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub(crate) enum UnwindCode<Reg> {
pub enum UnwindCode<Reg> {
/// Defines that a register is saved at the specified offset.
SaveRegister {
offset: CodeOffset,
/// The saved register.
reg: Reg,
/// The specified offset relative to the stack pointer.
stack_offset: u32,
},
/// Defines that a register is as defined before call.
RestoreRegister {
offset: CodeOffset,
/// The restored register.
reg: Reg,
},
/// The stack pointer was adjusted to allocate the stack.
StackAlloc {
offset: CodeOffset,
/// Size to allocate.
size: u32,
},
/// The stack pointer was adjusted to free the stack.
StackDealloc {
offset: CodeOffset,
/// Size to deallocate.
size: u32,
},
/// The alternative register was assigned as frame pointer base.
SetFramePointer {
offset: CodeOffset,
/// The specified register.
reg: Reg,
},
RememberState {
offset: CodeOffset,
},
RestoreState {
offset: CodeOffset,
},
/// Restores a frame pointer base to default register.
RestoreFramePointer,
/// Saves the state.
RememberState,
/// Restores the state.
RestoreState,
}
/// Unwind information as generated by a backend.
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub struct UnwindInfo<Reg> {
pub(crate) prologue_size: CodeOffset,
pub(crate) prologue_unwind_codes: Vec<UnwindCode<Reg>>,
pub(crate) epilogues_unwind_codes: Vec<Vec<UnwindCode<Reg>>>,
pub(crate) function_size: CodeOffset,
pub(crate) word_size: u8,
/// Size of the prologue.
pub prologue_size: CodeOffset,
/// Unwind codes for prologue.
pub prologue_unwind_codes: Vec<(CodeOffset, UnwindCode<Reg>)>,
/// Unwind codes for epilogues.
pub epilogues_unwind_codes: Vec<Vec<(CodeOffset, UnwindCode<Reg>)>>,
/// Entire function size.
pub function_size: CodeOffset,
/// Platform word size in bytes.
pub word_size: u8,
/// Initial stack pointer offset.
pub initial_sp_offset: u8,
}
}

View File

@@ -98,8 +98,8 @@ impl Into<gimli::write::CallFrameInstruction> for CallFrameInstruction {
pub(crate) trait RegisterMapper<Reg> {
/// Maps Reg.
fn map(&self, reg: Reg) -> Result<Register, RegisterMappingError>;
/// Gets RSP in gimli's index space.
fn rsp(&self) -> Register;
/// Gets stack pointer register.
fn sp(&self) -> Register;
}
/// Represents unwind information for a single System V ABI function.
@@ -118,9 +118,9 @@ impl UnwindInfo {
map_reg: &'b dyn RegisterMapper<Reg>,
) -> CodegenResult<Self> {
use input::UnwindCode;
let mut builder = InstructionBuilder::new(unwind.word_size, map_reg);
let mut builder = InstructionBuilder::new(unwind.initial_sp_offset, map_reg);
for c in unwind.prologue_unwind_codes.iter().chain(
for (offset, c) in unwind.prologue_unwind_codes.iter().chain(
unwind
.epilogues_unwind_codes
.iter()
@@ -128,38 +128,36 @@ impl UnwindInfo {
.flatten(),
) {
match c {
UnwindCode::SaveRegister {
offset,
reg,
stack_offset: 0,
} => {
UnwindCode::SaveRegister { reg, stack_offset } => {
builder
.save_reg(*offset, *reg)
.save_reg(*offset, *reg, *stack_offset)
.map_err(CodegenError::RegisterMappingError)?;
}
UnwindCode::StackAlloc { offset, size } => {
UnwindCode::StackAlloc { size } => {
builder.adjust_sp_down_imm(*offset, *size as i64);
}
UnwindCode::StackDealloc { offset, size } => {
UnwindCode::StackDealloc { size } => {
builder.adjust_sp_up_imm(*offset, *size as i64);
}
UnwindCode::RestoreRegister { offset, reg } => {
UnwindCode::RestoreRegister { reg } => {
builder
.restore_reg(*offset, *reg)
.map_err(CodegenError::RegisterMappingError)?;
}
UnwindCode::SetFramePointer { offset, reg } => {
UnwindCode::SetFramePointer { reg } => {
builder
.set_cfa_reg(*offset, *reg)
.map_err(CodegenError::RegisterMappingError)?;
}
UnwindCode::RememberState { offset } => {
UnwindCode::RestoreFramePointer => {
builder.restore_cfa(*offset);
}
UnwindCode::RememberState => {
builder.remember_state(*offset);
}
UnwindCode::RestoreState { offset } => {
UnwindCode::RestoreState => {
builder.restore_state(*offset);
}
_ => {}
}
}
@@ -190,9 +188,9 @@ struct InstructionBuilder<'a, Reg: PartialEq + Copy> {
}
impl<'a, Reg: PartialEq + Copy> InstructionBuilder<'a, Reg> {
fn new(word_size: u8, map_reg: &'a (dyn RegisterMapper<Reg> + 'a)) -> Self {
fn new(sp_offset: u8, map_reg: &'a (dyn RegisterMapper<Reg> + 'a)) -> Self {
Self {
sp_offset: word_size as i32, // CFA offset starts at word size offset to account for the return address on stack
sp_offset: sp_offset as i32, // CFA offset starts at the specified offset to account for the return address on stack
saved_state: None,
frame_register: None,
map_reg,
@@ -200,11 +198,19 @@ impl<'a, Reg: PartialEq + Copy> InstructionBuilder<'a, Reg> {
}
}
fn save_reg(&mut self, offset: u32, reg: Reg) -> Result<(), RegisterMappingError> {
fn save_reg(
&mut self,
offset: u32,
reg: Reg,
stack_offset: u32,
) -> Result<(), RegisterMappingError> {
// Pushes in the prologue are register saves, so record an offset of the save
self.instructions.push((
offset,
CallFrameInstruction::Offset(self.map_reg.map(reg)?, -self.sp_offset),
CallFrameInstruction::Offset(
self.map_reg.map(reg)?,
stack_offset as i32 - self.sp_offset,
),
));
Ok(())
@@ -270,15 +276,16 @@ impl<'a, Reg: PartialEq + Copy> InstructionBuilder<'a, Reg> {
Ok(())
}
fn restore_cfa(&mut self, offset: u32) {
// Restore SP and its offset.
self.instructions.push((
offset,
CallFrameInstruction::Cfa(self.map_reg.sp(), self.sp_offset),
));
self.frame_register = None;
}
fn restore_reg(&mut self, offset: u32, reg: Reg) -> Result<(), RegisterMappingError> {
// Update the CFA if this is the restore of the frame pointer register.
if Some(reg) == self.frame_register {
self.frame_register = None;
self.instructions.push((
offset,
CallFrameInstruction::Cfa(self.map_reg.rsp(), self.sp_offset),
));
}
// Pops in the epilogue are register restores, so record a "same value" for the register
self.instructions.push((
offset,

View File

@@ -226,13 +226,9 @@ impl UnwindInfo {
let word_size: u32 = unwind.word_size.into();
let mut unwind_codes = Vec::new();
for c in unwind.prologue_unwind_codes.iter() {
for (offset, c) in unwind.prologue_unwind_codes.iter() {
match c {
InputUnwindCode::SaveRegister {
offset,
reg,
stack_offset,
} => {
InputUnwindCode::SaveRegister { reg, stack_offset } => {
let reg = MR::map(*reg);
let offset = ensure_unwind_offset(*offset)?;
match reg {
@@ -269,7 +265,7 @@ impl UnwindInfo {
}
}
}
InputUnwindCode::StackAlloc { offset, size } => {
InputUnwindCode::StackAlloc { size } => {
unwind_codes.push(UnwindCode::StackAlloc {
offset: ensure_unwind_offset(*offset)?,
size: *size,

View File

@@ -1,36 +1,125 @@
use super::Inst;
use crate::isa::unwind::UnwindInfo;
use crate::machinst::{UnwindInfoContext, UnwindInfoGenerator, UnwindInfoKind};
use crate::isa::unwind::input::UnwindInfo;
use crate::isa::x64::inst::{
args::{AluRmiROpcode, Amode, RegMemImm, SyntheticAmode},
regs, Inst,
};
use crate::machinst::{UnwindInfoContext, UnwindInfoGenerator};
use crate::result::CodegenResult;
use alloc::vec::Vec;
use regalloc::Reg;
#[cfg(feature = "unwind")]
pub use self::systemv::create_cie;
#[cfg(feature = "unwind")]
mod systemv;
pub(crate) mod systemv;
pub struct X64UnwindInfo;
impl UnwindInfoGenerator<Inst> for X64UnwindInfo {
#[allow(unused_variables)]
fn create_unwind_info(
context: UnwindInfoContext<Inst>,
kind: UnwindInfoKind,
) -> CodegenResult<Option<UnwindInfo>> {
// Assumption: RBP is being used as the frame pointer for both calling conventions
// In the future, we should be omitting frame pointer as an optimization, so this will change
Ok(match kind {
#[cfg(feature = "unwind")]
UnwindInfoKind::SystemV => {
const WORD_SIZE: u8 = 8;
systemv::create_unwind_info(context, WORD_SIZE)?.map(UnwindInfo::SystemV)
) -> CodegenResult<Option<UnwindInfo<Reg>>> {
use crate::isa::unwind::input::{self, UnwindCode};
let mut codes = Vec::new();
const WORD_SIZE: u8 = 8;
for i in context.prologue.clone() {
let i = i as usize;
let inst = &context.insts[i];
let offset = context.insts_layout[i];
match inst {
Inst::Push64 {
src: RegMemImm::Reg { reg },
} => {
codes.push((
offset,
UnwindCode::StackAlloc {
size: WORD_SIZE.into(),
},
));
codes.push((
offset,
UnwindCode::SaveRegister {
reg: *reg,
stack_offset: 0,
},
));
}
Inst::MovRR { src, dst, .. } => {
if *src == regs::rsp() {
codes.push((offset, UnwindCode::SetFramePointer { reg: dst.to_reg() }));
}
}
Inst::AluRmiR {
is_64: true,
op: AluRmiROpcode::Sub,
src: RegMemImm::Imm { simm32 },
dst,
..
} if dst.to_reg() == regs::rsp() => {
let imm = *simm32;
codes.push((offset, UnwindCode::StackAlloc { size: imm }));
}
Inst::MovRM {
src,
dst: SyntheticAmode::Real(Amode::ImmReg { simm32, base }),
..
} if *base == regs::rsp() => {
// `mov reg, imm(rsp)`
let imm = *simm32;
codes.push((
offset,
UnwindCode::SaveRegister {
reg: *src,
stack_offset: imm,
},
));
}
Inst::AluRmiR {
is_64: true,
op: AluRmiROpcode::Add,
src: RegMemImm::Imm { simm32 },
dst,
..
} if dst.to_reg() == regs::rsp() => {
let imm = *simm32;
codes.push((offset, UnwindCode::StackDealloc { size: imm }));
}
_ => {}
}
#[cfg(feature = "unwind")]
UnwindInfoKind::Windows => {
//TODO winx64::create_unwind_info(context)?.map(|u| UnwindInfo::WindowsX64(u))
panic!();
}
UnwindInfoKind::None => None,
})
}
let last_epilogue_end = context.len;
let epilogues_unwind_codes = context
.epilogues
.iter()
.map(|epilogue| {
// TODO add logic to process epilogue instruction instead of
// returning empty array.
let end = epilogue.end as usize - 1;
let end_offset = context.insts_layout[end];
if end_offset == last_epilogue_end {
// Do not remember/restore for very last epilogue.
return vec![];
}
let start = epilogue.start as usize;
let offset = context.insts_layout[start];
vec![
(offset, UnwindCode::RememberState),
// TODO epilogue instructions
(end_offset, UnwindCode::RestoreState),
]
})
.collect();
let prologue_size = context.insts_layout[context.prologue.end as usize];
Ok(Some(input::UnwindInfo {
prologue_size,
prologue_unwind_codes: codes,
epilogues_unwind_codes,
function_size: context.len,
word_size: WORD_SIZE,
initial_sp_offset: WORD_SIZE,
}))
}
}

View File

@@ -1,13 +1,8 @@
//! Unwind information for System V ABI (x86-64).
use crate::isa::unwind::input;
use crate::isa::unwind::systemv::{RegisterMappingError, UnwindInfo};
use crate::isa::x64::inst::{
args::{AluRmiROpcode, Amode, RegMemImm, SyntheticAmode},
regs, Inst,
};
use crate::machinst::UnwindInfoContext;
use crate::result::CodegenResult;
use alloc::vec::Vec;
use gimli::{write::CommonInformationEntry, Encoding, Format, Register, X86_64};
use regalloc::{Reg, RegClass};
@@ -88,113 +83,15 @@ pub fn map_reg(reg: Reg) -> Result<Register, RegisterMappingError> {
}
pub(crate) fn create_unwind_info(
context: UnwindInfoContext<Inst>,
word_size: u8,
unwind: input::UnwindInfo<Reg>,
) -> CodegenResult<Option<UnwindInfo>> {
use crate::isa::unwind::input::{self, UnwindCode};
let mut codes = Vec::new();
for i in context.prologue.clone() {
let i = i as usize;
let inst = &context.insts[i];
let offset = context.insts_layout[i];
match inst {
Inst::Push64 {
src: RegMemImm::Reg { reg },
} => {
codes.push(UnwindCode::StackAlloc {
offset,
size: word_size.into(),
});
codes.push(UnwindCode::SaveRegister {
offset,
reg: *reg,
stack_offset: 0,
});
}
Inst::MovRR { src, dst, .. } => {
if *src == regs::rsp() {
codes.push(UnwindCode::SetFramePointer {
offset,
reg: dst.to_reg(),
});
}
}
Inst::AluRmiR {
is_64: true,
op: AluRmiROpcode::Sub,
src: RegMemImm::Imm { simm32 },
dst,
..
} if dst.to_reg() == regs::rsp() => {
let imm = *simm32;
codes.push(UnwindCode::StackAlloc { offset, size: imm });
}
Inst::MovRM {
src,
dst: SyntheticAmode::Real(Amode::ImmReg { simm32, base }),
..
} if *base == regs::rsp() => {
// `mov reg, imm(rsp)`
let imm = *simm32;
codes.push(UnwindCode::SaveRegister {
offset,
reg: *src,
stack_offset: imm,
});
}
Inst::AluRmiR {
is_64: true,
op: AluRmiROpcode::Add,
src: RegMemImm::Imm { simm32 },
dst,
..
} if dst.to_reg() == regs::rsp() => {
let imm = *simm32;
codes.push(UnwindCode::StackDealloc { offset, size: imm });
}
_ => {}
}
}
let last_epilogue_end = context.len;
let epilogues_unwind_codes = context
.epilogues
.iter()
.map(|epilogue| {
let end = epilogue.end as usize - 1;
let end_offset = context.insts_layout[end];
if end_offset == last_epilogue_end {
// Do not remember/restore for very last epilogue.
return vec![];
}
let start = epilogue.start as usize;
let offset = context.insts_layout[start];
vec![
UnwindCode::RememberState { offset },
UnwindCode::RestoreState { offset: end_offset },
]
})
.collect();
let prologue_size = context.insts_layout[context.prologue.end as usize];
let unwind = input::UnwindInfo {
prologue_size,
prologue_unwind_codes: codes,
epilogues_unwind_codes,
function_size: context.len,
word_size,
};
struct RegisterMapper;
impl crate::isa::unwind::systemv::RegisterMapper<Reg> for RegisterMapper {
fn map(&self, reg: Reg) -> Result<u16, RegisterMappingError> {
Ok(map_reg(reg)?.0)
}
fn rsp(&self) -> u16 {
map_reg(regs::rsp()).unwrap().0
fn sp(&self) -> u16 {
X86_64::RSP.0
}
}
let map = RegisterMapper;

View File

@@ -103,10 +103,29 @@ impl MachBackend for X64Backend {
IntCC::UnsignedGreaterThanOrEqual
}
#[cfg(feature = "unwind")]
fn emit_unwind_info(
&self,
result: &MachCompileResult,
kind: crate::machinst::UnwindInfoKind,
) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
use crate::isa::unwind::UnwindInfo;
use crate::machinst::UnwindInfoKind;
Ok(match (result.unwind_info.as_ref(), kind) {
(Some(info), UnwindInfoKind::SystemV) => {
inst::unwind::systemv::create_unwind_info(info.clone())?.map(UnwindInfo::SystemV)
}
(Some(_info), UnwindInfoKind::Windows) => {
//TODO inst::unwind::winx64::create_unwind_info(info.clone())?.map(|u| UnwindInfo::WindowsX64(u))
None
}
_ => None,
})
}
#[cfg(feature = "unwind")]
fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
// By default, an ISA cannot create a System V CIE
Some(inst::unwind::create_cie())
Some(inst::unwind::systemv::create_cie())
}
}

View File

@@ -81,7 +81,7 @@ pub(crate) fn create_unwind_info(
unwind_codes = epilogues_unwind_codes.last_mut().unwrap();
if !is_last_block {
unwind_codes.push(UnwindCode::RememberState { offset });
unwind_codes.push((offset, UnwindCode::RememberState));
}
} else if in_epilogue {
unwind_codes = epilogues_unwind_codes.last_mut().unwrap();
@@ -95,15 +95,19 @@ pub(crate) fn create_unwind_info(
match opcode {
Opcode::X86Push => {
let reg = func.locations[arg].unwrap_reg();
unwind_codes.push(UnwindCode::StackAlloc {
unwind_codes.push((
offset,
size: word_size.into(),
});
unwind_codes.push(UnwindCode::SaveRegister {
UnwindCode::StackAlloc {
size: word_size.into(),
},
));
unwind_codes.push((
offset,
reg,
stack_offset: 0,
});
UnwindCode::SaveRegister {
reg,
stack_offset: 0,
},
));
}
Opcode::AdjustSpDown => {
let stack_size =
@@ -111,10 +115,8 @@ pub(crate) fn create_unwind_info(
// This is used when calling a stack check function
// We need to track the assignment to RAX which has the size of the stack
unwind_codes.push(UnwindCode::StackAlloc {
offset,
size: stack_size,
});
unwind_codes
.push((offset, UnwindCode::StackAlloc { size: stack_size }));
}
_ => {}
}
@@ -138,10 +140,8 @@ pub(crate) fn create_unwind_info(
stack_size = Some(imm as u32);
unwind_codes.push(UnwindCode::StackAlloc {
offset,
size: imm as u32,
});
unwind_codes
.push((offset, UnwindCode::StackAlloc { size: imm as u32 }));
}
Opcode::AdjustSpUpImm => {
let imm: i64 = imm.into();
@@ -149,10 +149,8 @@ pub(crate) fn create_unwind_info(
stack_size = Some(imm as u32);
unwind_codes.push(UnwindCode::StackDealloc {
offset,
size: imm as u32,
});
unwind_codes
.push((offset, UnwindCode::StackDealloc { size: imm as u32 }));
}
_ => {}
}
@@ -170,18 +168,20 @@ pub(crate) fn create_unwind_info(
// Note: the stack_offset here is relative to an adjusted SP
if dst == (RU::rsp as RegUnit) && FPR.contains(src) {
let stack_offset: i32 = stack_offset.into();
unwind_codes.push(UnwindCode::SaveRegister {
unwind_codes.push((
offset,
reg: src,
stack_offset: stack_offset as u32,
});
UnwindCode::SaveRegister {
reg: src,
stack_offset: stack_offset as u32,
},
));
}
}
}
InstructionData::CopySpecial { src, dst, .. } if frame_register.is_none() => {
// Check for change in CFA register (RSP is always the starting CFA)
if src == (RU::rsp as RegUnit) {
unwind_codes.push(UnwindCode::SetFramePointer { offset, reg: dst });
unwind_codes.push((offset, UnwindCode::SetFramePointer { reg: dst }));
frame_register = Some(dst);
}
}
@@ -203,18 +203,25 @@ pub(crate) fn create_unwind_info(
let offset = epilogue_pop_offsets[i];
let reg = func.locations[*arg].unwrap_reg();
unwind_codes.push(UnwindCode::RestoreRegister { offset, reg });
unwind_codes.push(UnwindCode::StackDealloc {
unwind_codes.push((offset, UnwindCode::RestoreRegister { reg }));
unwind_codes.push((
offset,
size: word_size.into(),
});
UnwindCode::StackDealloc {
size: word_size.into(),
},
));
if Some(reg) == frame_register {
unwind_codes.push((offset, UnwindCode::RestoreFramePointer));
// Keep frame_register assigned for next epilogue.
}
}
epilogue_pop_offsets.clear();
// TODO ensure unwind codes sorted by offsets ?
if !is_last_block {
unwind_codes.push(UnwindCode::RestoreState { offset });
unwind_codes.push((offset, UnwindCode::RestoreState));
}
in_epilogue = false;
@@ -232,6 +239,7 @@ pub(crate) fn create_unwind_info(
epilogues_unwind_codes,
function_size,
word_size,
initial_sp_offset: word_size,
}))
}
@@ -271,37 +279,36 @@ mod tests {
UnwindInfo {
prologue_size: 9,
prologue_unwind_codes: vec![
UnwindCode::StackAlloc { offset: 2, size: 8 },
UnwindCode::SaveRegister {
offset: 2,
reg: RU::rbp.into(),
stack_offset: 0,
},
UnwindCode::SetFramePointer {
offset: 5,
reg: RU::rbp.into(),
},
UnwindCode::StackAlloc {
offset: 9,
size: 64
}
(2, UnwindCode::StackAlloc { size: 8 }),
(
2,
UnwindCode::SaveRegister {
reg: RU::rbp.into(),
stack_offset: 0,
}
),
(
5,
UnwindCode::SetFramePointer {
reg: RU::rbp.into(),
}
),
(9, UnwindCode::StackAlloc { size: 64 })
],
epilogues_unwind_codes: vec![vec![
UnwindCode::StackDealloc {
offset: 13,
size: 64
},
UnwindCode::RestoreRegister {
offset: 15,
reg: RU::rbp.into()
},
UnwindCode::StackDealloc {
offset: 15,
size: 8
}
(13, UnwindCode::StackDealloc { size: 64 }),
(
15,
UnwindCode::RestoreRegister {
reg: RU::rbp.into()
}
),
(15, UnwindCode::StackDealloc { size: 8 }),
(15, UnwindCode::RestoreFramePointer)
]],
function_size: 16,
word_size: 8,
initial_sp_offset: 8,
}
);
}
@@ -329,37 +336,36 @@ mod tests {
UnwindInfo {
prologue_size: 27,
prologue_unwind_codes: vec![
UnwindCode::StackAlloc { offset: 2, size: 8 },
UnwindCode::SaveRegister {
offset: 2,
reg: RU::rbp.into(),
stack_offset: 0,
},
UnwindCode::SetFramePointer {
offset: 5,
reg: RU::rbp.into(),
},
UnwindCode::StackAlloc {
offset: 27,
size: 10000
}
(2, UnwindCode::StackAlloc { size: 8 }),
(
2,
UnwindCode::SaveRegister {
reg: RU::rbp.into(),
stack_offset: 0,
}
),
(
5,
UnwindCode::SetFramePointer {
reg: RU::rbp.into(),
}
),
(27, UnwindCode::StackAlloc { size: 10000 })
],
epilogues_unwind_codes: vec![vec![
UnwindCode::StackDealloc {
offset: 34,
size: 10000
},
UnwindCode::RestoreRegister {
offset: 36,
reg: RU::rbp.into()
},
UnwindCode::StackDealloc {
offset: 36,
size: 8
}
(34, UnwindCode::StackDealloc { size: 10000 }),
(
36,
UnwindCode::RestoreRegister {
reg: RU::rbp.into()
}
),
(36, UnwindCode::StackDealloc { size: 8 }),
(36, UnwindCode::RestoreFramePointer)
]],
function_size: 37,
word_size: 8,
initial_sp_offset: 8,
}
);
}
@@ -387,37 +393,36 @@ mod tests {
UnwindInfo {
prologue_size: 27,
prologue_unwind_codes: vec![
UnwindCode::StackAlloc { offset: 2, size: 8 },
UnwindCode::SaveRegister {
offset: 2,
reg: RU::rbp.into(),
stack_offset: 0,
},
UnwindCode::SetFramePointer {
offset: 5,
reg: RU::rbp.into(),
},
UnwindCode::StackAlloc {
offset: 27,
size: 1000000
}
(2, UnwindCode::StackAlloc { size: 8 }),
(
2,
UnwindCode::SaveRegister {
reg: RU::rbp.into(),
stack_offset: 0,
}
),
(
5,
UnwindCode::SetFramePointer {
reg: RU::rbp.into(),
}
),
(27, UnwindCode::StackAlloc { size: 1000000 })
],
epilogues_unwind_codes: vec![vec![
UnwindCode::StackDealloc {
offset: 34,
size: 1000000
},
UnwindCode::RestoreRegister {
offset: 36,
reg: RU::rbp.into()
},
UnwindCode::StackDealloc {
offset: 36,
size: 8
}
(34, UnwindCode::StackDealloc { size: 1000000 }),
(
36,
UnwindCode::RestoreRegister {
reg: RU::rbp.into()
}
),
(36, UnwindCode::StackDealloc { size: 8 }),
(36, UnwindCode::RestoreFramePointer)
]],
function_size: 37,
word_size: 8,
initial_sp_offset: 8,
}
);
}
@@ -458,43 +463,48 @@ mod tests {
UnwindInfo {
prologue_size: 5,
prologue_unwind_codes: vec![
UnwindCode::StackAlloc { offset: 2, size: 8 },
UnwindCode::SaveRegister {
offset: 2,
reg: RU::rbp.into(),
stack_offset: 0,
},
UnwindCode::SetFramePointer {
offset: 5,
reg: RU::rbp.into()
}
(2, UnwindCode::StackAlloc { size: 8 }),
(
2,
UnwindCode::SaveRegister {
reg: RU::rbp.into(),
stack_offset: 0,
}
),
(
5,
UnwindCode::SetFramePointer {
reg: RU::rbp.into()
}
)
],
epilogues_unwind_codes: vec![
vec![
UnwindCode::RememberState { offset: 12 },
UnwindCode::RestoreRegister {
offset: 12,
reg: RU::rbp.into()
},
UnwindCode::StackDealloc {
offset: 12,
size: 8
},
UnwindCode::RestoreState { offset: 13 }
(12, UnwindCode::RememberState),
(
12,
UnwindCode::RestoreRegister {
reg: RU::rbp.into()
}
),
(12, UnwindCode::StackDealloc { size: 8 }),
(12, UnwindCode::RestoreFramePointer),
(13, UnwindCode::RestoreState)
],
vec![
UnwindCode::RestoreRegister {
offset: 15,
reg: RU::rbp.into()
},
UnwindCode::StackDealloc {
offset: 15,
size: 8
}
(
15,
UnwindCode::RestoreRegister {
reg: RU::rbp.into()
}
),
(15, UnwindCode::StackDealloc { size: 8 }),
(15, UnwindCode::RestoreFramePointer)
]
],
function_size: 16,
word_size: 8,
initial_sp_offset: 8,
}
);
}

View File

@@ -118,7 +118,7 @@ pub(crate) fn create_unwind_info(
fn map(&self, reg: RegUnit) -> Result<u16, RegisterMappingError> {
Ok(map_reg(self.0, reg)?.0)
}
fn rsp(&self) -> u16 {
fn sp(&self) -> u16 {
X86_64::RSP.0
}
}
@@ -165,7 +165,7 @@ mod tests {
_ => panic!("expected unwind information"),
};
assert_eq!(format!("{:?}", fde), "FrameDescriptionEntry { address: Constant(1234), length: 16, lsda: None, instructions: [(2, CfaOffset(16)), (2, Offset(Register(6), -16)), (5, CfaRegister(Register(6))), (15, Cfa(Register(7), 8)), (15, SameValue(Register(6)))] }");
assert_eq!(format!("{:?}", fde), "FrameDescriptionEntry { address: Constant(1234), length: 16, lsda: None, instructions: [(2, CfaOffset(16)), (2, Offset(Register(6), -16)), (5, CfaRegister(Register(6))), (15, SameValue(Register(6))), (15, Cfa(Register(7), 8))] }");
}
fn create_function(call_conv: CallConv, stack_slot: Option<StackSlotData>) -> Function {
@@ -205,7 +205,7 @@ mod tests {
_ => panic!("expected unwind information"),
};
assert_eq!(format!("{:?}", fde), "FrameDescriptionEntry { address: Constant(4321), length: 16, lsda: None, instructions: [(2, CfaOffset(16)), (2, Offset(Register(6), -16)), (5, CfaRegister(Register(6))), (12, RememberState), (12, Cfa(Register(7), 8)), (12, SameValue(Register(6))), (13, RestoreState), (15, Cfa(Register(7), 8)), (15, SameValue(Register(6)))] }");
assert_eq!(format!("{:?}", fde), "FrameDescriptionEntry { address: Constant(4321), length: 16, lsda: None, instructions: [(2, CfaOffset(16)), (2, Offset(Register(6), -16)), (5, CfaRegister(Register(6))), (12, RememberState), (12, SameValue(Register(6))), (12, Cfa(Register(7), 8)), (13, RestoreState), (15, SameValue(Register(6))), (15, Cfa(Register(7), 8))] }");
}
fn create_multi_return_function(call_conv: CallConv) -> Function {

View File

@@ -129,7 +129,7 @@ impl TargetIsa for TargetIsaAdapter {
self.backend.unsigned_sub_overflow_condition()
}
#[cfg(feature = "unwind")]
#[cfg(all(feature = "unwind", feature = "x64"))]
fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
self.backend.create_systemv_cie()
}

View File

@@ -99,7 +99,7 @@
use crate::binemit::{CodeInfo, CodeOffset, StackMap};
use crate::ir::condcodes::IntCC;
use crate::ir::{Function, Type};
use crate::isa::unwind;
use crate::isa::unwind::input as unwind_input;
use crate::result::CodegenResult;
use crate::settings::Flags;
@@ -314,7 +314,7 @@ pub struct MachCompileResult {
/// Disassembly, if requested.
pub disasm: Option<String>,
/// Unwind info.
pub unwind_info: Option<unwind::UnwindInfo>,
pub unwind_info: Option<unwind_input::UnwindInfo<Reg>>,
}
impl MachCompileResult {
@@ -360,6 +360,17 @@ pub trait MachBackend {
/// Condition that will be true when an IsubIfcout overflows.
fn unsigned_sub_overflow_condition(&self) -> IntCC;
/// Produces unwind info based on backend results.
#[cfg(feature = "unwind")]
fn emit_unwind_info(
&self,
_result: &MachCompileResult,
_kind: UnwindInfoKind,
) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
// By default, an backend cannot produce unwind info.
Ok(None)
}
/// Machine-specific condcode info needed by TargetIsa.
/// Creates a new System V Common Information Entry for the ISA.
#[cfg(feature = "unwind")]
@@ -403,6 +414,5 @@ pub trait UnwindInfoGenerator<I: MachInstEmit> {
/// emitted instructions.
fn create_unwind_info(
context: UnwindInfoContext<I>,
kind: UnwindInfoKind,
) -> CodegenResult<Option<unwind::UnwindInfo>>;
) -> CodegenResult<Option<unwind_input::UnwindInfo<Reg>>>;
}

View File

@@ -560,7 +560,7 @@ impl<I: VCodeInst> VCode<I> {
/// Generates unwind info.
pub fn unwind_info(
&self,
) -> crate::result::CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
) -> crate::result::CodegenResult<Option<crate::isa::unwind::input::UnwindInfo<Reg>>> {
let layout = &self.insts_layout.borrow();
let (prologue, epilogues) = self.prologue_epilogue_ranges.as_ref().unwrap();
let context = UnwindInfoContext {
@@ -570,7 +570,7 @@ impl<I: VCodeInst> VCode<I> {
prologue: prologue.clone(),
epilogues,
};
I::UnwindInfo::create_unwind_info(context, self.abi.unwind_info_kind())
I::UnwindInfo::create_unwind_info(context)
}
/// Get the IR block for a BlockIndex, if one exists.

View File

@@ -37,8 +37,8 @@ block0:
; nextln: DW_CFA_advance_loc (3)
; nextln: DW_CFA_def_cfa_register (r6)
; nextln: DW_CFA_advance_loc (1)
; nextln: DW_CFA_def_cfa (r7, 8)
; nextln: DW_CFA_same_value (r6)
; nextln: DW_CFA_def_cfa (r7, 8)
; nextln: DW_CFA_nop
; check a function with medium-sized stack alloc
@@ -76,8 +76,8 @@ block0:
; nextln: DW_CFA_advance_loc (3)
; nextln: DW_CFA_def_cfa_register (r6)
; nextln: DW_CFA_advance_loc (21)
; nextln: DW_CFA_def_cfa (r7, 8)
; nextln: DW_CFA_same_value (r6)
; nextln: DW_CFA_def_cfa (r7, 8)
; nextln: DW_CFA_nop
; check a function with large-sized stack alloc
@@ -115,8 +115,8 @@ block0:
; nextln: DW_CFA_advance_loc (3)
; nextln: DW_CFA_def_cfa_register (r6)
; nextln: DW_CFA_advance_loc (21)
; nextln: DW_CFA_def_cfa (r7, 8)
; nextln: DW_CFA_same_value (r6)
; nextln: DW_CFA_def_cfa (r7, 8)
; nextln: DW_CFA_nop
; nextln:
@@ -200,7 +200,6 @@ block0(v0: i64, v1: i64):
; nextln: DW_CFA_advance_loc (1)
; nextln: DW_CFA_same_value (r3)
; nextln: DW_CFA_advance_loc (1)
; nextln: DW_CFA_def_cfa (r7, 8)
; nextln: DW_CFA_same_value (r6)
; nextln: DW_CFA_nop
; nextln: DW_CFA_def_cfa (r7, 8)
; nextln: DW_CFA_nop