wasmer_compiler_singlepass/riscv_decl.rs
1//! RISC-V structures.
2
3use crate::location::{CombinedRegister, Reg as AbstractReg};
4use std::slice::Iter;
5use wasmer_types::{CompileError, Type};
6
7/*
8
9Register definition: https://en.wikichip.org/wiki/risc-v/registers#Calling_convention
10
11+-----+-----------+-------------------------------+-------------------+
12| Reg | ABI Name | Description | Saved by Callee |
13+-----+-----------+-------------------------------+-------------------+
14| x0 | zero | hardwired zero | - |
15| x1 | ra | return address | -R |
16| x2 | sp | stack pointer | -E |
17| x3 | gp | global pointer | - |
18| x4 | tp | thread pointer | - |
19| x5 | t0 | temporary register 0 | -R |
20| x6 | t1 | temporary register 1 | -R |
21| x7 | t2 | temporary register 2 | -R |
22| x8 | s0/fp | saved register 0/frame pointer| -E |
23| x9 | s1 | saved register 1 | -E |
24| x10 | a0 | function arg 0/return value 0 | -R |
25| x11 | a1 | function arg 1/return value 1 | -R |
26| x12 | a2 | function argument 2 | -R |
27| x13 | a3 | function argument 3 | -R |
28| x14 | a4 | function argument 4 | -R |
29| x15 | a5 | function argument 5 | -R |
30| x16 | a6 | function argument 6 | -R |
31| x17 | a7 | function argument 7 | -R |
32| x18 | s2 | saved register 2 | -E |
33| x19 | s3 | saved register 3 | -E |
34| x20 | s4 | saved register 4 | -E |
35| x21 | s5 | saved register 5 | -E |
36| x22 | s6 | saved register 6 | -E |
37| x23 | s7 | saved register 7 | -E |
38| x24 | s8 | saved register 8 | -E |
39| x25 | s9 | saved register 9 | -E |
40| x26 | s10 | saved register 10 | -E |
41| x27 | s11 | saved register 11 | -E |
42| x28 | t3 | temporary register 3 | -R |
43| x29 | t4 | temporary register 4 | -R |
44| x30 | t5 | temporary register 5 | -R |
45| x31 | t6 | temporary register 6 | -R |
46+-----+-----------+-------------------------------+-------------------+
47Legend: -R = caller-saved, -E = callee-saved, - = not saved
48*/
49
50/// General-purpose registers.
51#[repr(u8)]
52#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
53#[allow(clippy::upper_case_acronyms)]
54pub enum GPR {
55 XZero = 0,
56 X1 = 1,
57 Sp = 2,
58 X3 = 3,
59 X4 = 4,
60 X5 = 5,
61 X6 = 6,
62 X7 = 7,
63 Fp = 8,
64 X9 = 9,
65 X10 = 10,
66 X11 = 11,
67 X12 = 12,
68 X13 = 13,
69 X14 = 14,
70 X15 = 15,
71 X16 = 16,
72 X17 = 17,
73 X18 = 18,
74 X19 = 19,
75 X20 = 20,
76 X21 = 21,
77 X22 = 22,
78 X23 = 23,
79 X24 = 24,
80 X25 = 25,
81 X26 = 26,
82 X27 = 27,
83 X28 = 28,
84 X29 = 29,
85 X30 = 30,
86 X31 = 31,
87}
88
89impl From<GPR> for u8 {
90 fn from(val: GPR) -> Self {
91 val as u8
92 }
93}
94
95impl AbstractReg for GPR {
96 fn into_index(self) -> usize {
97 self as usize
98 }
99 fn from_index(n: usize) -> Result<GPR, ()> {
100 match n {
101 0..=31 => Ok(*GPR::iterator().nth(n).unwrap()),
102 _ => Err(()),
103 }
104 }
105 fn iterator() -> Iter<'static, GPR> {
106 static GPRS: [GPR; 32] = [
107 GPR::XZero,
108 GPR::X1,
109 GPR::Sp,
110 GPR::X3,
111 GPR::X4,
112 GPR::X5,
113 GPR::X6,
114 GPR::X7,
115 GPR::Fp,
116 GPR::X9,
117 GPR::X10,
118 GPR::X11,
119 GPR::X12,
120 GPR::X13,
121 GPR::X14,
122 GPR::X15,
123 GPR::X16,
124 GPR::X17,
125 GPR::X18,
126 GPR::X19,
127 GPR::X20,
128 GPR::X21,
129 GPR::X22,
130 GPR::X23,
131 GPR::X24,
132 GPR::X25,
133 GPR::X26,
134 GPR::X27,
135 GPR::X28,
136 GPR::X29,
137 GPR::X30,
138 GPR::X31,
139 ];
140 GPRS.iter()
141 }
142 #[cfg(feature = "unwind")]
143 fn to_dwarf(self) -> gimli::Register {
144 use gimli::RiscV;
145
146 match self {
147 GPR::XZero => RiscV::ZERO,
148 GPR::X1 => RiscV::X1,
149 GPR::Sp => RiscV::SP,
150 GPR::X3 => RiscV::X3,
151 GPR::X4 => RiscV::X4,
152 GPR::X5 => RiscV::X5,
153 GPR::X6 => RiscV::X6,
154 GPR::X7 => RiscV::X7,
155 GPR::Fp => RiscV::FP,
156 GPR::X9 => RiscV::X9,
157 GPR::X10 => RiscV::X10,
158 GPR::X11 => RiscV::X11,
159 GPR::X12 => RiscV::X12,
160 GPR::X13 => RiscV::X13,
161 GPR::X14 => RiscV::X14,
162 GPR::X15 => RiscV::X15,
163 GPR::X16 => RiscV::X16,
164 GPR::X17 => RiscV::X17,
165 GPR::X18 => RiscV::X18,
166 GPR::X19 => RiscV::X19,
167 GPR::X20 => RiscV::X20,
168 GPR::X21 => RiscV::X21,
169 GPR::X22 => RiscV::X22,
170 GPR::X23 => RiscV::X23,
171 GPR::X24 => RiscV::X24,
172 GPR::X25 => RiscV::X25,
173 GPR::X26 => RiscV::X26,
174 GPR::X27 => RiscV::X27,
175 GPR::X28 => RiscV::X28,
176 GPR::X29 => RiscV::X29,
177 GPR::X30 => RiscV::X30,
178 GPR::X31 => RiscV::X31,
179 }
180 }
181}
182
183/*
184+-----+-------+--------------------------+-------------------+
185| Reg | Name | Description | Saved by |
186+-----+-------+--------------------------+-------------------+
187| f0 | ft0 | FP temporary | Caller |
188| f1 | ft1 | FP temporary | Caller |
189| f2 | ft2 | FP temporary | Caller |
190| f3 | ft3 | FP temporary | Caller |
191| f4 | ft4 | FP temporary | Caller |
192| f5 | ft5 | FP temporary | Caller |
193| f6 | ft6 | FP temporary | Caller |
194| f7 | ft7 | FP temporary | Caller |
195| f8 | fs0 | FP saved register | Callee |
196| f9 | fs1 | FP saved register | Callee |
197| f10 | fa0 | FP argument/return value | Caller |
198| f11 | fa1 | FP argument/return value | Caller |
199| f12 | fa2 | FP argument | Caller |
200| f13 | fa3 | FP argument | Caller |
201| f14 | fa4 | FP argument | Caller |
202| f15 | fa5 | FP argument | Caller |
203| f16 | fa6 | FP argument | Caller |
204| f17 | fa7 | FP argument | Caller |
205| f18 | fs2 | FP saved register | Callee |
206| f19 | fs3 | FP saved register | Callee |
207| f20 | fs4 | FP saved register | Callee |
208| f21 | fs5 | FP saved register | Callee |
209| f22 | fs6 | FP saved register | Callee |
210| f23 | fs7 | FP saved register | Callee |
211| f24 | fs8 | FP saved register | Callee |
212| f25 | fs9 | FP saved register | Callee |
213| f26 | fs10 | FP saved register | Callee |
214| f27 | fs11 | FP saved register | Callee |
215| f28 | ft8 | FP temporary | Caller |
216| f29 | ft9 | FP temporary | Caller |
217| f30 | ft10 | FP temporary | Caller |
218| f31 | ft11 | FP temporary | Caller |
219+-----+-------+--------------------------+-------------------+
220Legend: FP = floating-point
221*/
222
223/// Floating-point registers.
224#[repr(u8)]
225#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
226#[allow(clippy::upper_case_acronyms)]
227pub enum FPR {
228 F0 = 0,
229 F1 = 1,
230 F2 = 2,
231 F3 = 3,
232 F4 = 4,
233 F5 = 5,
234 F6 = 6,
235 F7 = 7,
236 F8 = 8,
237 F9 = 9,
238 F10 = 10,
239 F11 = 11,
240 F12 = 12,
241 F13 = 13,
242 F14 = 14,
243 F15 = 15,
244 F16 = 16,
245 F17 = 17,
246 F18 = 18,
247 F19 = 19,
248 F20 = 20,
249 F21 = 21,
250 F22 = 22,
251 F23 = 23,
252 F24 = 24,
253 F25 = 25,
254 F26 = 26,
255 F27 = 27,
256 F28 = 28,
257 F29 = 29,
258 F30 = 30,
259 F31 = 31,
260}
261
262impl From<FPR> for u8 {
263 fn from(val: FPR) -> Self {
264 val as u8
265 }
266}
267
268impl AbstractReg for FPR {
269 fn into_index(self) -> usize {
270 self as usize
271 }
272 fn from_index(n: usize) -> Result<FPR, ()> {
273 match n {
274 0..=31 => Ok(*FPR::iterator().nth(n).unwrap()),
275 _ => Err(()),
276 }
277 }
278 fn iterator() -> Iter<'static, FPR> {
279 static FPRS: [FPR; 32] = [
280 FPR::F0,
281 FPR::F1,
282 FPR::F2,
283 FPR::F3,
284 FPR::F4,
285 FPR::F5,
286 FPR::F6,
287 FPR::F7,
288 FPR::F8,
289 FPR::F9,
290 FPR::F10,
291 FPR::F11,
292 FPR::F12,
293 FPR::F13,
294 FPR::F14,
295 FPR::F15,
296 FPR::F16,
297 FPR::F17,
298 FPR::F18,
299 FPR::F19,
300 FPR::F20,
301 FPR::F21,
302 FPR::F22,
303 FPR::F23,
304 FPR::F24,
305 FPR::F25,
306 FPR::F26,
307 FPR::F27,
308 FPR::F28,
309 FPR::F29,
310 FPR::F30,
311 FPR::F31,
312 ];
313 FPRS.iter()
314 }
315
316 #[cfg(feature = "unwind")]
317 fn to_dwarf(self) -> gimli::Register {
318 use gimli::RiscV;
319
320 match self {
321 FPR::F0 => RiscV::F0,
322 FPR::F1 => RiscV::F1,
323 FPR::F2 => RiscV::F2,
324 FPR::F3 => RiscV::F3,
325 FPR::F4 => RiscV::F4,
326 FPR::F5 => RiscV::F5,
327 FPR::F6 => RiscV::F6,
328 FPR::F7 => RiscV::F7,
329 FPR::F8 => RiscV::F8,
330 FPR::F9 => RiscV::F9,
331 FPR::F10 => RiscV::F10,
332 FPR::F11 => RiscV::F11,
333 FPR::F12 => RiscV::F12,
334 FPR::F13 => RiscV::F13,
335 FPR::F14 => RiscV::F14,
336 FPR::F15 => RiscV::F15,
337 FPR::F16 => RiscV::F16,
338 FPR::F17 => RiscV::F17,
339 FPR::F18 => RiscV::F18,
340 FPR::F19 => RiscV::F19,
341 FPR::F20 => RiscV::F20,
342 FPR::F21 => RiscV::F21,
343 FPR::F22 => RiscV::F22,
344 FPR::F23 => RiscV::F23,
345 FPR::F24 => RiscV::F24,
346 FPR::F25 => RiscV::F25,
347 FPR::F26 => RiscV::F26,
348 FPR::F27 => RiscV::F27,
349 FPR::F28 => RiscV::F28,
350 FPR::F29 => RiscV::F29,
351 FPR::F30 => RiscV::F30,
352 FPR::F31 => RiscV::F31,
353 }
354 }
355}
356
357/// A combined RISC-V register.
358#[derive(Copy, Clone, Debug, Eq, PartialEq)]
359#[allow(clippy::upper_case_acronyms)]
360pub enum RiscvRegister {
361 /// General-purpose register.
362 GPR(GPR),
363 /// Floating-point register.
364 FPR(FPR),
365}
366
367impl CombinedRegister for RiscvRegister {
368 fn from_gpr(x: u16) -> Self {
369 RiscvRegister::GPR(GPR::from_index(x as usize).unwrap())
370 }
371 fn from_simd(x: u16) -> Self {
372 RiscvRegister::FPR(FPR::from_index(x as usize).unwrap())
373 }
374}
375
376/// Allocator for function argument registers according to the RISC-V ABI.
377#[derive(Default)]
378pub struct ArgumentRegisterAllocator {
379 n_gprs: usize,
380 n_fprs: usize,
381}
382
383impl ArgumentRegisterAllocator {
384 /// Allocates a register for argument type `ty`. Returns `None` if no register is available.
385 #[allow(dead_code)]
386 pub fn next(&mut self, ty: Type) -> Result<Option<RiscvRegister>, CompileError> {
387 let ret = {
388 static GPR_SEQ: &[GPR] = &[
389 GPR::X10,
390 GPR::X11,
391 GPR::X12,
392 GPR::X13,
393 GPR::X14,
394 GPR::X15,
395 GPR::X16,
396 GPR::X17,
397 ];
398 static FPR_SEQ: &[FPR] = &[
399 FPR::F10,
400 FPR::F11,
401 FPR::F12,
402 FPR::F13,
403 FPR::F14,
404 FPR::F15,
405 FPR::F16,
406 FPR::F17,
407 ];
408 match ty {
409 Type::I32 | Type::I64 | Type::FuncRef | Type::ExternRef => {
410 if self.n_gprs < GPR_SEQ.len() {
411 let gpr = GPR_SEQ[self.n_gprs];
412 self.n_gprs += 1;
413 Some(RiscvRegister::GPR(gpr))
414 } else {
415 None
416 }
417 }
418 Type::F32 | Type::F64 => {
419 if self.n_fprs < FPR_SEQ.len() {
420 let neon = FPR_SEQ[self.n_fprs];
421 self.n_fprs += 1;
422 Some(RiscvRegister::FPR(neon))
423 } else {
424 None
425 }
426 }
427 _ => {
428 return Err(CompileError::Codegen(format!(
429 "No register available for type {ty}"
430 )));
431 }
432 }
433 };
434
435 Ok(ret)
436 }
437}