Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/codegen/src/isa/s390x/inst/unwind/systemv.rs
1693 views
1
//! Unwind information for System V ABI (s390x).
2
3
use crate::isa::unwind::systemv::RegisterMappingError;
4
use crate::machinst::{Reg, RegClass};
5
use gimli::{Encoding, Format, Register, write::CommonInformationEntry};
6
7
/// Creates a new s390x common information entry (CIE).
8
pub 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.
29
pub 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
90
pub(crate) struct RegisterMapper;
91
92
impl 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)]
99
mod tests {
100
use crate::Context;
101
use crate::cursor::{Cursor, FuncCursor};
102
use crate::ir::{
103
AbiParam, Function, InstBuilder, Signature, StackSlotData, StackSlotKind, types,
104
};
105
use crate::isa::{CallConv, lookup};
106
use crate::settings::{Flags, builder};
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!(
137
format!("{fde:?}"),
138
"FrameDescriptionEntry { address: Constant(1234), length: 10, lsda: None, instructions: [(4, CfaOffset(224))] }"
139
);
140
}
141
142
fn create_function(call_conv: CallConv, stack_slot: Option<StackSlotData>) -> Function {
143
let mut func = Function::with_name_signature(Default::default(), Signature::new(call_conv));
144
145
let block0 = func.dfg.make_block();
146
let mut pos = FuncCursor::new(&mut func);
147
pos.insert_block(block0);
148
pos.ins().return_(&[]);
149
150
if let Some(stack_slot) = stack_slot {
151
func.sized_stack_slots.push(stack_slot);
152
}
153
154
func
155
}
156
157
#[test]
158
fn test_multi_return_func() {
159
let isa = lookup(triple!("s390x"))
160
.expect("expect s390x ISA")
161
.finish(Flags::new(builder()))
162
.expect("Creating compiler backend");
163
164
let mut context = Context::for_function(create_multi_return_function(
165
CallConv::SystemV,
166
Some(StackSlotData::new(StackSlotKind::ExplicitSlot, 64, 0)),
167
));
168
169
let code = context
170
.compile(&*isa, &mut Default::default())
171
.expect("expected compilation");
172
173
let fde = match code
174
.create_unwind_info(isa.as_ref())
175
.expect("can create unwind info")
176
{
177
Some(crate::isa::unwind::UnwindInfo::SystemV(info)) => {
178
info.to_fde(Address::Constant(4321))
179
}
180
_ => panic!("expected unwind information"),
181
};
182
183
assert_eq!(
184
format!("{fde:?}"),
185
"FrameDescriptionEntry { address: Constant(4321), length: 26, lsda: None, instructions: [(4, CfaOffset(224))] }"
186
);
187
}
188
189
fn create_multi_return_function(
190
call_conv: CallConv,
191
stack_slot: Option<StackSlotData>,
192
) -> Function {
193
let mut sig = Signature::new(call_conv);
194
sig.params.push(AbiParam::new(types::I32));
195
let mut func = Function::with_name_signature(Default::default(), sig);
196
197
let block0 = func.dfg.make_block();
198
let v0 = func.dfg.append_block_param(block0, types::I32);
199
let block1 = func.dfg.make_block();
200
let block2 = func.dfg.make_block();
201
202
let mut pos = FuncCursor::new(&mut func);
203
pos.insert_block(block0);
204
pos.ins().brif(v0, block2, &[], block1, &[]);
205
206
pos.insert_block(block1);
207
pos.ins().return_(&[]);
208
209
pos.insert_block(block2);
210
pos.ins().return_(&[]);
211
212
if let Some(stack_slot) = stack_slot {
213
func.sized_stack_slots.push(stack_slot);
214
}
215
216
func
217
}
218
}
219
220