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, PartialEq)]
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, PartialEq)]
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 is_memory_only(&self) -> bool {
384 matches!(self.kind(), OperandKind::Mem(_))
385 }
386
387 #[must_use]
390 pub fn uses_register(&self) -> bool {
391 use OperandKind::*;
392 match self.kind() {
393 Imm(_) => false,
394 FixedReg(_) | Reg(_) | RegMem(_) | Mem(_) => true,
395 }
396 }
397
398 #[must_use]
400 pub fn kind(&self) -> OperandKind {
401 use Location::*;
402 match self {
403 al | ax | eax | rax | rbx | cl | rcx | dx | edx | rdx | xmm0 => {
404 OperandKind::FixedReg(*self)
405 }
406 imm8 | imm16 | imm32 | imm64 => OperandKind::Imm(*self),
407 r8 | r16 | r32 | r32a | r32b | r64 | r64a | r64b | xmm1 | xmm2 | xmm3 => {
408 OperandKind::Reg(*self)
409 }
410 rm8 | rm16 | rm32 | rm64 | xmm_m8 | xmm_m16 | xmm_m32 | xmm_m64 | xmm_m128 => {
411 OperandKind::RegMem(*self)
412 }
413 m8 | m16 | m32 | m64 | m128 => OperandKind::Mem(*self),
414 }
415 }
416
417 #[must_use]
422 pub fn reg_class(&self) -> Option<RegClass> {
423 use Location::*;
424 match self {
425 imm8 | imm16 | imm32 | imm64 | m8 | m16 | m32 | m64 | m128 => None,
426 al | ax | eax | rax | rbx | cl | rcx | dx | edx | rdx | r8 | r16 | r32 | r32a
427 | r32b | r64 | r64a | r64b | rm8 | rm16 | rm32 | rm64 => Some(RegClass::Gpr),
428 xmm1 | xmm2 | xmm3 | xmm_m8 | xmm_m16 | xmm_m32 | xmm_m64 | xmm_m128 | xmm0 => {
429 Some(RegClass::Xmm)
430 }
431 }
432 }
433}
434
435impl core::fmt::Display for Location {
436 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
437 use Location::*;
438 match self {
439 imm8 => write!(f, "imm8"),
440 imm16 => write!(f, "imm16"),
441 imm32 => write!(f, "imm32"),
442 imm64 => write!(f, "imm64"),
443
444 al => write!(f, "al"),
445 ax => write!(f, "ax"),
446 eax => write!(f, "eax"),
447 rax => write!(f, "rax"),
448 rbx => write!(f, "rbx"),
449 cl => write!(f, "cl"),
450 rcx => write!(f, "rcx"),
451 dx => write!(f, "dx"),
452 edx => write!(f, "edx"),
453 rdx => write!(f, "rdx"),
454 xmm0 => write!(f, "xmm0"),
455
456 r8 => write!(f, "r8"),
457 r16 => write!(f, "r16"),
458 r32 => write!(f, "r32"),
459 r32a => write!(f, "r32a"),
460 r32b => write!(f, "r32b"),
461 r64 => write!(f, "r64"),
462 r64a => write!(f, "r64a"),
463 r64b => write!(f, "r64b"),
464 rm8 => write!(f, "rm8"),
465 rm16 => write!(f, "rm16"),
466 rm32 => write!(f, "rm32"),
467 rm64 => write!(f, "rm64"),
468
469 xmm1 => write!(f, "xmm1"),
470 xmm2 => write!(f, "xmm2"),
471 xmm3 => write!(f, "xmm3"),
472 xmm_m8 => write!(f, "xmm_m8"),
473 xmm_m16 => write!(f, "xmm_m16"),
474 xmm_m32 => write!(f, "xmm_m32"),
475 xmm_m64 => write!(f, "xmm_m64"),
476 xmm_m128 => write!(f, "xmm_m128"),
477
478 m8 => write!(f, "m8"),
479 m16 => write!(f, "m16"),
480 m32 => write!(f, "m32"),
481 m64 => write!(f, "m64"),
482 m128 => write!(f, "m128"),
483 }
484 }
485}
486
487#[derive(Clone, Copy, Debug)]
494pub enum OperandKind {
495 FixedReg(Location),
496 Imm(Location),
497 Reg(Location),
498 RegMem(Location),
499 Mem(Location),
500}
501
502#[derive(Clone, Copy, Debug, PartialEq)]
510pub enum Mutability {
511 Read,
512 ReadWrite,
513 Write,
514}
515
516impl Mutability {
517 pub fn is_read(&self) -> bool {
521 match self {
522 Mutability::Read | Mutability::ReadWrite => true,
523 Mutability::Write => false,
524 }
525 }
526
527 pub fn is_write(&self) -> bool {
531 match self {
532 Mutability::Read => false,
533 Mutability::ReadWrite | Mutability::Write => true,
534 }
535 }
536}
537
538impl Default for Mutability {
539 fn default() -> Self {
540 Self::Read
541 }
542}
543
544impl core::fmt::Display for Mutability {
545 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
546 match self {
547 Self::Read => write!(f, "r"),
548 Self::ReadWrite => write!(f, "rw"),
549 Self::Write => write!(f, "w"),
550 }
551 }
552}
553
554#[derive(Clone, Copy, Debug, PartialEq)]
561pub enum Extension {
562 None,
563 SignExtendQuad,
564 SignExtendLong,
565 SignExtendWord,
566}
567
568impl Extension {
569 #[must_use]
571 pub fn is_sign_extended(&self) -> bool {
572 matches!(
573 self,
574 Self::SignExtendQuad | Self::SignExtendLong | Self::SignExtendWord
575 )
576 }
577}
578
579impl Default for Extension {
580 fn default() -> Self {
581 Self::None
582 }
583}
584
585impl core::fmt::Display for Extension {
586 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
587 match self {
588 Extension::None => write!(f, ""),
589 Extension::SignExtendQuad => write!(f, "sxq"),
590 Extension::SignExtendLong => write!(f, "sxl"),
591 Extension::SignExtendWord => write!(f, "sxw"),
592 }
593 }
594}
595
596#[derive(Clone, Copy, Debug, PartialEq)]
603pub enum Eflags {
604 None,
605 R,
606 W,
607 RW,
608}
609
610impl Eflags {
611 pub fn is_read(&self) -> bool {
614 match self {
615 Eflags::None | Eflags::W => false,
616 Eflags::R | Eflags::RW => true,
617 }
618 }
619
620 pub fn is_write(&self) -> bool {
623 match self {
624 Eflags::None | Eflags::R => false,
625 Eflags::W | Eflags::RW => true,
626 }
627 }
628}
629
630impl Default for Eflags {
631 fn default() -> Self {
632 Self::None
633 }
634}
635
636impl core::fmt::Display for Eflags {
637 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
638 match self {
639 Self::None => write!(f, ""),
640 Self::R => write!(f, "r"),
641 Self::W => write!(f, "w"),
642 Self::RW => write!(f, "rw"),
643 }
644 }
645}