1pub fn fmt(name: impl Into<String>, operands: impl IntoIterator<Item = Operand>) -> Format {
21 Format {
22 name: name.into(),
23 operands: operands.into_iter().collect(),
24 eflags: Eflags::default(),
25 }
26}
27
28#[must_use]
35pub fn rw(op: impl Into<Operand>) -> Operand {
36 let op = op.into();
37 assert!(!matches!(op.location.kind(), OperandKind::Imm(_)));
38 Operand {
39 mutability: Mutability::ReadWrite,
40 ..op
41 }
42}
43
44#[must_use]
46pub fn r(op: impl Into<Operand>) -> Operand {
47 let op = op.into();
48 assert!(op.mutability.is_read());
49 op
50}
51
52#[must_use]
54pub fn w(op: impl Into<Operand>) -> Operand {
55 let op = op.into();
56 Operand {
57 mutability: Mutability::Write,
58 ..op
59 }
60}
61
62pub fn align(location: Location) -> Operand {
64 assert!(location.uses_memory());
65 Operand {
66 align: true,
67 ..Operand::from(location)
68 }
69}
70
71pub fn implicit(location: Location) -> Operand {
74 assert!(matches!(location.kind(), OperandKind::FixedReg(_)));
75 Operand {
76 implicit: true,
77 ..Operand::from(location)
78 }
79}
80
81#[must_use]
88pub fn sxq(location: Location) -> Operand {
89 assert!(location.bits() <= 64);
90 Operand {
91 extension: Extension::SignExtendQuad,
92 ..Operand::from(location)
93 }
94}
95
96#[must_use]
103pub fn sxl(location: Location) -> Operand {
104 assert!(location.bits() <= 32);
105 Operand {
106 extension: Extension::SignExtendLong,
107 ..Operand::from(location)
108 }
109}
110
111#[must_use]
118pub fn sxw(location: Location) -> Operand {
119 assert!(location.bits() <= 16);
120 Operand {
121 extension: Extension::SignExtendWord,
122 ..Operand::from(location)
123 }
124}
125
126#[derive(Clone)]
128pub struct Format {
129 pub name: String,
133 pub operands: Vec<Operand>,
136 pub eflags: Eflags,
138}
139
140impl Format {
141 pub fn locations(&self) -> impl Iterator<Item = &Location> + '_ {
143 self.operands.iter().map(|o| &o.location)
144 }
145
146 pub fn uses_memory(&self) -> Option<Location> {
149 debug_assert!(
150 self.locations()
151 .copied()
152 .filter(Location::uses_memory)
153 .count()
154 <= 1
155 );
156 self.locations().copied().find(Location::uses_memory)
157 }
158
159 #[must_use]
162 pub fn uses_register(&self) -> bool {
163 self.locations().any(Location::uses_register)
164 }
165
166 pub fn operands_by_kind(&self) -> Vec<OperandKind> {
168 self.locations().map(Location::kind).collect()
169 }
170
171 pub fn flags(mut self, eflags: Eflags) -> Self {
173 self.eflags = eflags;
174 self
175 }
176
177 pub fn uses_eflags(&self) -> bool {
179 self.eflags != Eflags::None
180 }
181}
182
183impl core::fmt::Display for Format {
184 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
185 let Format {
186 name,
187 operands,
188 eflags,
189 } = self;
190 let operands = operands
191 .iter()
192 .map(|operand| format!("{operand}"))
193 .collect::<Vec<_>>()
194 .join(", ");
195 write!(f, "{name}({operands})")?;
196
197 if *eflags != Eflags::None {
198 write!(f, "[flags:{eflags}]")?;
199 }
200
201 Ok(())
202 }
203}
204
205#[derive(Clone, Copy, Debug)]
218pub struct Operand {
219 pub location: Location,
221 pub mutability: Mutability,
223 pub extension: Extension,
225 pub align: bool,
229 pub implicit: bool,
232}
233
234impl core::fmt::Display for Operand {
235 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
236 let Self {
237 location,
238 mutability,
239 extension,
240 align,
241 implicit,
242 } = self;
243 write!(f, "{location}")?;
244 let mut flags = vec![];
245 if !matches!(mutability, Mutability::Read) {
246 flags.push(format!("{mutability}"));
247 }
248 if !matches!(extension, Extension::None) {
249 flags.push(format!("{extension}"));
250 }
251 if *align != false {
252 flags.push("align".to_owned());
253 }
254 if *implicit {
255 flags.push("implicit".to_owned());
256 }
257 if !flags.is_empty() {
258 write!(f, "[{}]", flags.join(","))?;
259 }
260 Ok(())
261 }
262}
263
264impl From<Location> for Operand {
265 fn from(location: Location) -> Self {
266 let mutability = Mutability::default();
267 let extension = Extension::default();
268 let align = false;
269 let implicit = false;
270 Self {
271 location,
272 mutability,
273 extension,
274 align,
275 implicit,
276 }
277 }
278}
279
280pub enum RegClass {
282 Gpr,
283 Xmm,
284}
285
286impl core::fmt::Display for RegClass {
287 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
288 match self {
289 RegClass::Gpr => write!(f, "Gpr"),
290 RegClass::Xmm => write!(f, "Xmm"),
291 }
292 }
293}
294
295#[derive(Clone, Copy, Debug)]
297#[allow(non_camel_case_types, reason = "makes DSL definitions easier to read")]
298pub enum Location {
299 al,
301 ax,
302 eax,
303 rax,
304 rbx,
305 dx,
306 edx,
307 rdx,
308 cl,
309 rcx,
310 xmm0,
311
312 imm8,
314 imm16,
315 imm32,
316 imm64,
317
318 r8,
320 r16,
321 r32,
322 r32a,
323 r32b,
324 r64,
325 r64a,
326 r64b,
327 rm8,
328 rm16,
329 rm32,
330 rm64,
331
332 xmm1,
334 xmm2,
335 xmm3,
336 xmm_m8,
337 xmm_m16,
338 xmm_m32,
339 xmm_m64,
340 xmm_m128,
341
342 m8,
344 m16,
345 m32,
346 m64,
347 m128,
348}
349
350impl Location {
351 #[must_use]
353 pub fn bits(&self) -> u16 {
354 use Location::*;
355 match self {
356 al | cl | imm8 | r8 | rm8 | m8 | xmm_m8 => 8,
357 ax | dx | imm16 | r16 | rm16 | m16 | xmm_m16 => 16,
358 eax | edx | imm32 | r32 | r32a | r32b | rm32 | m32 | xmm_m32 => 32,
359 rax | rbx | rcx | rdx | imm64 | r64 | r64a | r64b | rm64 | m64 | xmm_m64 => 64,
360 xmm1 | xmm2 | xmm3 | xmm_m128 | xmm0 | m128 => 128,
361 }
362 }
363
364 #[must_use]
366 pub fn bytes(&self) -> u16 {
367 self.bits() / 8
368 }
369
370 #[must_use]
372 pub fn uses_memory(&self) -> bool {
373 use OperandKind::*;
374 match self.kind() {
375 FixedReg(_) | Imm(_) | Reg(_) => false,
376 RegMem(_) | Mem(_) => true,
377 }
378 }
379
380 #[must_use]
383 pub fn uses_register(&self) -> bool {
384 use OperandKind::*;
385 match self.kind() {
386 Imm(_) => false,
387 FixedReg(_) | Reg(_) | RegMem(_) | Mem(_) => true,
388 }
389 }
390
391 #[must_use]
393 pub fn kind(&self) -> OperandKind {
394 use Location::*;
395 match self {
396 al | ax | eax | rax | rbx | cl | rcx | dx | edx | rdx | xmm0 => {
397 OperandKind::FixedReg(*self)
398 }
399 imm8 | imm16 | imm32 | imm64 => OperandKind::Imm(*self),
400 r8 | r16 | r32 | r32a | r32b | r64 | r64a | r64b | xmm1 | xmm2 | xmm3 => {
401 OperandKind::Reg(*self)
402 }
403 rm8 | rm16 | rm32 | rm64 | xmm_m8 | xmm_m16 | xmm_m32 | xmm_m64 | xmm_m128 => {
404 OperandKind::RegMem(*self)
405 }
406 m8 | m16 | m32 | m64 | m128 => OperandKind::Mem(*self),
407 }
408 }
409
410 #[must_use]
415 pub fn reg_class(&self) -> Option<RegClass> {
416 use Location::*;
417 match self {
418 imm8 | imm16 | imm32 | imm64 | m8 | m16 | m32 | m64 | m128 => None,
419 al | ax | eax | rax | rbx | cl | rcx | dx | edx | rdx | r8 | r16 | r32 | r32a
420 | r32b | r64 | r64a | r64b | rm8 | rm16 | rm32 | rm64 => Some(RegClass::Gpr),
421 xmm1 | xmm2 | xmm3 | xmm_m8 | xmm_m16 | xmm_m32 | xmm_m64 | xmm_m128 | xmm0 => {
422 Some(RegClass::Xmm)
423 }
424 }
425 }
426}
427
428impl core::fmt::Display for Location {
429 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
430 use Location::*;
431 match self {
432 imm8 => write!(f, "imm8"),
433 imm16 => write!(f, "imm16"),
434 imm32 => write!(f, "imm32"),
435 imm64 => write!(f, "imm64"),
436
437 al => write!(f, "al"),
438 ax => write!(f, "ax"),
439 eax => write!(f, "eax"),
440 rax => write!(f, "rax"),
441 rbx => write!(f, "rbx"),
442 cl => write!(f, "cl"),
443 rcx => write!(f, "rcx"),
444 dx => write!(f, "dx"),
445 edx => write!(f, "edx"),
446 rdx => write!(f, "rdx"),
447 xmm0 => write!(f, "xmm0"),
448
449 r8 => write!(f, "r8"),
450 r16 => write!(f, "r16"),
451 r32 => write!(f, "r32"),
452 r32a => write!(f, "r32a"),
453 r32b => write!(f, "r32b"),
454 r64 => write!(f, "r64"),
455 r64a => write!(f, "r64a"),
456 r64b => write!(f, "r64b"),
457 rm8 => write!(f, "rm8"),
458 rm16 => write!(f, "rm16"),
459 rm32 => write!(f, "rm32"),
460 rm64 => write!(f, "rm64"),
461
462 xmm1 => write!(f, "xmm1"),
463 xmm2 => write!(f, "xmm2"),
464 xmm3 => write!(f, "xmm3"),
465 xmm_m8 => write!(f, "xmm_m8"),
466 xmm_m16 => write!(f, "xmm_m16"),
467 xmm_m32 => write!(f, "xmm_m32"),
468 xmm_m64 => write!(f, "xmm_m64"),
469 xmm_m128 => write!(f, "xmm_m128"),
470
471 m8 => write!(f, "m8"),
472 m16 => write!(f, "m16"),
473 m32 => write!(f, "m32"),
474 m64 => write!(f, "m64"),
475 m128 => write!(f, "m128"),
476 }
477 }
478}
479
480#[derive(Clone, Copy, Debug)]
487pub enum OperandKind {
488 FixedReg(Location),
489 Imm(Location),
490 Reg(Location),
491 RegMem(Location),
492 Mem(Location),
493}
494
495#[derive(Clone, Copy, Debug, PartialEq)]
503pub enum Mutability {
504 Read,
505 ReadWrite,
506 Write,
507}
508
509impl Mutability {
510 pub fn is_read(&self) -> bool {
514 match self {
515 Mutability::Read | Mutability::ReadWrite => true,
516 Mutability::Write => false,
517 }
518 }
519
520 pub fn is_write(&self) -> bool {
524 match self {
525 Mutability::Read => false,
526 Mutability::ReadWrite | Mutability::Write => true,
527 }
528 }
529}
530
531impl Default for Mutability {
532 fn default() -> Self {
533 Self::Read
534 }
535}
536
537impl core::fmt::Display for Mutability {
538 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
539 match self {
540 Self::Read => write!(f, "r"),
541 Self::ReadWrite => write!(f, "rw"),
542 Self::Write => write!(f, "w"),
543 }
544 }
545}
546
547#[derive(Clone, Copy, Debug, PartialEq)]
554pub enum Extension {
555 None,
556 SignExtendQuad,
557 SignExtendLong,
558 SignExtendWord,
559}
560
561impl Extension {
562 #[must_use]
564 pub fn is_sign_extended(&self) -> bool {
565 matches!(
566 self,
567 Self::SignExtendQuad | Self::SignExtendLong | Self::SignExtendWord
568 )
569 }
570}
571
572impl Default for Extension {
573 fn default() -> Self {
574 Self::None
575 }
576}
577
578impl core::fmt::Display for Extension {
579 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
580 match self {
581 Extension::None => write!(f, ""),
582 Extension::SignExtendQuad => write!(f, "sxq"),
583 Extension::SignExtendLong => write!(f, "sxl"),
584 Extension::SignExtendWord => write!(f, "sxw"),
585 }
586 }
587}
588
589#[derive(Clone, Copy, Debug, PartialEq)]
596pub enum Eflags {
597 None,
598 R,
599 W,
600 RW,
601}
602
603impl Eflags {
604 pub fn is_read(&self) -> bool {
607 match self {
608 Eflags::None | Eflags::W => false,
609 Eflags::R | Eflags::RW => true,
610 }
611 }
612
613 pub fn is_write(&self) -> bool {
616 match self {
617 Eflags::None | Eflags::R => false,
618 Eflags::W | Eflags::RW => true,
619 }
620 }
621}
622
623impl Default for Eflags {
624 fn default() -> Self {
625 Self::None
626 }
627}
628
629impl core::fmt::Display for Eflags {
630 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
631 match self {
632 Self::None => write!(f, ""),
633 Self::R => write!(f, "r"),
634 Self::W => write!(f, "w"),
635 Self::RW => write!(f, "rw"),
636 }
637 }
638}