cranelift_codegen/isa/s390x/inst/unwind/
systemv.rs

1//! Unwind information for System V ABI (s390x).
2
3use crate::isa::unwind::systemv::RegisterMappingError;
4use crate::machinst::{Reg, RegClass};
5use gimli::{write::CommonInformationEntry, Encoding, Format, Register};
6
7/// Creates a new s390x common information entry (CIE).
8pub 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,            // Code alignment factor
18        -8,           // Data alignment factor
19        Register(14), // Return address column - register %r14
20    );
21
22    // Every frame will start with the call frame address (CFA) at %r15 + 160.
23    entry.add_instruction(CallFrameInstruction::Cfa(Register(15), 160));
24
25    entry
26}
27
28/// Map Cranelift registers to their corresponding Gimli registers.
29pub 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}