wasmer_compiler_singlepass/
arm64_decl.rs

1//! ARM64 structures.
2
3use crate::{
4    common_decl::{MachineState, MachineValue, RegisterIndex},
5    location::{CombinedRegister, Reg as AbstractReg},
6};
7use std::collections::BTreeMap;
8use std::slice::Iter;
9use wasmer_types::target::CallingConvention;
10use wasmer_types::{CompileError, Type};
11
12/// General-purpose registers.
13#[repr(u8)]
14#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
15#[allow(clippy::upper_case_acronyms)]
16pub enum GPR {
17    X0 = 0,
18    X1 = 1,
19    X2 = 2,
20    X3 = 3,
21    X4 = 4,
22    X5 = 5,
23    X6 = 6,
24    X7 = 7,
25    X8 = 8,
26    X9 = 9,
27    X10 = 10,
28    X11 = 11,
29    X12 = 12,
30    X13 = 13,
31    X14 = 14,
32    X15 = 15,
33    X16 = 16,
34    X17 = 17,
35    X18 = 18,
36    X19 = 19,
37    X20 = 20,
38    X21 = 21,
39    X22 = 22,
40    X23 = 23,
41    X24 = 24,
42    X25 = 25,
43    X26 = 26,
44    X27 = 27,
45    X28 = 28,
46    X29 = 29,
47    X30 = 30,
48    XzrSp = 31,
49}
50
51impl From<GPR> for u8 {
52    fn from(val: GPR) -> Self {
53        val as u8
54    }
55}
56
57/// NEON registers.
58#[repr(u8)]
59#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
60#[allow(dead_code)]
61#[allow(clippy::upper_case_acronyms)]
62pub enum NEON {
63    V0 = 0,
64    V1 = 1,
65    V2 = 2,
66    V3 = 3,
67    V4 = 4,
68    V5 = 5,
69    V6 = 6,
70    V7 = 7,
71    V8 = 8,
72    V9 = 9,
73    V10 = 10,
74    V11 = 11,
75    V12 = 12,
76    V13 = 13,
77    V14 = 14,
78    V15 = 15,
79    V16 = 16,
80    V17 = 17,
81    V18 = 18,
82    V19 = 19,
83    V20 = 20,
84    V21 = 21,
85    V22 = 22,
86    V23 = 23,
87    V24 = 24,
88    V25 = 25,
89    V26 = 26,
90    V27 = 27,
91    V28 = 28,
92    V29 = 29,
93    V30 = 30,
94    V31 = 31,
95}
96
97impl From<NEON> for u8 {
98    fn from(val: NEON) -> Self {
99        val as u8
100    }
101}
102
103impl AbstractReg for GPR {
104    fn is_callee_save(self) -> bool {
105        self as usize > 18
106    }
107    fn is_reserved(self) -> bool {
108        !matches!(self.into_index(), 0..=16 | 19..=27)
109    }
110    fn into_index(self) -> usize {
111        self as usize
112    }
113    fn from_index(n: usize) -> Result<GPR, ()> {
114        match n {
115            0..=31 => Ok(*GPR::iterator().nth(n).unwrap()),
116            _ => Err(()),
117        }
118    }
119    fn iterator() -> Iter<'static, GPR> {
120        static GPRS: [GPR; 32] = [
121            GPR::X0,
122            GPR::X1,
123            GPR::X2,
124            GPR::X3,
125            GPR::X4,
126            GPR::X5,
127            GPR::X6,
128            GPR::X7,
129            GPR::X8,
130            GPR::X9,
131            GPR::X10,
132            GPR::X11,
133            GPR::X12,
134            GPR::X13,
135            GPR::X14,
136            GPR::X15,
137            GPR::X16,
138            GPR::X17,
139            GPR::X18,
140            GPR::X19,
141            GPR::X20,
142            GPR::X21,
143            GPR::X22,
144            GPR::X23,
145            GPR::X24,
146            GPR::X25,
147            GPR::X26,
148            GPR::X27,
149            GPR::X28,
150            GPR::X29,
151            GPR::X30,
152            GPR::XzrSp,
153        ];
154        GPRS.iter()
155    }
156    #[cfg(feature = "unwind")]
157    fn to_dwarf(self) -> gimli::Register {
158        use gimli::AArch64;
159
160        match self {
161            GPR::X0 => AArch64::X0,
162            GPR::X1 => AArch64::X1,
163            GPR::X2 => AArch64::X2,
164            GPR::X3 => AArch64::X3,
165            GPR::X4 => AArch64::X4,
166            GPR::X5 => AArch64::X5,
167            GPR::X6 => AArch64::X6,
168            GPR::X7 => AArch64::X7,
169            GPR::X8 => AArch64::X8,
170            GPR::X9 => AArch64::X9,
171            GPR::X10 => AArch64::X10,
172            GPR::X11 => AArch64::X11,
173            GPR::X12 => AArch64::X12,
174            GPR::X13 => AArch64::X13,
175            GPR::X14 => AArch64::X14,
176            GPR::X15 => AArch64::X15,
177            GPR::X16 => AArch64::X16,
178            GPR::X17 => AArch64::X17,
179            GPR::X18 => AArch64::X18,
180            GPR::X19 => AArch64::X19,
181            GPR::X20 => AArch64::X20,
182            GPR::X21 => AArch64::X21,
183            GPR::X22 => AArch64::X22,
184            GPR::X23 => AArch64::X23,
185            GPR::X24 => AArch64::X24,
186            GPR::X25 => AArch64::X25,
187            GPR::X26 => AArch64::X26,
188            GPR::X27 => AArch64::X27,
189            GPR::X28 => AArch64::X28,
190            GPR::X29 => AArch64::X29,
191            GPR::X30 => AArch64::X30,
192            GPR::XzrSp => AArch64::SP,
193        }
194    }
195}
196
197impl AbstractReg for NEON {
198    fn is_callee_save(self) -> bool {
199        self as usize > 16
200    }
201    fn is_reserved(self) -> bool {
202        false
203    }
204    fn into_index(self) -> usize {
205        self as usize
206    }
207    fn from_index(n: usize) -> Result<NEON, ()> {
208        match n {
209            0..=31 => Ok(*NEON::iterator().nth(n).unwrap()),
210            _ => Err(()),
211        }
212    }
213    fn iterator() -> Iter<'static, NEON> {
214        const NEONS: [NEON; 32] = [
215            NEON::V0,
216            NEON::V1,
217            NEON::V2,
218            NEON::V3,
219            NEON::V4,
220            NEON::V5,
221            NEON::V6,
222            NEON::V7,
223            NEON::V8,
224            NEON::V9,
225            NEON::V10,
226            NEON::V11,
227            NEON::V12,
228            NEON::V13,
229            NEON::V14,
230            NEON::V15,
231            NEON::V16,
232            NEON::V17,
233            NEON::V18,
234            NEON::V19,
235            NEON::V20,
236            NEON::V21,
237            NEON::V22,
238            NEON::V23,
239            NEON::V24,
240            NEON::V25,
241            NEON::V26,
242            NEON::V27,
243            NEON::V28,
244            NEON::V29,
245            NEON::V30,
246            NEON::V31,
247        ];
248        NEONS.iter()
249    }
250    #[cfg(feature = "unwind")]
251    fn to_dwarf(self) -> gimli::Register {
252        use gimli::AArch64;
253
254        match self {
255            NEON::V0 => AArch64::V0,
256            NEON::V1 => AArch64::V1,
257            NEON::V2 => AArch64::V2,
258            NEON::V3 => AArch64::V3,
259            NEON::V4 => AArch64::V4,
260            NEON::V5 => AArch64::V5,
261            NEON::V6 => AArch64::V6,
262            NEON::V7 => AArch64::V7,
263            NEON::V8 => AArch64::V8,
264            NEON::V9 => AArch64::V9,
265            NEON::V10 => AArch64::V10,
266            NEON::V11 => AArch64::V11,
267            NEON::V12 => AArch64::V12,
268            NEON::V13 => AArch64::V13,
269            NEON::V14 => AArch64::V14,
270            NEON::V15 => AArch64::V15,
271            NEON::V16 => AArch64::V16,
272            NEON::V17 => AArch64::V17,
273            NEON::V18 => AArch64::V18,
274            NEON::V19 => AArch64::V19,
275            NEON::V20 => AArch64::V20,
276            NEON::V21 => AArch64::V21,
277            NEON::V22 => AArch64::V22,
278            NEON::V23 => AArch64::V23,
279            NEON::V24 => AArch64::V24,
280            NEON::V25 => AArch64::V25,
281            NEON::V26 => AArch64::V26,
282            NEON::V27 => AArch64::V27,
283            NEON::V28 => AArch64::V28,
284            NEON::V29 => AArch64::V29,
285            NEON::V30 => AArch64::V30,
286            NEON::V31 => AArch64::V31,
287        }
288    }
289}
290
291/// A machine register under the x86-64 architecture.
292#[derive(Copy, Clone, Debug, Eq, PartialEq)]
293#[allow(clippy::upper_case_acronyms)]
294pub enum ARM64Register {
295    /// General-purpose registers.
296    GPR(GPR),
297    /// NEON (floating point/SIMD) registers.
298    NEON(NEON),
299}
300
301impl CombinedRegister for ARM64Register {
302    /// Returns the index of the register.
303    fn to_index(&self) -> RegisterIndex {
304        match *self {
305            ARM64Register::GPR(x) => RegisterIndex(x as usize),
306            ARM64Register::NEON(x) => RegisterIndex(x as usize + 64),
307        }
308    }
309    /// Convert from a GPR register
310    fn from_gpr(x: u16) -> Self {
311        ARM64Register::GPR(GPR::from_index(x as usize).unwrap())
312    }
313    /// Convert from an SIMD register
314    fn from_simd(x: u16) -> Self {
315        ARM64Register::NEON(NEON::from_index(x as usize).unwrap())
316    }
317}
318
319/// An allocator that allocates registers for function arguments according to the System V ABI.
320#[derive(Default)]
321pub struct ArgumentRegisterAllocator {
322    n_gprs: usize,
323    n_neons: usize,
324}
325
326impl ArgumentRegisterAllocator {
327    /// Allocates a register for argument type `ty`. Returns `None` if no register is available for this type.
328    pub fn next(
329        &mut self,
330        ty: Type,
331        calling_convention: CallingConvention,
332    ) -> Result<Option<ARM64Register>, CompileError> {
333        let ret = match calling_convention {
334            CallingConvention::SystemV | CallingConvention::AppleAarch64 => {
335                static GPR_SEQ: &[GPR] = &[
336                    GPR::X0,
337                    GPR::X1,
338                    GPR::X2,
339                    GPR::X3,
340                    GPR::X4,
341                    GPR::X5,
342                    GPR::X6,
343                    GPR::X7,
344                ];
345                static NEON_SEQ: &[NEON] = &[
346                    NEON::V0,
347                    NEON::V1,
348                    NEON::V2,
349                    NEON::V3,
350                    NEON::V4,
351                    NEON::V5,
352                    NEON::V6,
353                    NEON::V7,
354                ];
355                match ty {
356                    Type::I32 | Type::I64 => {
357                        if self.n_gprs < GPR_SEQ.len() {
358                            let gpr = GPR_SEQ[self.n_gprs];
359                            self.n_gprs += 1;
360                            Some(ARM64Register::GPR(gpr))
361                        } else {
362                            None
363                        }
364                    }
365                    Type::F32 | Type::F64 => {
366                        if self.n_neons < NEON_SEQ.len() {
367                            let neon = NEON_SEQ[self.n_neons];
368                            self.n_neons += 1;
369                            Some(ARM64Register::NEON(neon))
370                        } else {
371                            None
372                        }
373                    }
374                    _ => {
375                        return Err(CompileError::Codegen(format!(
376                            "No register available for {calling_convention:?} and type {ty}"
377                        )));
378                    }
379                }
380            }
381            _ => {
382                return Err(CompileError::Codegen(format!(
383                    "No register available for {calling_convention:?} and type {ty}"
384                )));
385            }
386        };
387
388        Ok(ret)
389    }
390}
391
392/// Create a new `MachineState` with default values.
393pub fn new_machine_state() -> MachineState {
394    MachineState {
395        stack_values: vec![],
396        register_values: vec![MachineValue::Undefined; 32 + 32],
397        prev_frame: BTreeMap::new(),
398        wasm_stack: vec![],
399        wasm_inst_offset: usize::MAX,
400    }
401}