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