diff --git a/cranelift/codegen/src/context.rs b/cranelift/codegen/src/context.rs index eb4cdf26f6..4eb0c3b127 100644 --- a/cranelift/codegen/src/context.rs +++ b/cranelift/codegen/src/context.rs @@ -253,13 +253,16 @@ impl Context { &self, isa: &dyn TargetIsa, ) -> CodegenResult> { - 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) } diff --git a/cranelift/codegen/src/isa/aarch64/inst/unwind.rs b/cranelift/codegen/src/isa/aarch64/inst/unwind.rs index 51aad46687..9ea2cb29c0 100644 --- a/cranelift/codegen/src/isa/aarch64/inst/unwind.rs +++ b/cranelift/codegen/src/isa/aarch64/inst/unwind.rs @@ -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 for AArch64UnwindInfo { fn create_unwind_info( _context: UnwindInfoContext, - _kind: UnwindInfoKind, - ) -> CodegenResult> { + ) -> CodegenResult>> { // TODO Ok(None) } diff --git a/cranelift/codegen/src/isa/arm32/inst/unwind.rs b/cranelift/codegen/src/isa/arm32/inst/unwind.rs index 78109ed6c1..b9ffeba0cf 100644 --- a/cranelift/codegen/src/isa/arm32/inst/unwind.rs +++ b/cranelift/codegen/src/isa/arm32/inst/unwind.rs @@ -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 for Arm32UnwindInfo { fn create_unwind_info( _context: UnwindInfoContext, - _kind: UnwindInfoKind, - ) -> CodegenResult> { + ) -> CodegenResult>> { // TODO Ok(None) } diff --git a/cranelift/codegen/src/isa/unwind.rs b/cranelift/codegen/src/isa/unwind.rs index 1d5324976a..a4c5f0b6b7 100644 --- a/cranelift/codegen/src/isa/unwind.rs +++ b/cranelift/codegen/src/isa/unwind.rs @@ -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 { + pub enum UnwindCode { + /// 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 { - pub(crate) prologue_size: CodeOffset, - pub(crate) prologue_unwind_codes: Vec>, - pub(crate) epilogues_unwind_codes: Vec>>, - 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)>, + /// Unwind codes for epilogues. + pub epilogues_unwind_codes: Vec)>>, + /// 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, } } diff --git a/cranelift/codegen/src/isa/unwind/systemv.rs b/cranelift/codegen/src/isa/unwind/systemv.rs index 3a3f14ab36..dfb2ef5936 100644 --- a/cranelift/codegen/src/isa/unwind/systemv.rs +++ b/cranelift/codegen/src/isa/unwind/systemv.rs @@ -98,8 +98,8 @@ impl Into for CallFrameInstruction { pub(crate) trait RegisterMapper { /// Maps Reg. fn map(&self, reg: Reg) -> Result; - /// 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, ) -> CodegenResult { 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 + 'a)) -> Self { + fn new(sp_offset: u8, map_reg: &'a (dyn RegisterMapper + '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, diff --git a/cranelift/codegen/src/isa/unwind/winx64.rs b/cranelift/codegen/src/isa/unwind/winx64.rs index 3d01982745..b3c21fc473 100644 --- a/cranelift/codegen/src/isa/unwind/winx64.rs +++ b/cranelift/codegen/src/isa/unwind/winx64.rs @@ -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, diff --git a/cranelift/codegen/src/isa/x64/inst/unwind.rs b/cranelift/codegen/src/isa/x64/inst/unwind.rs index 75107f058c..022b2e65fe 100644 --- a/cranelift/codegen/src/isa/x64/inst/unwind.rs +++ b/cranelift/codegen/src/isa/x64/inst/unwind.rs @@ -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 for X64UnwindInfo { - #[allow(unused_variables)] fn create_unwind_info( context: UnwindInfoContext, - kind: UnwindInfoKind, - ) -> CodegenResult> { - // 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>> { + 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, + })) } } diff --git a/cranelift/codegen/src/isa/x64/inst/unwind/systemv.rs b/cranelift/codegen/src/isa/x64/inst/unwind/systemv.rs index 8f940753d1..68473a8afb 100644 --- a/cranelift/codegen/src/isa/x64/inst/unwind/systemv.rs +++ b/cranelift/codegen/src/isa/x64/inst/unwind/systemv.rs @@ -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 { } pub(crate) fn create_unwind_info( - context: UnwindInfoContext, - word_size: u8, + unwind: input::UnwindInfo, ) -> CodegenResult> { - 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 for RegisterMapper { fn map(&self, reg: Reg) -> Result { 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; diff --git a/cranelift/codegen/src/isa/x64/mod.rs b/cranelift/codegen/src/isa/x64/mod.rs index 969447e923..fd4444498d 100644 --- a/cranelift/codegen/src/isa/x64/mod.rs +++ b/cranelift/codegen/src/isa/x64/mod.rs @@ -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> { + 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 { - // By default, an ISA cannot create a System V CIE - Some(inst::unwind::create_cie()) + Some(inst::unwind::systemv::create_cie()) } } diff --git a/cranelift/codegen/src/isa/x86/unwind.rs b/cranelift/codegen/src/isa/x86/unwind.rs index 3168cc49be..2d6b29f04d 100644 --- a/cranelift/codegen/src/isa/x86/unwind.rs +++ b/cranelift/codegen/src/isa/x86/unwind.rs @@ -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, } ); } diff --git a/cranelift/codegen/src/isa/x86/unwind/systemv.rs b/cranelift/codegen/src/isa/x86/unwind/systemv.rs index 3b1266e72f..f6333f5afb 100644 --- a/cranelift/codegen/src/isa/x86/unwind/systemv.rs +++ b/cranelift/codegen/src/isa/x86/unwind/systemv.rs @@ -118,7 +118,7 @@ pub(crate) fn create_unwind_info( fn map(&self, reg: RegUnit) -> Result { 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) -> 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 { diff --git a/cranelift/codegen/src/machinst/adapter.rs b/cranelift/codegen/src/machinst/adapter.rs index 43ff9e51a4..c312f76d4a 100644 --- a/cranelift/codegen/src/machinst/adapter.rs +++ b/cranelift/codegen/src/machinst/adapter.rs @@ -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 { self.backend.create_systemv_cie() } diff --git a/cranelift/codegen/src/machinst/mod.rs b/cranelift/codegen/src/machinst/mod.rs index 8d36ed6516..83b3c6f83b 100644 --- a/cranelift/codegen/src/machinst/mod.rs +++ b/cranelift/codegen/src/machinst/mod.rs @@ -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, /// Unwind info. - pub unwind_info: Option, + pub unwind_info: Option>, } 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> { + // 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 { /// emitted instructions. fn create_unwind_info( context: UnwindInfoContext, - kind: UnwindInfoKind, - ) -> CodegenResult>; + ) -> CodegenResult>>; } diff --git a/cranelift/codegen/src/machinst/vcode.rs b/cranelift/codegen/src/machinst/vcode.rs index 8705865d15..1a34ae988a 100644 --- a/cranelift/codegen/src/machinst/vcode.rs +++ b/cranelift/codegen/src/machinst/vcode.rs @@ -560,7 +560,7 @@ impl VCode { /// Generates unwind info. pub fn unwind_info( &self, - ) -> crate::result::CodegenResult> { + ) -> crate::result::CodegenResult>> { let layout = &self.insts_layout.borrow(); let (prologue, epilogues) = self.prologue_epilogue_ranges.as_ref().unwrap(); let context = UnwindInfoContext { @@ -570,7 +570,7 @@ impl VCode { 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. diff --git a/cranelift/filetests/filetests/isa/x86/systemv_x64_unwind.clif b/cranelift/filetests/filetests/isa/x86/systemv_x64_unwind.clif index cf0da2f4db..9d4053aee1 100644 --- a/cranelift/filetests/filetests/isa/x86/systemv_x64_unwind.clif +++ b/cranelift/filetests/filetests/isa/x86/systemv_x64_unwind.clif @@ -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