cranelift_codegen/isa/x64/inst/unwind/
systemv.rs1use crate::isa::unwind::systemv::RegisterMappingError;
4use crate::machinst::{Reg, RegClass};
5use gimli::{Encoding, Format, Register, X86_64, write::CommonInformationEntry};
6
7pub fn create_cie() -> CommonInformationEntry {
9 use gimli::write::CallFrameInstruction;
10
11 let mut entry = CommonInformationEntry::new(
12 Encoding {
13 address_size: 8,
14 format: Format::Dwarf32,
15 version: 1,
16 },
17 1, -8, X86_64::RA,
20 );
21
22 entry.add_instruction(CallFrameInstruction::Cfa(X86_64::RSP, 8));
25
26 entry.add_instruction(CallFrameInstruction::Offset(X86_64::RA, -8));
28
29 entry
30}
31
32pub fn map_reg(reg: Reg) -> Result<Register, RegisterMappingError> {
34 const X86_GP_REG_MAP: [gimli::Register; 16] = [
36 X86_64::RAX,
37 X86_64::RCX,
38 X86_64::RDX,
39 X86_64::RBX,
40 X86_64::RSP,
41 X86_64::RBP,
42 X86_64::RSI,
43 X86_64::RDI,
44 X86_64::R8,
45 X86_64::R9,
46 X86_64::R10,
47 X86_64::R11,
48 X86_64::R12,
49 X86_64::R13,
50 X86_64::R14,
51 X86_64::R15,
52 ];
53 const X86_XMM_REG_MAP: [gimli::Register; 16] = [
54 X86_64::XMM0,
55 X86_64::XMM1,
56 X86_64::XMM2,
57 X86_64::XMM3,
58 X86_64::XMM4,
59 X86_64::XMM5,
60 X86_64::XMM6,
61 X86_64::XMM7,
62 X86_64::XMM8,
63 X86_64::XMM9,
64 X86_64::XMM10,
65 X86_64::XMM11,
66 X86_64::XMM12,
67 X86_64::XMM13,
68 X86_64::XMM14,
69 X86_64::XMM15,
70 ];
71
72 match reg.class() {
73 RegClass::Int => {
74 Ok(X86_GP_REG_MAP[reg.to_real_reg().unwrap().hw_enc() as usize])
77 }
78 RegClass::Float => Ok(X86_XMM_REG_MAP[reg.to_real_reg().unwrap().hw_enc() as usize]),
79 RegClass::Vector => unreachable!(),
80 }
81}
82
83pub(crate) struct RegisterMapper;
84
85impl crate::isa::unwind::systemv::RegisterMapper<Reg> for RegisterMapper {
86 fn map(&self, reg: Reg) -> Result<u16, RegisterMappingError> {
87 Ok(map_reg(reg)?.0)
88 }
89 fn fp(&self) -> Option<u16> {
90 Some(X86_64::RBP.0)
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use crate::Context;
97 use crate::cursor::{Cursor, FuncCursor};
98 use crate::ir::{
99 AbiParam, Function, InstBuilder, Signature, StackSlotData, StackSlotKind, types,
100 };
101 use crate::isa::{CallConv, lookup};
102 use crate::settings::{Flags, builder};
103 use gimli::write::Address;
104 use target_lexicon::triple;
105
106 #[test]
107 fn test_simple_func() {
108 let isa = lookup(triple!("x86_64"))
109 .expect("expect x86 ISA")
110 .finish(Flags::new(builder()))
111 .expect("expect backend creation to succeed");
112
113 let mut context = Context::for_function(create_function(
114 CallConv::SystemV,
115 Some(StackSlotData::new(StackSlotKind::ExplicitSlot, 64, 0)),
116 ));
117
118 let code = context
119 .compile(&*isa, &mut Default::default())
120 .expect("expected compilation");
121
122 let fde = match code
123 .create_unwind_info(isa.as_ref())
124 .expect("can create unwind info")
125 {
126 Some(crate::isa::unwind::UnwindInfo::SystemV(info)) => {
127 info.to_fde(Address::Constant(1234))
128 }
129 _ => panic!("expected unwind information"),
130 };
131
132 assert_eq!(
133 format!("{fde:?}"),
134 "FrameDescriptionEntry { address: Constant(1234), length: 17, lsda: None, instructions: [(1, CfaOffset(16)), (1, Offset(Register(6), -16)), (4, CfaRegister(Register(6)))] }"
135 );
136 }
137
138 fn create_function(call_conv: CallConv, stack_slot: Option<StackSlotData>) -> Function {
139 let mut func = Function::with_name_signature(Default::default(), Signature::new(call_conv));
140
141 let block0 = func.dfg.make_block();
142 let mut pos = FuncCursor::new(&mut func);
143 pos.insert_block(block0);
144 pos.ins().return_(&[]);
145
146 if let Some(stack_slot) = stack_slot {
147 func.sized_stack_slots.push(stack_slot);
148 }
149
150 func
151 }
152
153 #[test]
154 fn test_multi_return_func() {
155 let isa = lookup(triple!("x86_64"))
156 .expect("expect x86 ISA")
157 .finish(Flags::new(builder()))
158 .expect("expect backend creation to succeed");
159
160 let mut context = Context::for_function(create_multi_return_function(CallConv::SystemV));
161
162 let code = context
163 .compile(&*isa, &mut Default::default())
164 .expect("expected compilation");
165
166 let fde = match code
167 .create_unwind_info(isa.as_ref())
168 .expect("can create unwind info")
169 {
170 Some(crate::isa::unwind::UnwindInfo::SystemV(info)) => {
171 info.to_fde(Address::Constant(4321))
172 }
173 _ => panic!("expected unwind information"),
174 };
175
176 assert_eq!(
177 format!("{fde:?}"),
178 "FrameDescriptionEntry { address: Constant(4321), length: 22, lsda: None, instructions: [(1, CfaOffset(16)), (1, Offset(Register(6), -16)), (4, CfaRegister(Register(6)))] }"
179 );
180 }
181
182 fn create_multi_return_function(call_conv: CallConv) -> Function {
183 let mut sig = Signature::new(call_conv);
184 sig.params.push(AbiParam::new(types::I32));
185 let mut func = Function::with_name_signature(Default::default(), sig);
186
187 let block0 = func.dfg.make_block();
188 let v0 = func.dfg.append_block_param(block0, types::I32);
189 let block1 = func.dfg.make_block();
190 let block2 = func.dfg.make_block();
191
192 let mut pos = FuncCursor::new(&mut func);
193 pos.insert_block(block0);
194 pos.ins().brif(v0, block2, &[], block1, &[]);
195
196 pos.insert_block(block1);
197 pos.ins().return_(&[]);
198
199 pos.insert_block(block2);
200 pos.ins().return_(&[]);
201
202 func
203 }
204}