1pub fn fmt(
21 name: impl Into<String>,
22 operands: impl IntoIterator<Item = impl Into<Operand>>,
23) -> Format {
24 Format {
25 name: name.into(),
26 operands: operands.into_iter().map(Into::into).collect(),
27 }
28}
29
30#[must_use]
37pub fn rw(location: Location) -> Operand {
38 assert!(!matches!(location.kind(), OperandKind::Imm(_)));
39 Operand {
40 location,
41 mutability: Mutability::ReadWrite,
42 extension: Extension::default(),
43 align: false,
44 }
45}
46
47#[must_use]
49pub fn r(op: impl Into<Operand>) -> Operand {
50 let op = op.into();
51 assert!(op.mutability.is_read());
52 op
53}
54
55#[must_use]
57pub fn w(location: Location) -> Operand {
58 Operand {
59 location,
60 mutability: Mutability::Write,
61 extension: Extension::None,
62 align: false,
63 }
64}
65
66pub fn align(location: Location) -> Operand {
68 assert!(location.uses_memory());
69 Operand {
70 location,
71 mutability: Mutability::Read,
72 extension: Extension::None,
73 align: true,
74 }
75}
76
77#[must_use]
84pub fn sxq(location: Location) -> Operand {
85 assert!(location.bits() <= 64);
86 Operand {
87 location,
88 mutability: Mutability::Read,
89 extension: Extension::SignExtendQuad,
90 align: false,
91 }
92}
93
94#[must_use]
101pub fn sxl(location: Location) -> Operand {
102 assert!(location.bits() <= 32);
103 Operand {
104 location,
105 mutability: Mutability::Read,
106 extension: Extension::SignExtendLong,
107 align: false,
108 }
109}
110
111#[must_use]
118pub fn sxw(location: Location) -> Operand {
119 assert!(location.bits() <= 16);
120 Operand {
121 location,
122 mutability: Mutability::Read,
123 extension: Extension::SignExtendWord,
124 align: false,
125 }
126}
127
128pub struct Format {
130 pub name: String,
134 pub operands: Vec<Operand>,
137}
138
139impl Format {
140 pub fn locations(&self) -> impl Iterator<Item = &Location> + '_ {
142 self.operands.iter().map(|o| &o.location)
143 }
144
145 pub fn uses_memory(&self) -> Option<Location> {
148 debug_assert!(
149 self.locations()
150 .copied()
151 .filter(Location::uses_memory)
152 .count()
153 <= 1
154 );
155 self.locations().copied().find(Location::uses_memory)
156 }
157
158 #[must_use]
161 pub fn uses_register(&self) -> bool {
162 self.locations().any(Location::uses_register)
163 }
164
165 pub fn operands_by_kind(&self) -> Vec<OperandKind> {
167 self.locations().map(Location::kind).collect()
168 }
169}
170
171impl core::fmt::Display for Format {
172 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
173 let Format { name, operands } = self;
174 let operands = operands
175 .iter()
176 .map(|operand| format!("{operand}"))
177 .collect::<Vec<_>>()
178 .join(", ");
179 write!(f, "{name}({operands})")
180 }
181}
182
183#[derive(Clone, Copy, Debug)]
196pub struct Operand {
197 pub location: Location,
199 pub mutability: Mutability,
201 pub extension: Extension,
203 pub align: bool,
207}
208
209impl core::fmt::Display for Operand {
210 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
211 let Self {
212 location,
213 mutability,
214 extension,
215 align,
216 } = self;
217 write!(f, "{location}")?;
218 let mut flags = vec![];
219 if !matches!(mutability, Mutability::Read) {
220 flags.push(format!("{mutability}"));
221 }
222 if !matches!(extension, Extension::None) {
223 flags.push(format!("{extension}"));
224 }
225 if *align != false {
226 flags.push("align".to_owned());
227 }
228 if !flags.is_empty() {
229 write!(f, "[{}]", flags.join(","))?;
230 }
231 Ok(())
232 }
233}
234
235impl From<Location> for Operand {
236 fn from(location: Location) -> Self {
237 let mutability = Mutability::default();
238 let extension = Extension::default();
239 let align = false;
240 Self {
241 location,
242 mutability,
243 extension,
244 align,
245 }
246 }
247}
248
249pub enum RegClass {
251 Gpr,
252 Xmm,
253}
254
255impl core::fmt::Display for RegClass {
256 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
257 match self {
258 RegClass::Gpr => write!(f, "Gpr"),
259 RegClass::Xmm => write!(f, "Xmm"),
260 }
261 }
262}
263
264#[derive(Clone, Copy, Debug)]
266#[allow(non_camel_case_types, reason = "makes DSL definitions easier to read")]
267pub enum Location {
268 al,
270 ax,
271 eax,
272 rax,
273 cl,
274
275 imm8,
277 imm16,
278 imm32,
279
280 r8,
282 r16,
283 r32,
284 r64,
285 rm8,
286 rm16,
287 rm32,
288 rm64,
289
290 xmm,
292 xmm_m32,
293 xmm_m64,
294 xmm_m128,
295
296 m8,
298 m16,
299 m32,
300 m64,
301}
302
303impl Location {
304 #[must_use]
306 pub fn bits(&self) -> u8 {
307 use Location::*;
308 match self {
309 al | cl | imm8 | r8 | rm8 | m8 => 8,
310 ax | imm16 | r16 | rm16 | m16 => 16,
311 eax | imm32 | r32 | rm32 | m32 | xmm_m32 => 32,
312 rax | r64 | rm64 | m64 | xmm_m64 => 64,
313 xmm | xmm_m128 => 128,
314 }
315 }
316
317 #[must_use]
319 pub fn bytes(&self) -> u8 {
320 self.bits() / 8
321 }
322
323 #[must_use]
325 pub fn uses_memory(&self) -> bool {
326 use Location::*;
327 match self {
328 al | cl | ax | eax | rax | imm8 | imm16 | imm32 | r8 | r16 | r32 | r64 | xmm => false,
329 rm8 | rm16 | rm32 | rm64 | xmm_m32 | xmm_m64 | xmm_m128 | m8 | m16 | m32 | m64 => true,
330 }
331 }
332
333 #[must_use]
336 pub fn uses_register(&self) -> bool {
337 use Location::*;
338 match self {
339 imm8 | imm16 | imm32 => false,
340 al | ax | eax | rax | cl | r8 | r16 | r32 | r64 | rm8 | rm16 | rm32 | rm64 | xmm
341 | xmm_m32 | xmm_m64 | xmm_m128 | m8 | m16 | m32 | m64 => true,
342 }
343 }
344
345 #[must_use]
347 pub fn kind(&self) -> OperandKind {
348 use Location::*;
349 match self {
350 al | ax | eax | rax | cl => OperandKind::FixedReg(*self),
351 imm8 | imm16 | imm32 => OperandKind::Imm(*self),
352 r8 | r16 | r32 | r64 | xmm => OperandKind::Reg(*self),
353 rm8 | rm16 | rm32 | rm64 | xmm_m32 | xmm_m64 | xmm_m128 => OperandKind::RegMem(*self),
354 m8 | m16 | m32 | m64 => OperandKind::Mem(*self),
355 }
356 }
357
358 #[must_use]
363 pub fn reg_class(&self) -> Option<RegClass> {
364 use Location::*;
365 match self {
366 imm8 | imm16 | imm32 | m8 | m16 | m32 | m64 => None,
367 al | ax | eax | rax | cl | r8 | r16 | r32 | r64 | rm8 | rm16 | rm32 | rm64 => {
368 Some(RegClass::Gpr)
369 }
370 xmm | xmm_m32 | xmm_m64 | xmm_m128 => Some(RegClass::Xmm),
371 }
372 }
373}
374
375impl core::fmt::Display for Location {
376 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
377 use Location::*;
378 match self {
379 imm8 => write!(f, "imm8"),
380 imm16 => write!(f, "imm16"),
381 imm32 => write!(f, "imm32"),
382
383 al => write!(f, "al"),
384 ax => write!(f, "ax"),
385 eax => write!(f, "eax"),
386 rax => write!(f, "rax"),
387 cl => write!(f, "cl"),
388
389 r8 => write!(f, "r8"),
390 r16 => write!(f, "r16"),
391 r32 => write!(f, "r32"),
392 r64 => write!(f, "r64"),
393 rm8 => write!(f, "rm8"),
394 rm16 => write!(f, "rm16"),
395 rm32 => write!(f, "rm32"),
396 rm64 => write!(f, "rm64"),
397
398 xmm => write!(f, "xmm"),
399 xmm_m32 => write!(f, "xmm_m32"),
400 xmm_m64 => write!(f, "xmm_m64"),
401 xmm_m128 => write!(f, "xmm_m128"),
402
403 m8 => write!(f, "m8"),
404 m16 => write!(f, "m16"),
405 m32 => write!(f, "m32"),
406 m64 => write!(f, "m64"),
407 }
408 }
409}
410
411#[derive(Clone, Copy, Debug)]
418pub enum OperandKind {
419 FixedReg(Location),
420 Imm(Location),
421 Reg(Location),
422 RegMem(Location),
423 Mem(Location),
424}
425
426#[derive(Clone, Copy, Debug, PartialEq)]
434pub enum Mutability {
435 Read,
436 ReadWrite,
437 Write,
438}
439
440impl Mutability {
441 pub fn is_read(&self) -> bool {
445 match self {
446 Mutability::Read | Mutability::ReadWrite => true,
447 Mutability::Write => false,
448 }
449 }
450
451 pub fn is_write(&self) -> bool {
455 match self {
456 Mutability::Read => false,
457 Mutability::ReadWrite | Mutability::Write => true,
458 }
459 }
460}
461
462impl Default for Mutability {
463 fn default() -> Self {
464 Self::Read
465 }
466}
467
468impl core::fmt::Display for Mutability {
469 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
470 match self {
471 Self::Read => write!(f, "r"),
472 Self::ReadWrite => write!(f, "rw"),
473 Self::Write => write!(f, "w"),
474 }
475 }
476}
477
478#[derive(Clone, Copy, Debug, PartialEq)]
485pub enum Extension {
486 None,
487 SignExtendQuad,
488 SignExtendLong,
489 SignExtendWord,
490}
491
492impl Extension {
493 #[must_use]
495 pub fn is_sign_extended(&self) -> bool {
496 matches!(
497 self,
498 Self::SignExtendQuad | Self::SignExtendLong | Self::SignExtendWord
499 )
500 }
501}
502
503impl Default for Extension {
504 fn default() -> Self {
505 Self::None
506 }
507}
508
509impl core::fmt::Display for Extension {
510 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
511 match self {
512 Extension::None => write!(f, ""),
513 Extension::SignExtendQuad => write!(f, "sxq"),
514 Extension::SignExtendLong => write!(f, "sxl"),
515 Extension::SignExtendWord => write!(f, "sxw"),
516 }
517 }
518}