cranelift_codegen/isa/aarch64/inst/unwind/
systemv.rs1use crate::isa::aarch64::inst::regs;
4use crate::isa::unwind::systemv::RegisterMappingError;
5use crate::machinst::{Reg, RegClass};
6use gimli::{write::CommonInformationEntry, Encoding, Format, Register};
7
8pub fn create_cie() -> CommonInformationEntry {
10 use gimli::write::CallFrameInstruction;
11
12 let mut entry = CommonInformationEntry::new(
13 Encoding {
14 address_size: 8,
15 format: Format::Dwarf32,
16 version: 1,
17 },
18 4, -8, Register(regs::link_reg().to_real_reg().unwrap().hw_enc().into()),
21 );
22
23 let sp = Register((regs::stack_reg().to_real_reg().unwrap().hw_enc() & 31).into());
25 entry.add_instruction(CallFrameInstruction::Cfa(sp, 0));
26
27 entry
28}
29
30pub fn map_reg(reg: Reg) -> Result<Register, RegisterMappingError> {
32 match reg.class() {
38 RegClass::Int => {
39 let reg = (reg.to_real_reg().unwrap().hw_enc() & 31) as u16;
40 Ok(Register(reg))
41 }
42 RegClass::Float => {
43 let reg = reg.to_real_reg().unwrap().hw_enc() as u16;
44 Ok(Register(64 + reg))
45 }
46 RegClass::Vector => unreachable!(),
47 }
48}
49
50pub(crate) struct RegisterMapper;
51
52impl crate::isa::unwind::systemv::RegisterMapper<Reg> for RegisterMapper {
53 fn map(&self, reg: Reg) -> Result<u16, RegisterMappingError> {
54 Ok(map_reg(reg)?.0)
55 }
56 fn fp(&self) -> Option<u16> {
57 Some(regs::fp_reg().to_real_reg().unwrap().hw_enc().into())
58 }
59 fn lr(&self) -> Option<u16> {
60 Some(regs::link_reg().to_real_reg().unwrap().hw_enc().into())
61 }
62 fn lr_offset(&self) -> Option<u32> {
63 Some(8)
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use crate::cursor::{Cursor, FuncCursor};
70 use crate::ir::{
71 types, AbiParam, Function, InstBuilder, Signature, StackSlotData, StackSlotKind,
72 };
73 use crate::isa::{lookup, CallConv};
74 use crate::settings::{builder, Flags};
75 use crate::Context;
76 use gimli::write::Address;
77 use target_lexicon::triple;
78
79 #[test]
80 fn test_simple_func() {
81 let isa = lookup(triple!("aarch64"))
82 .expect("expect aarch64 ISA")
83 .finish(Flags::new(builder()))
84 .expect("Creating compiler backend");
85
86 let mut context = Context::for_function(create_function(
87 CallConv::SystemV,
88 Some(StackSlotData::new(StackSlotKind::ExplicitSlot, 64, 0)),
89 ));
90
91 let code = context
92 .compile(&*isa, &mut Default::default())
93 .expect("expected compilation");
94
95 let fde = match code
96 .create_unwind_info(isa.as_ref())
97 .expect("can create unwind info")
98 {
99 Some(crate::isa::unwind::UnwindInfo::SystemV(info)) => {
100 info.to_fde(Address::Constant(1234))
101 }
102 _ => panic!("expected unwind information"),
103 };
104
105 assert_eq!(format!("{fde:?}"), "FrameDescriptionEntry { address: Constant(1234), length: 24, lsda: None, instructions: [(4, CfaOffset(16)), (4, Offset(Register(29), -16)), (4, Offset(Register(30), -8)), (8, CfaRegister(Register(29)))] }");
106 }
107
108 fn create_function(call_conv: CallConv, stack_slot: Option<StackSlotData>) -> Function {
109 let mut func = Function::with_name_signature(Default::default(), Signature::new(call_conv));
110
111 let block0 = func.dfg.make_block();
112 let mut pos = FuncCursor::new(&mut func);
113 pos.insert_block(block0);
114 pos.ins().return_(&[]);
115
116 if let Some(stack_slot) = stack_slot {
117 func.sized_stack_slots.push(stack_slot);
118 }
119
120 func
121 }
122
123 #[test]
124 fn test_multi_return_func() {
125 let isa = lookup(triple!("aarch64"))
126 .expect("expect aarch64 ISA")
127 .finish(Flags::new(builder()))
128 .expect("Creating compiler backend");
129
130 let mut context = Context::for_function(create_multi_return_function(CallConv::SystemV));
131
132 let code = context
133 .compile(&*isa, &mut Default::default())
134 .expect("expected compilation");
135
136 let fde = match code
137 .create_unwind_info(isa.as_ref())
138 .expect("can create unwind info")
139 {
140 Some(crate::isa::unwind::UnwindInfo::SystemV(info)) => {
141 info.to_fde(Address::Constant(4321))
142 }
143 _ => panic!("expected unwind information"),
144 };
145
146 assert_eq!(
147 format!("{fde:?}"),
148 "FrameDescriptionEntry { address: Constant(4321), length: 16, lsda: None, instructions: [] }"
149 );
150 }
151
152 fn create_multi_return_function(call_conv: CallConv) -> Function {
153 let mut sig = Signature::new(call_conv);
154 sig.params.push(AbiParam::new(types::I32));
155 let mut func = Function::with_name_signature(Default::default(), sig);
156
157 let block0 = func.dfg.make_block();
158 let v0 = func.dfg.append_block_param(block0, types::I32);
159 let block1 = func.dfg.make_block();
160 let block2 = func.dfg.make_block();
161
162 let mut pos = FuncCursor::new(&mut func);
163 pos.insert_block(block0);
164 pos.ins().brif(v0, block2, &[], block1, &[]);
165
166 pos.insert_block(block1);
167 pos.ins().return_(&[]);
168
169 pos.insert_block(block2);
170 pos.ins().return_(&[]);
171
172 func
173 }
174}