cranelift_assembler_x64_meta/dsl/
format.rs1pub fn fmt(name: impl Into<String>, operands: impl IntoIterator<Item = impl Into<Operand>>) -> Format {
21 Format {
22 name: name.into(),
23 operands: operands.into_iter().map(Into::into).collect(),
24 }
25}
26
27#[must_use]
34pub fn rw(location: Location) -> Operand {
35 assert!(!matches!(location.kind(), OperandKind::Imm(_)));
36 Operand {
37 location,
38 mutability: Mutability::ReadWrite,
39 extension: Extension::default(),
40 }
41}
42
43#[must_use]
45pub fn r(location: Location) -> Operand {
46 Operand {
47 location,
48 mutability: Mutability::Read,
49 extension: Extension::None,
50 }
51}
52
53#[must_use]
60pub fn sxq(location: Location) -> Operand {
61 assert!(location.bits() <= 64);
62 Operand {
63 location,
64 mutability: Mutability::Read,
65 extension: Extension::SignExtendQuad,
66 }
67}
68
69#[must_use]
76pub fn sxl(location: Location) -> Operand {
77 assert!(location.bits() <= 32);
78 Operand {
79 location,
80 mutability: Mutability::Read,
81 extension: Extension::SignExtendLong,
82 }
83}
84
85#[must_use]
92pub fn sxw(location: Location) -> Operand {
93 assert!(location.bits() <= 16);
94 Operand {
95 location,
96 mutability: Mutability::Read,
97 extension: Extension::SignExtendWord,
98 }
99}
100
101pub struct Format {
103 pub name: String,
107 pub operands: Vec<Operand>,
110}
111
112impl Format {
113 pub fn locations(&self) -> impl Iterator<Item = &Location> + '_ {
115 self.operands.iter().map(|o| &o.location)
116 }
117
118 pub fn uses_memory(&self) -> Option<Location> {
121 debug_assert!(self.locations().copied().filter(Location::uses_memory).count() <= 1);
122 self.locations().copied().find(Location::uses_memory)
123 }
124
125 #[must_use]
128 pub fn uses_variable_register(&self) -> bool {
129 self.locations().any(Location::uses_variable_register)
130 }
131
132 pub fn operands_by_kind(&self) -> Vec<OperandKind> {
134 self.locations().map(Location::kind).collect()
135 }
136}
137
138impl core::fmt::Display for Format {
139 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
140 let Format { name, operands } = self;
141 let operands = operands
142 .iter()
143 .map(|operand| format!("{operand}"))
144 .collect::<Vec<_>>()
145 .join(", ");
146 write!(f, "{name}({operands})")
147 }
148}
149
150#[derive(Clone, Copy, Debug)]
162pub struct Operand {
163 pub location: Location,
165 pub mutability: Mutability,
167 pub extension: Extension,
169}
170
171impl core::fmt::Display for Operand {
172 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
173 let Self { location, mutability, extension } = self;
174 write!(f, "{location}")?;
175 let has_default_mutability = matches!(mutability, Mutability::Read);
176 let has_default_extension = matches!(extension, Extension::None);
177 match (has_default_mutability, has_default_extension) {
178 (true, true) => {}
179 (true, false) => write!(f, "[{extension}]")?,
180 (false, true) => write!(f, "[{mutability}]")?,
181 (false, false) => write!(f, "[{mutability},{extension}]")?,
182 }
183 Ok(())
184 }
185}
186
187impl From<Location> for Operand {
188 fn from(location: Location) -> Self {
189 let mutability = Mutability::default();
190 let extension = Extension::default();
191 Self { location, mutability, extension }
192 }
193}
194
195#[derive(Clone, Copy, Debug)]
197#[allow(non_camel_case_types, reason = "makes DSL definitions easier to read")]
198pub enum Location {
199 al,
200 ax,
201 eax,
202 rax,
203
204 cl,
205
206 imm8,
207 imm16,
208 imm32,
209
210 r8,
211 r16,
212 r32,
213 r64,
214
215 xmm,
216
217 rm8,
218 rm16,
219 rm32,
220 rm64,
221 rm128,
222}
223
224impl Location {
225 #[must_use]
227 pub fn bits(&self) -> u8 {
228 use Location::*;
229 match self {
230 al | cl | imm8 | r8 | rm8 => 8,
231 ax | imm16 | r16 | rm16 => 16,
232 eax | imm32 | r32 | rm32 => 32,
233 rax | r64 | rm64 => 64,
234 xmm | rm128 => 128,
235 }
236 }
237
238 #[must_use]
240 pub fn bytes(&self) -> u8 {
241 self.bits() / 8
242 }
243
244 #[must_use]
246 pub fn uses_memory(&self) -> bool {
247 use Location::*;
248 match self {
249 al | cl | ax | eax | rax | imm8 | imm16 | imm32 | r8 | r16 | r32 | r64 | xmm => false,
250 rm8 | rm16 | rm32 | rm64 | rm128 => true,
251 }
252 }
253
254 #[must_use]
257 pub fn uses_variable_register(&self) -> bool {
258 use Location::*;
259 match self {
260 al | ax | eax | rax | cl | imm8 | imm16 | imm32 => false,
261 r8 | r16 | r32 | r64 | xmm | rm8 | rm16 | rm32 | rm64 | rm128 => true,
262 }
263 }
264
265 #[must_use]
267 pub fn kind(&self) -> OperandKind {
268 use Location::*;
269 match self {
270 al | ax | eax | rax | cl => OperandKind::FixedReg(*self),
271 imm8 | imm16 | imm32 => OperandKind::Imm(*self),
272 r8 | r16 | r32 | r64 | xmm => OperandKind::Reg(*self),
273 rm8 | rm16 | rm32 | rm64 | rm128 => OperandKind::RegMem(*self),
274 }
275 }
276}
277
278impl core::fmt::Display for Location {
279 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
280 use Location::*;
281 match self {
282 al => write!(f, "al"),
283 ax => write!(f, "ax"),
284 eax => write!(f, "eax"),
285 rax => write!(f, "rax"),
286
287 cl => write!(f, "cl"),
288
289 imm8 => write!(f, "imm8"),
290 imm16 => write!(f, "imm16"),
291 imm32 => write!(f, "imm32"),
292
293 r8 => write!(f, "r8"),
294 r16 => write!(f, "r16"),
295 r32 => write!(f, "r32"),
296 r64 => write!(f, "r64"),
297
298 xmm => write!(f, "xmm"),
299
300 rm8 => write!(f, "rm8"),
301 rm16 => write!(f, "rm16"),
302 rm32 => write!(f, "rm32"),
303 rm64 => write!(f, "rm64"),
304 rm128 => write!(f, "rm128"),
305 }
306 }
307}
308
309#[derive(Clone, Copy, Debug)]
316pub enum OperandKind {
317 FixedReg(Location),
318 Imm(Location),
319 Reg(Location),
320 RegMem(Location),
321}
322
323#[derive(Clone, Copy, Debug, PartialEq)]
331pub enum Mutability {
332 Read,
333 ReadWrite,
334}
335
336impl Mutability {
337 pub fn is_read(&self) -> bool {
341 match self {
342 Mutability::Read | Mutability::ReadWrite => true,
343 }
344 }
345
346 pub fn is_write(&self) -> bool {
350 match self {
351 Mutability::Read => false,
352 Mutability::ReadWrite => true,
353 }
354 }
355}
356
357impl Default for Mutability {
358 fn default() -> Self {
359 Self::Read
360 }
361}
362
363impl core::fmt::Display for Mutability {
364 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
365 match self {
366 Self::Read => write!(f, "r"),
367 Self::ReadWrite => write!(f, "rw"),
368 }
369 }
370}
371
372#[derive(Clone, Copy, Debug, PartialEq)]
379pub enum Extension {
380 None,
381 SignExtendQuad,
382 SignExtendLong,
383 SignExtendWord,
384}
385
386impl Extension {
387 #[must_use]
389 pub fn is_sign_extended(&self) -> bool {
390 matches!(self, Self::SignExtendQuad | Self::SignExtendLong | Self::SignExtendWord)
391 }
392}
393
394impl Default for Extension {
395 fn default() -> Self {
396 Self::None
397 }
398}
399
400impl core::fmt::Display for Extension {
401 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
402 match self {
403 Extension::None => write!(f, ""),
404 Extension::SignExtendQuad => write!(f, "sxq"),
405 Extension::SignExtendLong => write!(f, "sxl"),
406 Extension::SignExtendWord => write!(f, "sxw"),
407 }
408 }
409}