wasmer_compiler_singlepass/
x64_decl.rs

1//! X64 structures.
2use wasmer_compiler::CallingConvention;
3use wasmer_types::Type;
4
5/// General-purpose registers.
6#[repr(u8)]
7#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
8pub(crate) enum GPR {
9    /// RAX register
10    RAX,
11    /// RCX register
12    RCX,
13    /// RDX register
14    RDX,
15    /// RBX register
16    RBX,
17    /// RSP register
18    RSP,
19    /// RBP register
20    RBP,
21    /// RSI register
22    RSI,
23    /// RDI register
24    RDI,
25    /// R8 register
26    R8,
27    /// R9 register
28    R9,
29    /// R10 register
30    R10,
31    /// R11 register
32    R11,
33    /// R12 register
34    R12,
35    /// R13 register
36    R13,
37    /// R14 register
38    R14,
39    /// R15 register
40    R15,
41}
42
43/// XMM registers.
44#[repr(u8)]
45#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
46#[allow(dead_code)]
47pub(crate) enum XMM {
48    /// XMM register 0
49    XMM0,
50    /// XMM register 1
51    XMM1,
52    /// XMM register 2
53    XMM2,
54    /// XMM register 3
55    XMM3,
56    /// XMM register 4
57    XMM4,
58    /// XMM register 5
59    XMM5,
60    /// XMM register 6
61    XMM6,
62    /// XMM register 7
63    XMM7,
64    /// XMM register 8
65    XMM8,
66    /// XMM register 9
67    XMM9,
68    /// XMM register 10
69    XMM10,
70    /// XMM register 11
71    XMM11,
72    /// XMM register 12
73    XMM12,
74    /// XMM register 13
75    XMM13,
76    /// XMM register 14
77    XMM14,
78    /// XMM register 15
79    XMM15,
80}
81
82/// A machine register under the x86-64 architecture.
83#[derive(Copy, Clone, Debug, Eq, PartialEq)]
84pub(crate) enum X64Register {
85    /// General-purpose registers.
86    GPR(GPR),
87    /// XMM (floating point/SIMD) registers.
88    XMM(XMM),
89}
90
91impl X64Register {
92    /// Converts a DWARF regnum to X64Register.
93    pub(crate) fn _from_dwarf_regnum(x: u16) -> Option<X64Register> {
94        Some(match x {
95            0 => X64Register::GPR(GPR::RAX),
96            1 => X64Register::GPR(GPR::RDX),
97            2 => X64Register::GPR(GPR::RCX),
98            3 => X64Register::GPR(GPR::RBX),
99            4 => X64Register::GPR(GPR::RSI),
100            5 => X64Register::GPR(GPR::RDI),
101            6 => X64Register::GPR(GPR::RBP),
102            7 => X64Register::GPR(GPR::RSP),
103            8 => X64Register::GPR(GPR::R8),
104            9 => X64Register::GPR(GPR::R9),
105            10 => X64Register::GPR(GPR::R10),
106            11 => X64Register::GPR(GPR::R11),
107            12 => X64Register::GPR(GPR::R12),
108            13 => X64Register::GPR(GPR::R13),
109            14 => X64Register::GPR(GPR::R14),
110            15 => X64Register::GPR(GPR::R15),
111
112            17 => X64Register::XMM(XMM::XMM0),
113            18 => X64Register::XMM(XMM::XMM1),
114            19 => X64Register::XMM(XMM::XMM2),
115            20 => X64Register::XMM(XMM::XMM3),
116            21 => X64Register::XMM(XMM::XMM4),
117            22 => X64Register::XMM(XMM::XMM5),
118            23 => X64Register::XMM(XMM::XMM6),
119            24 => X64Register::XMM(XMM::XMM7),
120            _ => return None,
121        })
122    }
123
124    /// Returns the instruction prefix for `movq %this_reg, ?(%rsp)`.
125    ///
126    /// To build an instruction, append the memory location as a 32-bit
127    /// offset to the stack pointer to this prefix.
128    pub(crate) fn _prefix_mov_to_stack(&self) -> Option<&'static [u8]> {
129        Some(match *self {
130            X64Register::GPR(gpr) => match gpr {
131                GPR::RDI => &[0x48, 0x89, 0xbc, 0x24],
132                GPR::RSI => &[0x48, 0x89, 0xb4, 0x24],
133                GPR::RDX => &[0x48, 0x89, 0x94, 0x24],
134                GPR::RCX => &[0x48, 0x89, 0x8c, 0x24],
135                GPR::R8 => &[0x4c, 0x89, 0x84, 0x24],
136                GPR::R9 => &[0x4c, 0x89, 0x8c, 0x24],
137                _ => return None,
138            },
139            X64Register::XMM(xmm) => match xmm {
140                XMM::XMM0 => &[0x66, 0x0f, 0xd6, 0x84, 0x24],
141                XMM::XMM1 => &[0x66, 0x0f, 0xd6, 0x8c, 0x24],
142                XMM::XMM2 => &[0x66, 0x0f, 0xd6, 0x94, 0x24],
143                XMM::XMM3 => &[0x66, 0x0f, 0xd6, 0x9c, 0x24],
144                XMM::XMM4 => &[0x66, 0x0f, 0xd6, 0xa4, 0x24],
145                XMM::XMM5 => &[0x66, 0x0f, 0xd6, 0xac, 0x24],
146                XMM::XMM6 => &[0x66, 0x0f, 0xd6, 0xb4, 0x24],
147                XMM::XMM7 => &[0x66, 0x0f, 0xd6, 0xbc, 0x24],
148                _ => return None,
149            },
150        })
151    }
152}
153
154/// An allocator that allocates registers for function arguments according to the System V ABI.
155#[derive(Default)]
156pub(crate) struct ArgumentRegisterAllocator {
157    n_gprs: usize,
158    n_xmms: usize,
159}
160
161impl ArgumentRegisterAllocator {
162    /// Allocates a register for argument type `ty`. Returns `None` if no register is available for this type.
163    pub(crate) fn next(
164        &mut self,
165        ty: Type,
166        calling_convention: CallingConvention,
167    ) -> Option<X64Register> {
168        match calling_convention {
169            CallingConvention::WindowsFastcall => {
170                static GPR_SEQ: &'static [GPR] = &[GPR::RCX, GPR::RDX, GPR::R8, GPR::R9];
171                static XMM_SEQ: &'static [XMM] = &[XMM::XMM0, XMM::XMM1, XMM::XMM2, XMM::XMM3];
172                let idx = self.n_gprs + self.n_xmms;
173                match ty {
174                    Type::I32 | Type::I64 => {
175                        if idx < 4 {
176                            let gpr = GPR_SEQ[idx];
177                            self.n_gprs += 1;
178                            Some(X64Register::GPR(gpr))
179                        } else {
180                            None
181                        }
182                    }
183                    Type::F32 | Type::F64 => {
184                        if idx < 4 {
185                            let xmm = XMM_SEQ[idx];
186                            self.n_xmms += 1;
187                            Some(X64Register::XMM(xmm))
188                        } else {
189                            None
190                        }
191                    }
192                    _ => todo!(
193                        "ArgumentRegisterAllocator::next: Unsupported type: {:?}",
194                        ty
195                    ),
196                }
197            }
198            _ => {
199                static GPR_SEQ: &'static [GPR] =
200                    &[GPR::RDI, GPR::RSI, GPR::RDX, GPR::RCX, GPR::R8, GPR::R9];
201                static XMM_SEQ: &'static [XMM] = &[
202                    XMM::XMM0,
203                    XMM::XMM1,
204                    XMM::XMM2,
205                    XMM::XMM3,
206                    XMM::XMM4,
207                    XMM::XMM5,
208                    XMM::XMM6,
209                    XMM::XMM7,
210                ];
211                match ty {
212                    Type::I32 | Type::I64 => {
213                        if self.n_gprs < GPR_SEQ.len() {
214                            let gpr = GPR_SEQ[self.n_gprs];
215                            self.n_gprs += 1;
216                            Some(X64Register::GPR(gpr))
217                        } else {
218                            None
219                        }
220                    }
221                    Type::F32 | Type::F64 => {
222                        if self.n_xmms < XMM_SEQ.len() {
223                            let xmm = XMM_SEQ[self.n_xmms];
224                            self.n_xmms += 1;
225                            Some(X64Register::XMM(xmm))
226                        } else {
227                            None
228                        }
229                    }
230                    _ => todo!(
231                        "ArgumentRegisterAllocator::next: Unsupported type: {:?}",
232                        ty
233                    ),
234                }
235            }
236        }
237    }
238}