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 // TODO: use new constant: https://github.com/gimli-rs/gimli/pull/802
156 GPR::Fp => RiscV::X8,
157 GPR::X9 => RiscV::X9,
158 GPR::X10 => RiscV::X10,
159 GPR::X11 => RiscV::X11,
160 GPR::X12 => RiscV::X12,
161 GPR::X13 => RiscV::X13,
162 GPR::X14 => RiscV::X14,
163 GPR::X15 => RiscV::X15,
164 GPR::X16 => RiscV::X16,
165 GPR::X17 => RiscV::X17,
166 GPR::X18 => RiscV::X18,
167 GPR::X19 => RiscV::X19,
168 GPR::X20 => RiscV::X20,
169 GPR::X21 => RiscV::X21,
170 GPR::X22 => RiscV::X22,
171 GPR::X23 => RiscV::X23,
172 GPR::X24 => RiscV::X24,
173 GPR::X25 => RiscV::X25,
174 GPR::X26 => RiscV::X26,
175 GPR::X27 => RiscV::X27,
176 GPR::X28 => RiscV::X28,
177 GPR::X29 => RiscV::X29,
178 GPR::X30 => RiscV::X30,
179 GPR::X31 => RiscV::X31,
180 }
181 }
182}
183
184/*
185+-----+-------+--------------------------+-------------------+
186| Reg | Name | Description | Saved by |
187+-----+-------+--------------------------+-------------------+
188| f0 | ft0 | FP temporary | Caller |
189| f1 | ft1 | FP temporary | Caller |
190| f2 | ft2 | FP temporary | Caller |
191| f3 | ft3 | FP temporary | Caller |
192| f4 | ft4 | FP temporary | Caller |
193| f5 | ft5 | FP temporary | Caller |
194| f6 | ft6 | FP temporary | Caller |
195| f7 | ft7 | FP temporary | Caller |
196| f8 | fs0 | FP saved register | Callee |
197| f9 | fs1 | FP saved register | Callee |
198| f10 | fa0 | FP argument/return value | Caller |
199| f11 | fa1 | FP argument/return value | Caller |
200| f12 | fa2 | FP argument | Caller |
201| f13 | fa3 | FP argument | Caller |
202| f14 | fa4 | FP argument | Caller |
203| f15 | fa5 | FP argument | Caller |
204| f16 | fa6 | FP argument | Caller |
205| f17 | fa7 | FP argument | Caller |
206| f18 | fs2 | FP saved register | Callee |
207| f19 | fs3 | FP saved register | Callee |
208| f20 | fs4 | FP saved register | Callee |
209| f21 | fs5 | FP saved register | Callee |
210| f22 | fs6 | FP saved register | Callee |
211| f23 | fs7 | FP saved register | Callee |
212| f24 | fs8 | FP saved register | Callee |
213| f25 | fs9 | FP saved register | Callee |
214| f26 | fs10 | FP saved register | Callee |
215| f27 | fs11 | FP saved register | Callee |
216| f28 | ft8 | FP temporary | Caller |
217| f29 | ft9 | FP temporary | Caller |
218| f30 | ft10 | FP temporary | Caller |
219| f31 | ft11 | FP temporary | Caller |
220+-----+-------+--------------------------+-------------------+
221Legend: FP = floating-point
222*/
223
224/// Floating-point registers.
225#[repr(u8)]
226#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
227#[allow(clippy::upper_case_acronyms)]
228pub enum FPR {
229 F0 = 0,
230 F1 = 1,
231 F2 = 2,
232 F3 = 3,
233 F4 = 4,
234 F5 = 5,
235 F6 = 6,
236 F7 = 7,
237 F8 = 8,
238 F9 = 9,
239 F10 = 10,
240 F11 = 11,
241 F12 = 12,
242 F13 = 13,
243 F14 = 14,
244 F15 = 15,
245 F16 = 16,
246 F17 = 17,
247 F18 = 18,
248 F19 = 19,
249 F20 = 20,
250 F21 = 21,
251 F22 = 22,
252 F23 = 23,
253 F24 = 24,
254 F25 = 25,
255 F26 = 26,
256 F27 = 27,
257 F28 = 28,
258 F29 = 29,
259 F30 = 30,
260 F31 = 31,
261}
262
263impl From<FPR> for u8 {
264 fn from(val: FPR) -> Self {
265 val as u8
266 }
267}
268
269impl AbstractReg for FPR {
270 fn into_index(self) -> usize {
271 self as usize
272 }
273 fn from_index(n: usize) -> Result<FPR, ()> {
274 match n {
275 0..=31 => Ok(*FPR::iterator().nth(n).unwrap()),
276 _ => Err(()),
277 }
278 }
279 fn iterator() -> Iter<'static, FPR> {
280 static FPRS: [FPR; 32] = [
281 FPR::F0,
282 FPR::F1,
283 FPR::F2,
284 FPR::F3,
285 FPR::F4,
286 FPR::F5,
287 FPR::F6,
288 FPR::F7,
289 FPR::F8,
290 FPR::F9,
291 FPR::F10,
292 FPR::F11,
293 FPR::F12,
294 FPR::F13,
295 FPR::F14,
296 FPR::F15,
297 FPR::F16,
298 FPR::F17,
299 FPR::F18,
300 FPR::F19,
301 FPR::F20,
302 FPR::F21,
303 FPR::F22,
304 FPR::F23,
305 FPR::F24,
306 FPR::F25,
307 FPR::F26,
308 FPR::F27,
309 FPR::F28,
310 FPR::F29,
311 FPR::F30,
312 FPR::F31,
313 ];
314 FPRS.iter()
315 }
316
317 #[cfg(feature = "unwind")]
318 fn to_dwarf(self) -> gimli::Register {
319 use gimli::RiscV;
320
321 match self {
322 FPR::F0 => RiscV::F0,
323 FPR::F1 => RiscV::F1,
324 FPR::F2 => RiscV::F2,
325 FPR::F3 => RiscV::F3,
326 FPR::F4 => RiscV::F4,
327 FPR::F5 => RiscV::F5,
328 FPR::F6 => RiscV::F6,
329 FPR::F7 => RiscV::F7,
330 FPR::F8 => RiscV::F8,
331 FPR::F9 => RiscV::F9,
332 FPR::F10 => RiscV::F10,
333 FPR::F11 => RiscV::F11,
334 FPR::F12 => RiscV::F12,
335 FPR::F13 => RiscV::F13,
336 FPR::F14 => RiscV::F14,
337 FPR::F15 => RiscV::F15,
338 FPR::F16 => RiscV::F16,
339 FPR::F17 => RiscV::F17,
340 FPR::F18 => RiscV::F18,
341 FPR::F19 => RiscV::F19,
342 FPR::F20 => RiscV::F20,
343 FPR::F21 => RiscV::F21,
344 FPR::F22 => RiscV::F22,
345 FPR::F23 => RiscV::F23,
346 FPR::F24 => RiscV::F24,
347 FPR::F25 => RiscV::F25,
348 FPR::F26 => RiscV::F26,
349 FPR::F27 => RiscV::F27,
350 FPR::F28 => RiscV::F28,
351 FPR::F29 => RiscV::F29,
352 FPR::F30 => RiscV::F30,
353 FPR::F31 => RiscV::F31,
354 }
355 }
356}
357
358/// A combined RISC-V register.
359#[derive(Copy, Clone, Debug, Eq, PartialEq)]
360#[allow(clippy::upper_case_acronyms)]
361pub enum RiscvRegister {
362 /// General-purpose register.
363 GPR(GPR),
364 /// Floating-point register.
365 FPR(FPR),
366}
367
368impl CombinedRegister for RiscvRegister {
369 fn from_gpr(x: u16) -> Self {
370 RiscvRegister::GPR(GPR::from_index(x as usize).unwrap())
371 }
372 fn from_simd(x: u16) -> Self {
373 RiscvRegister::FPR(FPR::from_index(x as usize).unwrap())
374 }
375}
376
377/// Allocator for function argument registers according to the RISC-V ABI.
378#[derive(Default)]
379pub struct ArgumentRegisterAllocator {
380 n_gprs: usize,
381 n_fprs: usize,
382}
383
384impl ArgumentRegisterAllocator {
385 /// Allocates a register for argument type `ty`. Returns `None` if no register is available.
386 #[allow(dead_code)]
387 pub fn next(&mut self, ty: Type) -> Result<Option<RiscvRegister>, CompileError> {
388 let ret = {
389 static GPR_SEQ: &[GPR] = &[
390 GPR::X10,
391 GPR::X11,
392 GPR::X12,
393 GPR::X13,
394 GPR::X14,
395 GPR::X15,
396 GPR::X16,
397 GPR::X17,
398 ];
399 static FPR_SEQ: &[FPR] = &[
400 FPR::F10,
401 FPR::F11,
402 FPR::F12,
403 FPR::F13,
404 FPR::F14,
405 FPR::F15,
406 FPR::F16,
407 FPR::F17,
408 ];
409 match ty {
410 Type::I32 | Type::I64 => {
411 if self.n_gprs < GPR_SEQ.len() {
412 let gpr = GPR_SEQ[self.n_gprs];
413 self.n_gprs += 1;
414 Some(RiscvRegister::GPR(gpr))
415 } else {
416 None
417 }
418 }
419 Type::F32 | Type::F64 => {
420 if self.n_fprs < FPR_SEQ.len() {
421 let neon = FPR_SEQ[self.n_fprs];
422 self.n_fprs += 1;
423 Some(RiscvRegister::FPR(neon))
424 } else {
425 None
426 }
427 }
428 _ => {
429 return Err(CompileError::Codegen(format!(
430 "No register available for type {ty}"
431 )));
432 }
433 }
434 };
435
436 Ok(ret)
437 }
438}