wasmer_compiler_singlepass/
x64_decl.rs

1//! X64 structures.
2
3#![allow(clippy::upper_case_acronyms)]
4use crate::common_decl::{MachineState, MachineValue, RegisterIndex};
5use crate::location::CombinedRegister;
6use crate::location::Reg as AbstractReg;
7use std::collections::BTreeMap;
8use std::slice::Iter;
9use wasmer_types::{CompileError, Type, target::CallingConvention};
10
11/// General-purpose registers.
12#[repr(u8)]
13#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
14pub enum GPR {
15    RAX = 0,
16    RCX = 1,
17    RDX = 2,
18    RBX = 3,
19    RSP = 4,
20    RBP = 5,
21    RSI = 6,
22    RDI = 7,
23    R8 = 8,
24    R9 = 9,
25    R10 = 10,
26    R11 = 11,
27    R12 = 12,
28    R13 = 13,
29    R14 = 14,
30    R15 = 15,
31}
32
33impl From<GPR> for u8 {
34    fn from(val: GPR) -> Self {
35        val as u8
36    }
37}
38
39/// XMM registers.
40#[repr(u8)]
41#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
42#[allow(dead_code)]
43pub enum XMM {
44    XMM0 = 0,
45    XMM1 = 1,
46    XMM2 = 2,
47    XMM3 = 3,
48    XMM4 = 4,
49    XMM5 = 5,
50    XMM6 = 6,
51    XMM7 = 7,
52    XMM8 = 8,
53    XMM9 = 9,
54    XMM10 = 10,
55    XMM11 = 11,
56    XMM12 = 12,
57    XMM13 = 13,
58    XMM14 = 14,
59    XMM15 = 15,
60}
61
62impl From<XMM> for u8 {
63    fn from(val: XMM) -> Self {
64        val as u8
65    }
66}
67
68impl AbstractReg for GPR {
69    fn is_callee_save(self) -> bool {
70        const IS_CALLEE_SAVE: [bool; 16] = [
71            false, false, false, true, true, true, false, false, false, false, false, false, true,
72            true, true, true,
73        ];
74        IS_CALLEE_SAVE[self as usize]
75    }
76    fn is_reserved(self) -> bool {
77        self == GPR::RSP || self == GPR::RBP || self == GPR::R10 || self == GPR::R15
78    }
79    fn into_index(self) -> usize {
80        self as usize
81    }
82    fn from_index(n: usize) -> Result<GPR, ()> {
83        match n {
84            0..=15 => Ok(*GPR::iterator().nth(n).unwrap()),
85            _ => Err(()),
86        }
87    }
88    fn iterator() -> Iter<'static, GPR> {
89        static GPRS: [GPR; 16] = [
90            GPR::RAX,
91            GPR::RCX,
92            GPR::RDX,
93            GPR::RBX,
94            GPR::RSP,
95            GPR::RBP,
96            GPR::RSI,
97            GPR::RDI,
98            GPR::R8,
99            GPR::R9,
100            GPR::R10,
101            GPR::R11,
102            GPR::R12,
103            GPR::R13,
104            GPR::R14,
105            GPR::R15,
106        ];
107        GPRS.iter()
108    }
109    #[cfg(feature = "unwind")]
110    fn to_dwarf(self) -> gimli::Register {
111        use gimli::X86_64;
112
113        match self {
114            GPR::RAX => X86_64::RAX,
115            GPR::RCX => X86_64::RCX,
116            GPR::RDX => X86_64::RDX,
117            GPR::RBX => X86_64::RBX,
118            GPR::RSP => X86_64::RSP,
119            GPR::RBP => X86_64::RBP,
120            GPR::RSI => X86_64::RSI,
121            GPR::RDI => X86_64::RDI,
122            GPR::R8 => X86_64::R8,
123            GPR::R9 => X86_64::R9,
124            GPR::R10 => X86_64::R10,
125            GPR::R11 => X86_64::R11,
126            GPR::R12 => X86_64::R12,
127            GPR::R13 => X86_64::R13,
128            GPR::R14 => X86_64::R14,
129            GPR::R15 => X86_64::R15,
130        }
131    }
132}
133
134impl AbstractReg for XMM {
135    fn is_callee_save(self) -> bool {
136        const IS_CALLEE_SAVE: [bool; 16] = [
137            false, false, false, false, false, false, false, false, true, true, true, true, true,
138            true, true, true,
139        ];
140        IS_CALLEE_SAVE[self as usize]
141    }
142    fn is_reserved(self) -> bool {
143        false
144    }
145    fn into_index(self) -> usize {
146        self as usize
147    }
148    fn from_index(n: usize) -> Result<XMM, ()> {
149        match n {
150            0..=15 => Ok(*XMM::iterator().nth(n).unwrap()),
151            _ => Err(()),
152        }
153    }
154    fn iterator() -> Iter<'static, XMM> {
155        static XMMS: [XMM; 16] = [
156            XMM::XMM0,
157            XMM::XMM1,
158            XMM::XMM2,
159            XMM::XMM3,
160            XMM::XMM4,
161            XMM::XMM5,
162            XMM::XMM6,
163            XMM::XMM7,
164            XMM::XMM8,
165            XMM::XMM9,
166            XMM::XMM10,
167            XMM::XMM11,
168            XMM::XMM12,
169            XMM::XMM13,
170            XMM::XMM14,
171            XMM::XMM15,
172        ];
173        XMMS.iter()
174    }
175    #[cfg(feature = "unwind")]
176    fn to_dwarf(self) -> gimli::Register {
177        use gimli::X86_64;
178
179        match self {
180            XMM::XMM0 => X86_64::XMM0,
181            XMM::XMM1 => X86_64::XMM1,
182            XMM::XMM2 => X86_64::XMM2,
183            XMM::XMM3 => X86_64::XMM3,
184            XMM::XMM4 => X86_64::XMM4,
185            XMM::XMM5 => X86_64::XMM5,
186            XMM::XMM6 => X86_64::XMM6,
187            XMM::XMM7 => X86_64::XMM7,
188            XMM::XMM8 => X86_64::XMM8,
189            XMM::XMM9 => X86_64::XMM9,
190            XMM::XMM10 => X86_64::XMM10,
191            XMM::XMM11 => X86_64::XMM11,
192            XMM::XMM12 => X86_64::XMM12,
193            XMM::XMM13 => X86_64::XMM13,
194            XMM::XMM14 => X86_64::XMM14,
195            XMM::XMM15 => X86_64::XMM15,
196        }
197    }
198}
199
200/// A machine register under the x86-64 architecture.
201#[derive(Copy, Clone, Debug, Eq, PartialEq)]
202pub enum X64Register {
203    /// General-purpose registers.
204    GPR(GPR),
205    /// XMM (floating point/SIMD) registers.
206    XMM(XMM),
207}
208
209impl CombinedRegister for X64Register {
210    /// Returns the index of the register.
211    fn to_index(&self) -> RegisterIndex {
212        match *self {
213            X64Register::GPR(x) => RegisterIndex(x as usize),
214            X64Register::XMM(x) => RegisterIndex(x as usize + 16),
215        }
216    }
217    /// Convert from a GPR register
218    fn from_gpr(x: u16) -> Self {
219        X64Register::GPR(GPR::from_index(x as usize).unwrap())
220    }
221    /// Convert from an SIMD register
222    fn from_simd(x: u16) -> Self {
223        X64Register::XMM(XMM::from_index(x as usize).unwrap())
224    }
225
226    /* x86_64-abi-0.99.pdf
227     * Register Name                    | Number | Abbreviation
228     * General Purpose Register RAX     | 0      | %rax
229     * General Purpose Register RDX     | 1      | %rdx
230     * General Purpose Register RCX     | 2      | %rcx
231     * General Purpose Register RBX     | 3      | %rbx
232     * General Purpose Register RSI     | 4      | %rsi
233     * General Purpose Register RDI     | 5      | %rdi
234     * Frame Pointer Register   RBP     | 6      | %rbp
235     * Stack Pointer Register   RSP     | 7      | %rsp
236     * Extended Integer Registers 8-15  | 8-15   | %r8-%r15
237     * Return Address RA                | 16     |
238     * Vector Registers 0-7             | 17-24  | %xmm0-%xmm7
239     * Extended Vector Registers 8-15   | 25-32  | %xmm8-%xmm15
240     * Floating Point Registers 0-7     | 33-40  | %st0-%st7
241     * MMX Registers 0-7                | 41-48  | %mm0-%mm7
242     * Flag Register                    | 49     | %rFLAGS
243     * Segment Register ES              | 50     | %es
244     * Segment Register CS              | 51     | %cs
245     * Segment Register SS              | 52     | %ss
246     * Segment Register DS              | 53     | %ds
247     * Segment Register FS              | 54     | %fs
248     * Segment Register GS              | 55     | %gs
249     * Reserved                         | 56-57  |
250     * FS Base address                  | 58     | %fs.base
251     * GS Base address                  | 59     | %gs.base
252     * Reserved                         | 60-61  |
253     * Task Register                    | 62     | %tr
254     * LDT Register                     | 63     | %ldtr
255     * 128-bit Media Control and Status | 64     | %mxcsr
256     * x87 Control Word                 | 65     | %fcw
257     * x87 Status Word                  | 66     | %fsw
258     */
259}
260
261/// An allocator that allocates registers for function arguments according to the System V ABI.
262#[derive(Default)]
263pub struct ArgumentRegisterAllocator {
264    n_gprs: usize,
265    n_xmms: usize,
266}
267
268impl ArgumentRegisterAllocator {
269    /// Allocates a register for argument type `ty`. Returns `None` if no register is available for this type.
270    pub fn next(
271        &mut self,
272        ty: Type,
273        calling_convention: CallingConvention,
274    ) -> Result<Option<X64Register>, CompileError> {
275        let ret = match calling_convention {
276            CallingConvention::WindowsFastcall => {
277                static GPR_SEQ: &[GPR] = &[GPR::RCX, GPR::RDX, GPR::R8, GPR::R9];
278                static XMM_SEQ: &[XMM] = &[XMM::XMM0, XMM::XMM1, XMM::XMM2, XMM::XMM3];
279                let idx = self.n_gprs + self.n_xmms;
280                match ty {
281                    Type::I32 | Type::I64 => {
282                        if idx < 4 {
283                            let gpr = GPR_SEQ[idx];
284                            self.n_gprs += 1;
285                            Some(X64Register::GPR(gpr))
286                        } else {
287                            None
288                        }
289                    }
290                    Type::F32 | Type::F64 => {
291                        if idx < 4 {
292                            let xmm = XMM_SEQ[idx];
293                            self.n_xmms += 1;
294                            Some(X64Register::XMM(xmm))
295                        } else {
296                            None
297                        }
298                    }
299                    _ => {
300                        return Err(CompileError::Codegen(format!(
301                            "No register available for {calling_convention:?} and type {ty}"
302                        )));
303                    }
304                }
305            }
306            _ => {
307                static GPR_SEQ: &[GPR] =
308                    &[GPR::RDI, GPR::RSI, GPR::RDX, GPR::RCX, GPR::R8, GPR::R9];
309                static XMM_SEQ: &[XMM] = &[
310                    XMM::XMM0,
311                    XMM::XMM1,
312                    XMM::XMM2,
313                    XMM::XMM3,
314                    XMM::XMM4,
315                    XMM::XMM5,
316                    XMM::XMM6,
317                    XMM::XMM7,
318                ];
319                match ty {
320                    Type::I32 | Type::I64 => {
321                        if self.n_gprs < GPR_SEQ.len() {
322                            let gpr = GPR_SEQ[self.n_gprs];
323                            self.n_gprs += 1;
324                            Some(X64Register::GPR(gpr))
325                        } else {
326                            None
327                        }
328                    }
329                    Type::F32 | Type::F64 => {
330                        if self.n_xmms < XMM_SEQ.len() {
331                            let xmm = XMM_SEQ[self.n_xmms];
332                            self.n_xmms += 1;
333                            Some(X64Register::XMM(xmm))
334                        } else {
335                            None
336                        }
337                    }
338                    _ => {
339                        return Err(CompileError::Codegen(format!(
340                            "No register available for {calling_convention:?} and type {ty}"
341                        )));
342                    }
343                }
344            }
345        };
346
347        Ok(ret)
348    }
349}
350
351/// Create a new `MachineState` with default values.
352pub fn new_machine_state() -> MachineState {
353    MachineState {
354        stack_values: vec![],
355        register_values: vec![MachineValue::Undefined; 16 + 8],
356        prev_frame: BTreeMap::new(),
357        wasm_stack: vec![],
358        wasm_inst_offset: usize::MAX,
359    }
360}