Path: blob/main/cranelift/codegen/src/isa/x64/inst/unwind/systemv.rs
1693 views
//! Unwind information for System V ABI (x86-64).12use crate::isa::unwind::systemv::RegisterMappingError;3use crate::machinst::{Reg, RegClass};4use gimli::{Encoding, Format, Register, X86_64, write::CommonInformationEntry};56/// Creates a new x86-64 common information entry (CIE).7pub fn create_cie() -> CommonInformationEntry {8use gimli::write::CallFrameInstruction;910let mut entry = CommonInformationEntry::new(11Encoding {12address_size: 8,13format: Format::Dwarf32,14version: 1,15},161, // Code alignment factor17-8, // Data alignment factor18X86_64::RA,19);2021// Every frame will start with the call frame address (CFA) at RSP+822// It is +8 to account for the push of the return address by the call instruction23entry.add_instruction(CallFrameInstruction::Cfa(X86_64::RSP, 8));2425// Every frame will start with the return address at RSP (CFA-8 = RSP+8-8 = RSP)26entry.add_instruction(CallFrameInstruction::Offset(X86_64::RA, -8));2728entry29}3031/// Map Cranelift registers to their corresponding Gimli registers.32pub fn map_reg(reg: Reg) -> Result<Register, RegisterMappingError> {33// Mapping from https://github.com/bytecodealliance/cranelift/pull/902 by @iximeow34const X86_GP_REG_MAP: [gimli::Register; 16] = [35X86_64::RAX,36X86_64::RCX,37X86_64::RDX,38X86_64::RBX,39X86_64::RSP,40X86_64::RBP,41X86_64::RSI,42X86_64::RDI,43X86_64::R8,44X86_64::R9,45X86_64::R10,46X86_64::R11,47X86_64::R12,48X86_64::R13,49X86_64::R14,50X86_64::R15,51];52const X86_XMM_REG_MAP: [gimli::Register; 16] = [53X86_64::XMM0,54X86_64::XMM1,55X86_64::XMM2,56X86_64::XMM3,57X86_64::XMM4,58X86_64::XMM5,59X86_64::XMM6,60X86_64::XMM7,61X86_64::XMM8,62X86_64::XMM9,63X86_64::XMM10,64X86_64::XMM11,65X86_64::XMM12,66X86_64::XMM13,67X86_64::XMM14,68X86_64::XMM15,69];7071match reg.class() {72RegClass::Int => {73// x86 GP registers have a weird mapping to DWARF registers, so we use a74// lookup table.75Ok(X86_GP_REG_MAP[reg.to_real_reg().unwrap().hw_enc() as usize])76}77RegClass::Float => Ok(X86_XMM_REG_MAP[reg.to_real_reg().unwrap().hw_enc() as usize]),78RegClass::Vector => unreachable!(),79}80}8182pub(crate) struct RegisterMapper;8384impl crate::isa::unwind::systemv::RegisterMapper<Reg> for RegisterMapper {85fn map(&self, reg: Reg) -> Result<u16, RegisterMappingError> {86Ok(map_reg(reg)?.0)87}88fn fp(&self) -> Option<u16> {89Some(X86_64::RBP.0)90}91}9293#[cfg(test)]94mod tests {95use crate::Context;96use crate::cursor::{Cursor, FuncCursor};97use crate::ir::{98AbiParam, Function, InstBuilder, Signature, StackSlotData, StackSlotKind, types,99};100use crate::isa::{CallConv, lookup};101use crate::settings::{Flags, builder};102use gimli::write::Address;103use target_lexicon::triple;104105#[test]106fn test_simple_func() {107let isa = lookup(triple!("x86_64"))108.expect("expect x86 ISA")109.finish(Flags::new(builder()))110.expect("expect backend creation to succeed");111112let mut context = Context::for_function(create_function(113CallConv::SystemV,114Some(StackSlotData::new(StackSlotKind::ExplicitSlot, 64, 0)),115));116117let code = context118.compile(&*isa, &mut Default::default())119.expect("expected compilation");120121let fde = match code122.create_unwind_info(isa.as_ref())123.expect("can create unwind info")124{125Some(crate::isa::unwind::UnwindInfo::SystemV(info)) => {126info.to_fde(Address::Constant(1234))127}128_ => panic!("expected unwind information"),129};130131assert_eq!(132format!("{fde:?}"),133"FrameDescriptionEntry { address: Constant(1234), length: 17, lsda: None, instructions: [(1, CfaOffset(16)), (1, Offset(Register(6), -16)), (4, CfaRegister(Register(6)))] }"134);135}136137fn create_function(call_conv: CallConv, stack_slot: Option<StackSlotData>) -> Function {138let mut func = Function::with_name_signature(Default::default(), Signature::new(call_conv));139140let block0 = func.dfg.make_block();141let mut pos = FuncCursor::new(&mut func);142pos.insert_block(block0);143pos.ins().return_(&[]);144145if let Some(stack_slot) = stack_slot {146func.sized_stack_slots.push(stack_slot);147}148149func150}151152#[test]153fn test_multi_return_func() {154let isa = lookup(triple!("x86_64"))155.expect("expect x86 ISA")156.finish(Flags::new(builder()))157.expect("expect backend creation to succeed");158159let mut context = Context::for_function(create_multi_return_function(CallConv::SystemV));160161let code = context162.compile(&*isa, &mut Default::default())163.expect("expected compilation");164165let fde = match code166.create_unwind_info(isa.as_ref())167.expect("can create unwind info")168{169Some(crate::isa::unwind::UnwindInfo::SystemV(info)) => {170info.to_fde(Address::Constant(4321))171}172_ => panic!("expected unwind information"),173};174175assert_eq!(176format!("{fde:?}"),177"FrameDescriptionEntry { address: Constant(4321), length: 22, lsda: None, instructions: [(1, CfaOffset(16)), (1, Offset(Register(6), -16)), (4, CfaRegister(Register(6)))] }"178);179}180181fn create_multi_return_function(call_conv: CallConv) -> Function {182let mut sig = Signature::new(call_conv);183sig.params.push(AbiParam::new(types::I32));184let mut func = Function::with_name_signature(Default::default(), sig);185186let block0 = func.dfg.make_block();187let v0 = func.dfg.append_block_param(block0, types::I32);188let block1 = func.dfg.make_block();189let block2 = func.dfg.make_block();190191let mut pos = FuncCursor::new(&mut func);192pos.insert_block(block0);193pos.ins().brif(v0, block2, &[], block1, &[]);194195pos.insert_block(block1);196pos.ins().return_(&[]);197198pos.insert_block(block2);199pos.ins().return_(&[]);200201func202}203}204205206