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