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:
@@ -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,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user