Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/codegen/src/isa/aarch64/inst/unwind/systemv.rs
1693 views
1
//! Unwind information for System V ABI (Aarch64).
2
3
use crate::isa::aarch64::inst::regs;
4
use crate::isa::unwind::systemv::RegisterMappingError;
5
use crate::machinst::{Reg, RegClass};
6
use gimli::{Encoding, Format, Register, write::CommonInformationEntry};
7
8
/// Creates a new aarch64 common information entry (CIE).
9
pub 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, // Code alignment factor
19
-8, // Data alignment factor
20
Register(regs::link_reg().to_real_reg().unwrap().hw_enc().into()),
21
);
22
23
// Every frame will start with the call frame address (CFA) at SP
24
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
30
/// Map Cranelift registers to their corresponding Gimli registers.
31
pub fn map_reg(reg: Reg) -> Result<Register, RegisterMappingError> {
32
// For AArch64 DWARF register mappings, see:
33
//
34
// https://developer.arm.com/documentation/ihi0057/e/?lang=en#dwarf-register-names
35
//
36
// X0--X31 is 0--31; V0--V31 is 64--95.
37
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
50
pub(crate) struct RegisterMapper;
51
52
impl 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)]
68
mod tests {
69
use crate::Context;
70
use crate::cursor::{Cursor, FuncCursor};
71
use crate::ir::{
72
AbiParam, Function, InstBuilder, Signature, StackSlotData, StackSlotKind, types,
73
};
74
use crate::isa::{CallConv, lookup};
75
use crate::settings::{Flags, builder};
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!(
106
format!("{fde:?}"),
107
"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)))] }"
108
);
109
}
110
111
fn create_function(call_conv: CallConv, stack_slot: Option<StackSlotData>) -> Function {
112
let mut func = Function::with_name_signature(Default::default(), Signature::new(call_conv));
113
114
let block0 = func.dfg.make_block();
115
let mut pos = FuncCursor::new(&mut func);
116
pos.insert_block(block0);
117
pos.ins().return_(&[]);
118
119
if let Some(stack_slot) = stack_slot {
120
func.sized_stack_slots.push(stack_slot);
121
}
122
123
func
124
}
125
126
#[test]
127
fn test_multi_return_func() {
128
let isa = lookup(triple!("aarch64"))
129
.expect("expect aarch64 ISA")
130
.finish(Flags::new(builder()))
131
.expect("Creating compiler backend");
132
133
let mut context = Context::for_function(create_multi_return_function(CallConv::SystemV));
134
135
let code = context
136
.compile(&*isa, &mut Default::default())
137
.expect("expected compilation");
138
139
let fde = match code
140
.create_unwind_info(isa.as_ref())
141
.expect("can create unwind info")
142
{
143
Some(crate::isa::unwind::UnwindInfo::SystemV(info)) => {
144
info.to_fde(Address::Constant(4321))
145
}
146
_ => panic!("expected unwind information"),
147
};
148
149
assert_eq!(
150
format!("{fde:?}"),
151
"FrameDescriptionEntry { address: Constant(4321), length: 16, lsda: None, instructions: [] }"
152
);
153
}
154
155
fn create_multi_return_function(call_conv: CallConv) -> Function {
156
let mut sig = Signature::new(call_conv);
157
sig.params.push(AbiParam::new(types::I32));
158
let mut func = Function::with_name_signature(Default::default(), sig);
159
160
let block0 = func.dfg.make_block();
161
let v0 = func.dfg.append_block_param(block0, types::I32);
162
let block1 = func.dfg.make_block();
163
let block2 = func.dfg.make_block();
164
165
let mut pos = FuncCursor::new(&mut func);
166
pos.insert_block(block0);
167
pos.ins().brif(v0, block2, &[], block1, &[]);
168
169
pos.insert_block(block1);
170
pos.ins().return_(&[]);
171
172
pos.insert_block(block2);
173
pos.ins().return_(&[]);
174
175
func
176
}
177
}
178
179