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:
@@ -253,13 +253,16 @@ impl Context {
|
|||||||
&self,
|
&self,
|
||||||
isa: &dyn TargetIsa,
|
isa: &dyn TargetIsa,
|
||||||
) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
|
) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
|
||||||
if self.mach_compile_result.is_some() {
|
if let Some(backend) = isa.get_mach_backend() {
|
||||||
return Ok(self
|
use crate::isa::CallConv;
|
||||||
.mach_compile_result
|
use crate::machinst::UnwindInfoKind;
|
||||||
.as_ref()
|
let unwind_info_kind = match self.func.signature.call_conv {
|
||||||
.unwrap()
|
CallConv::Fast | CallConv::Cold | CallConv::SystemV => UnwindInfoKind::SystemV,
|
||||||
.unwind_info
|
CallConv::WindowsFastcall => UnwindInfoKind::Windows,
|
||||||
.clone());
|
_ => 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)
|
isa.create_unwind_info(&self.func)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::isa::unwind::UnwindInfo;
|
use crate::isa::unwind::input::UnwindInfo;
|
||||||
use crate::result::CodegenResult;
|
use crate::result::CodegenResult;
|
||||||
|
|
||||||
pub struct AArch64UnwindInfo;
|
pub struct AArch64UnwindInfo;
|
||||||
@@ -7,8 +7,7 @@ pub struct AArch64UnwindInfo;
|
|||||||
impl UnwindInfoGenerator<Inst> for AArch64UnwindInfo {
|
impl UnwindInfoGenerator<Inst> for AArch64UnwindInfo {
|
||||||
fn create_unwind_info(
|
fn create_unwind_info(
|
||||||
_context: UnwindInfoContext<Inst>,
|
_context: UnwindInfoContext<Inst>,
|
||||||
_kind: UnwindInfoKind,
|
) -> CodegenResult<Option<UnwindInfo<Reg>>> {
|
||||||
) -> CodegenResult<Option<UnwindInfo>> {
|
|
||||||
// TODO
|
// TODO
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::isa::unwind::UnwindInfo;
|
use crate::isa::unwind::input::UnwindInfo;
|
||||||
use crate::result::CodegenResult;
|
use crate::result::CodegenResult;
|
||||||
|
|
||||||
pub struct Arm32UnwindInfo;
|
pub struct Arm32UnwindInfo;
|
||||||
@@ -7,8 +7,7 @@ pub struct Arm32UnwindInfo;
|
|||||||
impl UnwindInfoGenerator<Inst> for Arm32UnwindInfo {
|
impl UnwindInfoGenerator<Inst> for Arm32UnwindInfo {
|
||||||
fn create_unwind_info(
|
fn create_unwind_info(
|
||||||
_context: UnwindInfoContext<Inst>,
|
_context: UnwindInfoContext<Inst>,
|
||||||
_kind: UnwindInfoKind,
|
) -> CodegenResult<Option<UnwindInfo<Reg>>> {
|
||||||
) -> CodegenResult<Option<UnwindInfo>> {
|
|
||||||
// TODO
|
// TODO
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,51 +21,68 @@ pub enum UnwindInfo {
|
|||||||
SystemV(systemv::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 crate::binemit::CodeOffset;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
#[cfg(feature = "enable-serde")]
|
#[cfg(feature = "enable-serde")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// Elementary operation in the unwind operations.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
#[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 {
|
SaveRegister {
|
||||||
offset: CodeOffset,
|
/// The saved register.
|
||||||
reg: Reg,
|
reg: Reg,
|
||||||
|
/// The specified offset relative to the stack pointer.
|
||||||
stack_offset: u32,
|
stack_offset: u32,
|
||||||
},
|
},
|
||||||
|
/// Defines that a register is as defined before call.
|
||||||
RestoreRegister {
|
RestoreRegister {
|
||||||
offset: CodeOffset,
|
/// The restored register.
|
||||||
reg: Reg,
|
reg: Reg,
|
||||||
},
|
},
|
||||||
|
/// The stack pointer was adjusted to allocate the stack.
|
||||||
StackAlloc {
|
StackAlloc {
|
||||||
offset: CodeOffset,
|
/// Size to allocate.
|
||||||
size: u32,
|
size: u32,
|
||||||
},
|
},
|
||||||
|
/// The stack pointer was adjusted to free the stack.
|
||||||
StackDealloc {
|
StackDealloc {
|
||||||
offset: CodeOffset,
|
/// Size to deallocate.
|
||||||
size: u32,
|
size: u32,
|
||||||
},
|
},
|
||||||
|
/// The alternative register was assigned as frame pointer base.
|
||||||
SetFramePointer {
|
SetFramePointer {
|
||||||
offset: CodeOffset,
|
/// The specified register.
|
||||||
reg: Reg,
|
reg: Reg,
|
||||||
},
|
},
|
||||||
RememberState {
|
/// Restores a frame pointer base to default register.
|
||||||
offset: CodeOffset,
|
RestoreFramePointer,
|
||||||
},
|
/// Saves the state.
|
||||||
RestoreState {
|
RememberState,
|
||||||
offset: CodeOffset,
|
/// Restores the state.
|
||||||
},
|
RestoreState,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Unwind information as generated by a backend.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
|
||||||
pub struct UnwindInfo<Reg> {
|
pub struct UnwindInfo<Reg> {
|
||||||
pub(crate) prologue_size: CodeOffset,
|
/// Size of the prologue.
|
||||||
pub(crate) prologue_unwind_codes: Vec<UnwindCode<Reg>>,
|
pub prologue_size: CodeOffset,
|
||||||
pub(crate) epilogues_unwind_codes: Vec<Vec<UnwindCode<Reg>>>,
|
/// Unwind codes for prologue.
|
||||||
pub(crate) function_size: CodeOffset,
|
pub prologue_unwind_codes: Vec<(CodeOffset, UnwindCode<Reg>)>,
|
||||||
pub(crate) word_size: u8,
|
/// 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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,8 +98,8 @@ impl Into<gimli::write::CallFrameInstruction> for CallFrameInstruction {
|
|||||||
pub(crate) trait RegisterMapper<Reg> {
|
pub(crate) trait RegisterMapper<Reg> {
|
||||||
/// Maps Reg.
|
/// Maps Reg.
|
||||||
fn map(&self, reg: Reg) -> Result<Register, RegisterMappingError>;
|
fn map(&self, reg: Reg) -> Result<Register, RegisterMappingError>;
|
||||||
/// Gets RSP in gimli's index space.
|
/// Gets stack pointer register.
|
||||||
fn rsp(&self) -> Register;
|
fn sp(&self) -> Register;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents unwind information for a single System V ABI function.
|
/// Represents unwind information for a single System V ABI function.
|
||||||
@@ -118,9 +118,9 @@ impl UnwindInfo {
|
|||||||
map_reg: &'b dyn RegisterMapper<Reg>,
|
map_reg: &'b dyn RegisterMapper<Reg>,
|
||||||
) -> CodegenResult<Self> {
|
) -> CodegenResult<Self> {
|
||||||
use input::UnwindCode;
|
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
|
unwind
|
||||||
.epilogues_unwind_codes
|
.epilogues_unwind_codes
|
||||||
.iter()
|
.iter()
|
||||||
@@ -128,38 +128,36 @@ impl UnwindInfo {
|
|||||||
.flatten(),
|
.flatten(),
|
||||||
) {
|
) {
|
||||||
match c {
|
match c {
|
||||||
UnwindCode::SaveRegister {
|
UnwindCode::SaveRegister { reg, stack_offset } => {
|
||||||
offset,
|
|
||||||
reg,
|
|
||||||
stack_offset: 0,
|
|
||||||
} => {
|
|
||||||
builder
|
builder
|
||||||
.save_reg(*offset, *reg)
|
.save_reg(*offset, *reg, *stack_offset)
|
||||||
.map_err(CodegenError::RegisterMappingError)?;
|
.map_err(CodegenError::RegisterMappingError)?;
|
||||||
}
|
}
|
||||||
UnwindCode::StackAlloc { offset, size } => {
|
UnwindCode::StackAlloc { size } => {
|
||||||
builder.adjust_sp_down_imm(*offset, *size as i64);
|
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);
|
builder.adjust_sp_up_imm(*offset, *size as i64);
|
||||||
}
|
}
|
||||||
UnwindCode::RestoreRegister { offset, reg } => {
|
UnwindCode::RestoreRegister { reg } => {
|
||||||
builder
|
builder
|
||||||
.restore_reg(*offset, *reg)
|
.restore_reg(*offset, *reg)
|
||||||
.map_err(CodegenError::RegisterMappingError)?;
|
.map_err(CodegenError::RegisterMappingError)?;
|
||||||
}
|
}
|
||||||
UnwindCode::SetFramePointer { offset, reg } => {
|
UnwindCode::SetFramePointer { reg } => {
|
||||||
builder
|
builder
|
||||||
.set_cfa_reg(*offset, *reg)
|
.set_cfa_reg(*offset, *reg)
|
||||||
.map_err(CodegenError::RegisterMappingError)?;
|
.map_err(CodegenError::RegisterMappingError)?;
|
||||||
}
|
}
|
||||||
UnwindCode::RememberState { offset } => {
|
UnwindCode::RestoreFramePointer => {
|
||||||
|
builder.restore_cfa(*offset);
|
||||||
|
}
|
||||||
|
UnwindCode::RememberState => {
|
||||||
builder.remember_state(*offset);
|
builder.remember_state(*offset);
|
||||||
}
|
}
|
||||||
UnwindCode::RestoreState { offset } => {
|
UnwindCode::RestoreState => {
|
||||||
builder.restore_state(*offset);
|
builder.restore_state(*offset);
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,9 +188,9 @@ struct InstructionBuilder<'a, Reg: PartialEq + Copy> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Reg: PartialEq + Copy> InstructionBuilder<'a, Reg> {
|
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 {
|
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,
|
saved_state: None,
|
||||||
frame_register: None,
|
frame_register: None,
|
||||||
map_reg,
|
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
|
// Pushes in the prologue are register saves, so record an offset of the save
|
||||||
self.instructions.push((
|
self.instructions.push((
|
||||||
offset,
|
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(())
|
Ok(())
|
||||||
@@ -270,15 +276,16 @@ impl<'a, Reg: PartialEq + Copy> InstructionBuilder<'a, Reg> {
|
|||||||
Ok(())
|
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> {
|
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
|
// Pops in the epilogue are register restores, so record a "same value" for the register
|
||||||
self.instructions.push((
|
self.instructions.push((
|
||||||
offset,
|
offset,
|
||||||
|
|||||||
@@ -226,13 +226,9 @@ impl UnwindInfo {
|
|||||||
|
|
||||||
let word_size: u32 = unwind.word_size.into();
|
let word_size: u32 = unwind.word_size.into();
|
||||||
let mut unwind_codes = Vec::new();
|
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 {
|
match c {
|
||||||
InputUnwindCode::SaveRegister {
|
InputUnwindCode::SaveRegister { reg, stack_offset } => {
|
||||||
offset,
|
|
||||||
reg,
|
|
||||||
stack_offset,
|
|
||||||
} => {
|
|
||||||
let reg = MR::map(*reg);
|
let reg = MR::map(*reg);
|
||||||
let offset = ensure_unwind_offset(*offset)?;
|
let offset = ensure_unwind_offset(*offset)?;
|
||||||
match reg {
|
match reg {
|
||||||
@@ -269,7 +265,7 @@ impl UnwindInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputUnwindCode::StackAlloc { offset, size } => {
|
InputUnwindCode::StackAlloc { size } => {
|
||||||
unwind_codes.push(UnwindCode::StackAlloc {
|
unwind_codes.push(UnwindCode::StackAlloc {
|
||||||
offset: ensure_unwind_offset(*offset)?,
|
offset: ensure_unwind_offset(*offset)?,
|
||||||
size: *size,
|
size: *size,
|
||||||
|
|||||||
@@ -1,36 +1,125 @@
|
|||||||
use super::Inst;
|
use crate::isa::unwind::input::UnwindInfo;
|
||||||
use crate::isa::unwind::UnwindInfo;
|
use crate::isa::x64::inst::{
|
||||||
use crate::machinst::{UnwindInfoContext, UnwindInfoGenerator, UnwindInfoKind};
|
args::{AluRmiROpcode, Amode, RegMemImm, SyntheticAmode},
|
||||||
|
regs, Inst,
|
||||||
|
};
|
||||||
|
use crate::machinst::{UnwindInfoContext, UnwindInfoGenerator};
|
||||||
use crate::result::CodegenResult;
|
use crate::result::CodegenResult;
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use regalloc::Reg;
|
||||||
|
|
||||||
#[cfg(feature = "unwind")]
|
#[cfg(feature = "unwind")]
|
||||||
pub use self::systemv::create_cie;
|
pub(crate) mod systemv;
|
||||||
|
|
||||||
#[cfg(feature = "unwind")]
|
|
||||||
mod systemv;
|
|
||||||
|
|
||||||
pub struct X64UnwindInfo;
|
pub struct X64UnwindInfo;
|
||||||
|
|
||||||
impl UnwindInfoGenerator<Inst> for X64UnwindInfo {
|
impl UnwindInfoGenerator<Inst> for X64UnwindInfo {
|
||||||
#[allow(unused_variables)]
|
|
||||||
fn create_unwind_info(
|
fn create_unwind_info(
|
||||||
context: UnwindInfoContext<Inst>,
|
context: UnwindInfoContext<Inst>,
|
||||||
kind: UnwindInfoKind,
|
) -> CodegenResult<Option<UnwindInfo<Reg>>> {
|
||||||
) -> CodegenResult<Option<UnwindInfo>> {
|
use crate::isa::unwind::input::{self, UnwindCode};
|
||||||
// Assumption: RBP is being used as the frame pointer for both calling conventions
|
let mut codes = Vec::new();
|
||||||
// In the future, we should be omitting frame pointer as an optimization, so this will change
|
const WORD_SIZE: u8 = 8;
|
||||||
Ok(match kind {
|
|
||||||
#[cfg(feature = "unwind")]
|
for i in context.prologue.clone() {
|
||||||
UnwindInfoKind::SystemV => {
|
let i = i as usize;
|
||||||
const WORD_SIZE: u8 = 8;
|
let inst = &context.insts[i];
|
||||||
systemv::create_unwind_info(context, WORD_SIZE)?.map(UnwindInfo::SystemV)
|
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))
|
let last_epilogue_end = context.len;
|
||||||
panic!();
|
let epilogues_unwind_codes = context
|
||||||
}
|
.epilogues
|
||||||
UnwindInfoKind::None => None,
|
.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,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,8 @@
|
|||||||
//! Unwind information for System V ABI (x86-64).
|
//! Unwind information for System V ABI (x86-64).
|
||||||
|
|
||||||
|
use crate::isa::unwind::input;
|
||||||
use crate::isa::unwind::systemv::{RegisterMappingError, UnwindInfo};
|
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 crate::result::CodegenResult;
|
||||||
use alloc::vec::Vec;
|
|
||||||
use gimli::{write::CommonInformationEntry, Encoding, Format, Register, X86_64};
|
use gimli::{write::CommonInformationEntry, Encoding, Format, Register, X86_64};
|
||||||
use regalloc::{Reg, RegClass};
|
use regalloc::{Reg, RegClass};
|
||||||
|
|
||||||
@@ -88,113 +83,15 @@ pub fn map_reg(reg: Reg) -> Result<Register, RegisterMappingError> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn create_unwind_info(
|
pub(crate) fn create_unwind_info(
|
||||||
context: UnwindInfoContext<Inst>,
|
unwind: input::UnwindInfo<Reg>,
|
||||||
word_size: u8,
|
|
||||||
) -> CodegenResult<Option<UnwindInfo>> {
|
) -> 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;
|
struct RegisterMapper;
|
||||||
impl crate::isa::unwind::systemv::RegisterMapper<Reg> for RegisterMapper {
|
impl crate::isa::unwind::systemv::RegisterMapper<Reg> for RegisterMapper {
|
||||||
fn map(&self, reg: Reg) -> Result<u16, RegisterMappingError> {
|
fn map(&self, reg: Reg) -> Result<u16, RegisterMappingError> {
|
||||||
Ok(map_reg(reg)?.0)
|
Ok(map_reg(reg)?.0)
|
||||||
}
|
}
|
||||||
fn rsp(&self) -> u16 {
|
fn sp(&self) -> u16 {
|
||||||
map_reg(regs::rsp()).unwrap().0
|
X86_64::RSP.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let map = RegisterMapper;
|
let map = RegisterMapper;
|
||||||
|
|||||||
@@ -103,10 +103,29 @@ impl MachBackend for X64Backend {
|
|||||||
IntCC::UnsignedGreaterThanOrEqual
|
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")]
|
#[cfg(feature = "unwind")]
|
||||||
fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
|
fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
|
||||||
// By default, an ISA cannot create a System V CIE
|
Some(inst::unwind::systemv::create_cie())
|
||||||
Some(inst::unwind::create_cie())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ pub(crate) fn create_unwind_info(
|
|||||||
unwind_codes = epilogues_unwind_codes.last_mut().unwrap();
|
unwind_codes = epilogues_unwind_codes.last_mut().unwrap();
|
||||||
|
|
||||||
if !is_last_block {
|
if !is_last_block {
|
||||||
unwind_codes.push(UnwindCode::RememberState { offset });
|
unwind_codes.push((offset, UnwindCode::RememberState));
|
||||||
}
|
}
|
||||||
} else if in_epilogue {
|
} else if in_epilogue {
|
||||||
unwind_codes = epilogues_unwind_codes.last_mut().unwrap();
|
unwind_codes = epilogues_unwind_codes.last_mut().unwrap();
|
||||||
@@ -95,15 +95,19 @@ pub(crate) fn create_unwind_info(
|
|||||||
match opcode {
|
match opcode {
|
||||||
Opcode::X86Push => {
|
Opcode::X86Push => {
|
||||||
let reg = func.locations[arg].unwrap_reg();
|
let reg = func.locations[arg].unwrap_reg();
|
||||||
unwind_codes.push(UnwindCode::StackAlloc {
|
unwind_codes.push((
|
||||||
offset,
|
offset,
|
||||||
size: word_size.into(),
|
UnwindCode::StackAlloc {
|
||||||
});
|
size: word_size.into(),
|
||||||
unwind_codes.push(UnwindCode::SaveRegister {
|
},
|
||||||
|
));
|
||||||
|
unwind_codes.push((
|
||||||
offset,
|
offset,
|
||||||
reg,
|
UnwindCode::SaveRegister {
|
||||||
stack_offset: 0,
|
reg,
|
||||||
});
|
stack_offset: 0,
|
||||||
|
},
|
||||||
|
));
|
||||||
}
|
}
|
||||||
Opcode::AdjustSpDown => {
|
Opcode::AdjustSpDown => {
|
||||||
let stack_size =
|
let stack_size =
|
||||||
@@ -111,10 +115,8 @@ pub(crate) fn create_unwind_info(
|
|||||||
|
|
||||||
// This is used when calling a stack check function
|
// This is used when calling a stack check function
|
||||||
// We need to track the assignment to RAX which has the size of the stack
|
// We need to track the assignment to RAX which has the size of the stack
|
||||||
unwind_codes.push(UnwindCode::StackAlloc {
|
unwind_codes
|
||||||
offset,
|
.push((offset, UnwindCode::StackAlloc { size: stack_size }));
|
||||||
size: stack_size,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@@ -138,10 +140,8 @@ pub(crate) fn create_unwind_info(
|
|||||||
|
|
||||||
stack_size = Some(imm as u32);
|
stack_size = Some(imm as u32);
|
||||||
|
|
||||||
unwind_codes.push(UnwindCode::StackAlloc {
|
unwind_codes
|
||||||
offset,
|
.push((offset, UnwindCode::StackAlloc { size: imm as u32 }));
|
||||||
size: imm as u32,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
Opcode::AdjustSpUpImm => {
|
Opcode::AdjustSpUpImm => {
|
||||||
let imm: i64 = imm.into();
|
let imm: i64 = imm.into();
|
||||||
@@ -149,10 +149,8 @@ pub(crate) fn create_unwind_info(
|
|||||||
|
|
||||||
stack_size = Some(imm as u32);
|
stack_size = Some(imm as u32);
|
||||||
|
|
||||||
unwind_codes.push(UnwindCode::StackDealloc {
|
unwind_codes
|
||||||
offset,
|
.push((offset, UnwindCode::StackDealloc { size: imm as u32 }));
|
||||||
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
|
// Note: the stack_offset here is relative to an adjusted SP
|
||||||
if dst == (RU::rsp as RegUnit) && FPR.contains(src) {
|
if dst == (RU::rsp as RegUnit) && FPR.contains(src) {
|
||||||
let stack_offset: i32 = stack_offset.into();
|
let stack_offset: i32 = stack_offset.into();
|
||||||
unwind_codes.push(UnwindCode::SaveRegister {
|
unwind_codes.push((
|
||||||
offset,
|
offset,
|
||||||
reg: src,
|
UnwindCode::SaveRegister {
|
||||||
stack_offset: stack_offset as u32,
|
reg: src,
|
||||||
});
|
stack_offset: stack_offset as u32,
|
||||||
|
},
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InstructionData::CopySpecial { src, dst, .. } if frame_register.is_none() => {
|
InstructionData::CopySpecial { src, dst, .. } if frame_register.is_none() => {
|
||||||
// Check for change in CFA register (RSP is always the starting CFA)
|
// Check for change in CFA register (RSP is always the starting CFA)
|
||||||
if src == (RU::rsp as RegUnit) {
|
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);
|
frame_register = Some(dst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -203,18 +203,25 @@ pub(crate) fn create_unwind_info(
|
|||||||
let offset = epilogue_pop_offsets[i];
|
let offset = epilogue_pop_offsets[i];
|
||||||
|
|
||||||
let reg = func.locations[*arg].unwrap_reg();
|
let reg = func.locations[*arg].unwrap_reg();
|
||||||
unwind_codes.push(UnwindCode::RestoreRegister { offset, reg });
|
unwind_codes.push((offset, UnwindCode::RestoreRegister { reg }));
|
||||||
unwind_codes.push(UnwindCode::StackDealloc {
|
unwind_codes.push((
|
||||||
offset,
|
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();
|
epilogue_pop_offsets.clear();
|
||||||
|
|
||||||
// TODO ensure unwind codes sorted by offsets ?
|
// TODO ensure unwind codes sorted by offsets ?
|
||||||
|
|
||||||
if !is_last_block {
|
if !is_last_block {
|
||||||
unwind_codes.push(UnwindCode::RestoreState { offset });
|
unwind_codes.push((offset, UnwindCode::RestoreState));
|
||||||
}
|
}
|
||||||
|
|
||||||
in_epilogue = false;
|
in_epilogue = false;
|
||||||
@@ -232,6 +239,7 @@ pub(crate) fn create_unwind_info(
|
|||||||
epilogues_unwind_codes,
|
epilogues_unwind_codes,
|
||||||
function_size,
|
function_size,
|
||||||
word_size,
|
word_size,
|
||||||
|
initial_sp_offset: word_size,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,37 +279,36 @@ mod tests {
|
|||||||
UnwindInfo {
|
UnwindInfo {
|
||||||
prologue_size: 9,
|
prologue_size: 9,
|
||||||
prologue_unwind_codes: vec![
|
prologue_unwind_codes: vec![
|
||||||
UnwindCode::StackAlloc { offset: 2, size: 8 },
|
(2, UnwindCode::StackAlloc { size: 8 }),
|
||||||
UnwindCode::SaveRegister {
|
(
|
||||||
offset: 2,
|
2,
|
||||||
reg: RU::rbp.into(),
|
UnwindCode::SaveRegister {
|
||||||
stack_offset: 0,
|
reg: RU::rbp.into(),
|
||||||
},
|
stack_offset: 0,
|
||||||
UnwindCode::SetFramePointer {
|
}
|
||||||
offset: 5,
|
),
|
||||||
reg: RU::rbp.into(),
|
(
|
||||||
},
|
5,
|
||||||
UnwindCode::StackAlloc {
|
UnwindCode::SetFramePointer {
|
||||||
offset: 9,
|
reg: RU::rbp.into(),
|
||||||
size: 64
|
}
|
||||||
}
|
),
|
||||||
|
(9, UnwindCode::StackAlloc { size: 64 })
|
||||||
],
|
],
|
||||||
epilogues_unwind_codes: vec![vec![
|
epilogues_unwind_codes: vec![vec![
|
||||||
UnwindCode::StackDealloc {
|
(13, UnwindCode::StackDealloc { size: 64 }),
|
||||||
offset: 13,
|
(
|
||||||
size: 64
|
15,
|
||||||
},
|
UnwindCode::RestoreRegister {
|
||||||
UnwindCode::RestoreRegister {
|
reg: RU::rbp.into()
|
||||||
offset: 15,
|
}
|
||||||
reg: RU::rbp.into()
|
),
|
||||||
},
|
(15, UnwindCode::StackDealloc { size: 8 }),
|
||||||
UnwindCode::StackDealloc {
|
(15, UnwindCode::RestoreFramePointer)
|
||||||
offset: 15,
|
|
||||||
size: 8
|
|
||||||
}
|
|
||||||
]],
|
]],
|
||||||
function_size: 16,
|
function_size: 16,
|
||||||
word_size: 8,
|
word_size: 8,
|
||||||
|
initial_sp_offset: 8,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -329,37 +336,36 @@ mod tests {
|
|||||||
UnwindInfo {
|
UnwindInfo {
|
||||||
prologue_size: 27,
|
prologue_size: 27,
|
||||||
prologue_unwind_codes: vec![
|
prologue_unwind_codes: vec![
|
||||||
UnwindCode::StackAlloc { offset: 2, size: 8 },
|
(2, UnwindCode::StackAlloc { size: 8 }),
|
||||||
UnwindCode::SaveRegister {
|
(
|
||||||
offset: 2,
|
2,
|
||||||
reg: RU::rbp.into(),
|
UnwindCode::SaveRegister {
|
||||||
stack_offset: 0,
|
reg: RU::rbp.into(),
|
||||||
},
|
stack_offset: 0,
|
||||||
UnwindCode::SetFramePointer {
|
}
|
||||||
offset: 5,
|
),
|
||||||
reg: RU::rbp.into(),
|
(
|
||||||
},
|
5,
|
||||||
UnwindCode::StackAlloc {
|
UnwindCode::SetFramePointer {
|
||||||
offset: 27,
|
reg: RU::rbp.into(),
|
||||||
size: 10000
|
}
|
||||||
}
|
),
|
||||||
|
(27, UnwindCode::StackAlloc { size: 10000 })
|
||||||
],
|
],
|
||||||
epilogues_unwind_codes: vec![vec![
|
epilogues_unwind_codes: vec![vec![
|
||||||
UnwindCode::StackDealloc {
|
(34, UnwindCode::StackDealloc { size: 10000 }),
|
||||||
offset: 34,
|
(
|
||||||
size: 10000
|
36,
|
||||||
},
|
UnwindCode::RestoreRegister {
|
||||||
UnwindCode::RestoreRegister {
|
reg: RU::rbp.into()
|
||||||
offset: 36,
|
}
|
||||||
reg: RU::rbp.into()
|
),
|
||||||
},
|
(36, UnwindCode::StackDealloc { size: 8 }),
|
||||||
UnwindCode::StackDealloc {
|
(36, UnwindCode::RestoreFramePointer)
|
||||||
offset: 36,
|
|
||||||
size: 8
|
|
||||||
}
|
|
||||||
]],
|
]],
|
||||||
function_size: 37,
|
function_size: 37,
|
||||||
word_size: 8,
|
word_size: 8,
|
||||||
|
initial_sp_offset: 8,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -387,37 +393,36 @@ mod tests {
|
|||||||
UnwindInfo {
|
UnwindInfo {
|
||||||
prologue_size: 27,
|
prologue_size: 27,
|
||||||
prologue_unwind_codes: vec![
|
prologue_unwind_codes: vec![
|
||||||
UnwindCode::StackAlloc { offset: 2, size: 8 },
|
(2, UnwindCode::StackAlloc { size: 8 }),
|
||||||
UnwindCode::SaveRegister {
|
(
|
||||||
offset: 2,
|
2,
|
||||||
reg: RU::rbp.into(),
|
UnwindCode::SaveRegister {
|
||||||
stack_offset: 0,
|
reg: RU::rbp.into(),
|
||||||
},
|
stack_offset: 0,
|
||||||
UnwindCode::SetFramePointer {
|
}
|
||||||
offset: 5,
|
),
|
||||||
reg: RU::rbp.into(),
|
(
|
||||||
},
|
5,
|
||||||
UnwindCode::StackAlloc {
|
UnwindCode::SetFramePointer {
|
||||||
offset: 27,
|
reg: RU::rbp.into(),
|
||||||
size: 1000000
|
}
|
||||||
}
|
),
|
||||||
|
(27, UnwindCode::StackAlloc { size: 1000000 })
|
||||||
],
|
],
|
||||||
epilogues_unwind_codes: vec![vec![
|
epilogues_unwind_codes: vec![vec![
|
||||||
UnwindCode::StackDealloc {
|
(34, UnwindCode::StackDealloc { size: 1000000 }),
|
||||||
offset: 34,
|
(
|
||||||
size: 1000000
|
36,
|
||||||
},
|
UnwindCode::RestoreRegister {
|
||||||
UnwindCode::RestoreRegister {
|
reg: RU::rbp.into()
|
||||||
offset: 36,
|
}
|
||||||
reg: RU::rbp.into()
|
),
|
||||||
},
|
(36, UnwindCode::StackDealloc { size: 8 }),
|
||||||
UnwindCode::StackDealloc {
|
(36, UnwindCode::RestoreFramePointer)
|
||||||
offset: 36,
|
|
||||||
size: 8
|
|
||||||
}
|
|
||||||
]],
|
]],
|
||||||
function_size: 37,
|
function_size: 37,
|
||||||
word_size: 8,
|
word_size: 8,
|
||||||
|
initial_sp_offset: 8,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -458,43 +463,48 @@ mod tests {
|
|||||||
UnwindInfo {
|
UnwindInfo {
|
||||||
prologue_size: 5,
|
prologue_size: 5,
|
||||||
prologue_unwind_codes: vec![
|
prologue_unwind_codes: vec![
|
||||||
UnwindCode::StackAlloc { offset: 2, size: 8 },
|
(2, UnwindCode::StackAlloc { size: 8 }),
|
||||||
UnwindCode::SaveRegister {
|
(
|
||||||
offset: 2,
|
2,
|
||||||
reg: RU::rbp.into(),
|
UnwindCode::SaveRegister {
|
||||||
stack_offset: 0,
|
reg: RU::rbp.into(),
|
||||||
},
|
stack_offset: 0,
|
||||||
UnwindCode::SetFramePointer {
|
}
|
||||||
offset: 5,
|
),
|
||||||
reg: RU::rbp.into()
|
(
|
||||||
}
|
5,
|
||||||
|
UnwindCode::SetFramePointer {
|
||||||
|
reg: RU::rbp.into()
|
||||||
|
}
|
||||||
|
)
|
||||||
],
|
],
|
||||||
epilogues_unwind_codes: vec![
|
epilogues_unwind_codes: vec![
|
||||||
vec![
|
vec![
|
||||||
UnwindCode::RememberState { offset: 12 },
|
(12, UnwindCode::RememberState),
|
||||||
UnwindCode::RestoreRegister {
|
(
|
||||||
offset: 12,
|
12,
|
||||||
reg: RU::rbp.into()
|
UnwindCode::RestoreRegister {
|
||||||
},
|
reg: RU::rbp.into()
|
||||||
UnwindCode::StackDealloc {
|
}
|
||||||
offset: 12,
|
),
|
||||||
size: 8
|
(12, UnwindCode::StackDealloc { size: 8 }),
|
||||||
},
|
(12, UnwindCode::RestoreFramePointer),
|
||||||
UnwindCode::RestoreState { offset: 13 }
|
(13, UnwindCode::RestoreState)
|
||||||
],
|
],
|
||||||
vec![
|
vec![
|
||||||
UnwindCode::RestoreRegister {
|
(
|
||||||
offset: 15,
|
15,
|
||||||
reg: RU::rbp.into()
|
UnwindCode::RestoreRegister {
|
||||||
},
|
reg: RU::rbp.into()
|
||||||
UnwindCode::StackDealloc {
|
}
|
||||||
offset: 15,
|
),
|
||||||
size: 8
|
(15, UnwindCode::StackDealloc { size: 8 }),
|
||||||
}
|
(15, UnwindCode::RestoreFramePointer)
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
function_size: 16,
|
function_size: 16,
|
||||||
word_size: 8,
|
word_size: 8,
|
||||||
|
initial_sp_offset: 8,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ pub(crate) fn create_unwind_info(
|
|||||||
fn map(&self, reg: RegUnit) -> Result<u16, RegisterMappingError> {
|
fn map(&self, reg: RegUnit) -> Result<u16, RegisterMappingError> {
|
||||||
Ok(map_reg(self.0, reg)?.0)
|
Ok(map_reg(self.0, reg)?.0)
|
||||||
}
|
}
|
||||||
fn rsp(&self) -> u16 {
|
fn sp(&self) -> u16 {
|
||||||
X86_64::RSP.0
|
X86_64::RSP.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -165,7 +165,7 @@ mod tests {
|
|||||||
_ => panic!("expected unwind information"),
|
_ => 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 {
|
fn create_function(call_conv: CallConv, stack_slot: Option<StackSlotData>) -> Function {
|
||||||
@@ -205,7 +205,7 @@ mod tests {
|
|||||||
_ => panic!("expected unwind information"),
|
_ => 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 {
|
fn create_multi_return_function(call_conv: CallConv) -> Function {
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ impl TargetIsa for TargetIsaAdapter {
|
|||||||
self.backend.unsigned_sub_overflow_condition()
|
self.backend.unsigned_sub_overflow_condition()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "unwind")]
|
#[cfg(all(feature = "unwind", feature = "x64"))]
|
||||||
fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
|
fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
|
||||||
self.backend.create_systemv_cie()
|
self.backend.create_systemv_cie()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,7 +99,7 @@
|
|||||||
use crate::binemit::{CodeInfo, CodeOffset, StackMap};
|
use crate::binemit::{CodeInfo, CodeOffset, StackMap};
|
||||||
use crate::ir::condcodes::IntCC;
|
use crate::ir::condcodes::IntCC;
|
||||||
use crate::ir::{Function, Type};
|
use crate::ir::{Function, Type};
|
||||||
use crate::isa::unwind;
|
use crate::isa::unwind::input as unwind_input;
|
||||||
use crate::result::CodegenResult;
|
use crate::result::CodegenResult;
|
||||||
use crate::settings::Flags;
|
use crate::settings::Flags;
|
||||||
|
|
||||||
@@ -314,7 +314,7 @@ pub struct MachCompileResult {
|
|||||||
/// Disassembly, if requested.
|
/// Disassembly, if requested.
|
||||||
pub disasm: Option<String>,
|
pub disasm: Option<String>,
|
||||||
/// Unwind info.
|
/// Unwind info.
|
||||||
pub unwind_info: Option<unwind::UnwindInfo>,
|
pub unwind_info: Option<unwind_input::UnwindInfo<Reg>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MachCompileResult {
|
impl MachCompileResult {
|
||||||
@@ -360,6 +360,17 @@ pub trait MachBackend {
|
|||||||
/// Condition that will be true when an IsubIfcout overflows.
|
/// Condition that will be true when an IsubIfcout overflows.
|
||||||
fn unsigned_sub_overflow_condition(&self) -> IntCC;
|
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.
|
/// Machine-specific condcode info needed by TargetIsa.
|
||||||
/// Creates a new System V Common Information Entry for the ISA.
|
/// Creates a new System V Common Information Entry for the ISA.
|
||||||
#[cfg(feature = "unwind")]
|
#[cfg(feature = "unwind")]
|
||||||
@@ -403,6 +414,5 @@ pub trait UnwindInfoGenerator<I: MachInstEmit> {
|
|||||||
/// emitted instructions.
|
/// emitted instructions.
|
||||||
fn create_unwind_info(
|
fn create_unwind_info(
|
||||||
context: UnwindInfoContext<I>,
|
context: UnwindInfoContext<I>,
|
||||||
kind: UnwindInfoKind,
|
) -> CodegenResult<Option<unwind_input::UnwindInfo<Reg>>>;
|
||||||
) -> CodegenResult<Option<unwind::UnwindInfo>>;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -560,7 +560,7 @@ impl<I: VCodeInst> VCode<I> {
|
|||||||
/// Generates unwind info.
|
/// Generates unwind info.
|
||||||
pub fn unwind_info(
|
pub fn unwind_info(
|
||||||
&self,
|
&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 layout = &self.insts_layout.borrow();
|
||||||
let (prologue, epilogues) = self.prologue_epilogue_ranges.as_ref().unwrap();
|
let (prologue, epilogues) = self.prologue_epilogue_ranges.as_ref().unwrap();
|
||||||
let context = UnwindInfoContext {
|
let context = UnwindInfoContext {
|
||||||
@@ -570,7 +570,7 @@ impl<I: VCodeInst> VCode<I> {
|
|||||||
prologue: prologue.clone(),
|
prologue: prologue.clone(),
|
||||||
epilogues,
|
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.
|
/// Get the IR block for a BlockIndex, if one exists.
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ block0:
|
|||||||
; nextln: DW_CFA_advance_loc (3)
|
; nextln: DW_CFA_advance_loc (3)
|
||||||
; nextln: DW_CFA_def_cfa_register (r6)
|
; nextln: DW_CFA_def_cfa_register (r6)
|
||||||
; nextln: DW_CFA_advance_loc (1)
|
; nextln: DW_CFA_advance_loc (1)
|
||||||
; nextln: DW_CFA_def_cfa (r7, 8)
|
|
||||||
; nextln: DW_CFA_same_value (r6)
|
; nextln: DW_CFA_same_value (r6)
|
||||||
|
; nextln: DW_CFA_def_cfa (r7, 8)
|
||||||
; nextln: DW_CFA_nop
|
; nextln: DW_CFA_nop
|
||||||
|
|
||||||
; check a function with medium-sized stack alloc
|
; check a function with medium-sized stack alloc
|
||||||
@@ -76,8 +76,8 @@ block0:
|
|||||||
; nextln: DW_CFA_advance_loc (3)
|
; nextln: DW_CFA_advance_loc (3)
|
||||||
; nextln: DW_CFA_def_cfa_register (r6)
|
; nextln: DW_CFA_def_cfa_register (r6)
|
||||||
; nextln: DW_CFA_advance_loc (21)
|
; nextln: DW_CFA_advance_loc (21)
|
||||||
; nextln: DW_CFA_def_cfa (r7, 8)
|
|
||||||
; nextln: DW_CFA_same_value (r6)
|
; nextln: DW_CFA_same_value (r6)
|
||||||
|
; nextln: DW_CFA_def_cfa (r7, 8)
|
||||||
; nextln: DW_CFA_nop
|
; nextln: DW_CFA_nop
|
||||||
|
|
||||||
; check a function with large-sized stack alloc
|
; check a function with large-sized stack alloc
|
||||||
@@ -115,8 +115,8 @@ block0:
|
|||||||
; nextln: DW_CFA_advance_loc (3)
|
; nextln: DW_CFA_advance_loc (3)
|
||||||
; nextln: DW_CFA_def_cfa_register (r6)
|
; nextln: DW_CFA_def_cfa_register (r6)
|
||||||
; nextln: DW_CFA_advance_loc (21)
|
; nextln: DW_CFA_advance_loc (21)
|
||||||
; nextln: DW_CFA_def_cfa (r7, 8)
|
|
||||||
; nextln: DW_CFA_same_value (r6)
|
; nextln: DW_CFA_same_value (r6)
|
||||||
|
; nextln: DW_CFA_def_cfa (r7, 8)
|
||||||
; nextln: DW_CFA_nop
|
; nextln: DW_CFA_nop
|
||||||
; nextln:
|
; nextln:
|
||||||
|
|
||||||
@@ -200,7 +200,6 @@ block0(v0: i64, v1: i64):
|
|||||||
; nextln: DW_CFA_advance_loc (1)
|
; nextln: DW_CFA_advance_loc (1)
|
||||||
; nextln: DW_CFA_same_value (r3)
|
; nextln: DW_CFA_same_value (r3)
|
||||||
; nextln: DW_CFA_advance_loc (1)
|
; nextln: DW_CFA_advance_loc (1)
|
||||||
; nextln: DW_CFA_def_cfa (r7, 8)
|
|
||||||
; nextln: DW_CFA_same_value (r6)
|
; nextln: DW_CFA_same_value (r6)
|
||||||
; nextln: DW_CFA_nop
|
; nextln: DW_CFA_def_cfa (r7, 8)
|
||||||
; nextln: DW_CFA_nop
|
; nextln: DW_CFA_nop
|
||||||
|
|||||||
Reference in New Issue
Block a user