1 pub mod encode {
2     use crate::{CodeSink, inst};
3 
4     /// `NOP`
5     pub fn nop_1b(_: &inst::nop_1b, buf: &mut impl CodeSink) {
6         buf.put1(0x90);
7     }
8 
9     /// `66 NOP`
10     pub fn nop_2b(_: &inst::nop_2b, buf: &mut impl CodeSink) {
11         buf.put1(0x66);
12         buf.put1(0x90);
13     }
14 
15     /// `NOP DWORD ptr [EAX]`
16     pub fn nop_3b(_: &inst::nop_3b, buf: &mut impl CodeSink) {
17         buf.put1(0x0F);
18         buf.put1(0x1F);
19         buf.put1(0x00);
20     }
21 
22     /// `NOP DWORD ptr [EAX + 00H]`
23     pub fn nop_4b(_: &inst::nop_4b, buf: &mut impl CodeSink) {
24         buf.put1(0x0F);
25         buf.put1(0x1F);
26         buf.put1(0x40);
27         buf.put1(0x00);
28     }
29 
30     /// `NOP DWORD ptr [EAX + EAX*1 + 00H]`
31     pub fn nop_5b(_: &inst::nop_5b, buf: &mut impl CodeSink) {
32         buf.put1(0x0F);
33         buf.put1(0x1F);
34         buf.put1(0x44);
35         buf.put2(0x00_00);
36     }
37 
38     /// `66 NOP DWORD ptr [EAX + EAX*1 + 00H]`
39     pub fn nop_6b(_: &inst::nop_6b, buf: &mut impl CodeSink) {
40         buf.put1(0x66);
41         buf.put1(0x0F);
42         buf.put1(0x1F);
43         buf.put1(0x44);
44         buf.put2(0x00_00);
45     }
46 
47     /// `NOP DWORD ptr [EAX + 00000000H]`
48     pub fn nop_7b(_: &inst::nop_7b, buf: &mut impl CodeSink) {
49         buf.put1(0x0F);
50         buf.put1(0x1F);
51         buf.put1(0x80);
52         buf.put4(0x00_00_00_00);
53     }
54 
55     /// `NOP DWORD ptr [EAX + EAX*1 + 00000000H]`
56     pub fn nop_8b(_: &inst::nop_8b, buf: &mut impl CodeSink) {
57         buf.put1(0x0F);
58         buf.put1(0x1F);
59         buf.put1(0x84);
60         buf.put1(0x00);
61         buf.put4(0x00_00_00_00);
62     }
63 
64     /// `66 NOP DWORD ptr [EAX + EAX*1 + 00000000H]`
65     pub fn nop_9b(_: &inst::nop_9b, buf: &mut impl CodeSink) {
66         buf.put1(0x66);
67         buf.put1(0x0F);
68         buf.put1(0x1F);
69         buf.put1(0x84);
70         buf.put1(0x00);
71         buf.put4(0x00_00_00_00);
72     }
73 }
74 
75 pub mod mnemonic {
76     use crate::inst;
77     use crate::{Registers, XmmMem};
78     use std::borrow::Cow;
79 
80     macro_rules! lock {
81         ($name:tt => $mnemonic:expr) => {
82             pub fn $name<R: Registers>(_: &inst::$name<R>) -> Cow<'static, str> {
83                 Cow::Borrowed(concat!("lock ", $mnemonic))
84             }
85         };
86     }
87 
88     lock!(lock_addb_mi => "addb");
89     lock!(lock_addw_mi => "addw");
90     lock!(lock_addl_mi => "addl");
91     lock!(lock_addq_mi_sxl => "addq");
92     lock!(lock_addl_mi_sxb => "addl");
93     lock!(lock_addq_mi_sxb => "addq");
94     lock!(lock_addb_mr => "addb");
95     lock!(lock_addw_mr => "addw");
96     lock!(lock_addl_mr => "addl");
97     lock!(lock_addq_mr => "addq");
98 
99     lock!(lock_adcb_mi => "adcb");
100     lock!(lock_adcw_mi => "adcw");
101     lock!(lock_adcl_mi => "adcl");
102     lock!(lock_adcq_mi_sxl => "adcq");
103     lock!(lock_adcl_mi_sxb => "adcl");
104     lock!(lock_adcq_mi_sxb => "adcq");
105     lock!(lock_adcb_mr => "adcb");
106     lock!(lock_adcw_mr => "adcw");
107     lock!(lock_adcl_mr => "adcl");
108     lock!(lock_adcq_mr => "adcq");
109 
110     lock!(lock_subb_mi => "subb");
111     lock!(lock_subw_mi => "subw");
112     lock!(lock_subl_mi => "subl");
113     lock!(lock_subq_mi_sxl => "subq");
114     lock!(lock_subl_mi_sxb => "subl");
115     lock!(lock_subq_mi_sxb => "subq");
116     lock!(lock_subb_mr => "subb");
117     lock!(lock_subw_mr => "subw");
118     lock!(lock_subl_mr => "subl");
119     lock!(lock_subq_mr => "subq");
120 
121     lock!(lock_sbbb_mi => "sbbb");
122     lock!(lock_sbbw_mi => "sbbw");
123     lock!(lock_sbbl_mi => "sbbl");
124     lock!(lock_sbbq_mi_sxl => "sbbq");
125     lock!(lock_sbbl_mi_sxb => "sbbl");
126     lock!(lock_sbbq_mi_sxb => "sbbq");
127     lock!(lock_sbbb_mr => "sbbb");
128     lock!(lock_sbbw_mr => "sbbw");
129     lock!(lock_sbbl_mr => "sbbl");
130     lock!(lock_sbbq_mr => "sbbq");
131 
132     lock!(lock_andb_mi => "andb");
133     lock!(lock_andw_mi => "andw");
134     lock!(lock_andl_mi => "andl");
135     lock!(lock_andq_mi_sxl => "andq");
136     lock!(lock_andl_mi_sxb => "andl");
137     lock!(lock_andq_mi_sxb => "andq");
138     lock!(lock_andb_mr => "andb");
139     lock!(lock_andw_mr => "andw");
140     lock!(lock_andl_mr => "andl");
141     lock!(lock_andq_mr => "andq");
142 
143     lock!(lock_orb_mi => "orb");
144     lock!(lock_orw_mi => "orw");
145     lock!(lock_orl_mi => "orl");
146     lock!(lock_orq_mi_sxl => "orq");
147     lock!(lock_orl_mi_sxb => "orl");
148     lock!(lock_orq_mi_sxb => "orq");
149     lock!(lock_orb_mr => "orb");
150     lock!(lock_orw_mr => "orw");
151     lock!(lock_orl_mr => "orl");
152     lock!(lock_orq_mr => "orq");
153 
154     lock!(lock_xorb_mi => "xorb");
155     lock!(lock_xorw_mi => "xorw");
156     lock!(lock_xorl_mi => "xorl");
157     lock!(lock_xorq_mi_sxl => "xorq");
158     lock!(lock_xorl_mi_sxb => "xorl");
159     lock!(lock_xorq_mi_sxb => "xorq");
160     lock!(lock_xorb_mr => "xorb");
161     lock!(lock_xorw_mr => "xorw");
162     lock!(lock_xorl_mr => "xorl");
163     lock!(lock_xorq_mr => "xorq");
164 
165     lock!(lock_xaddb_mr => "xaddb");
166     lock!(lock_xaddw_mr => "xaddw");
167     lock!(lock_xaddl_mr => "xaddl");
168     lock!(lock_xaddq_mr => "xaddq");
169 
170     lock!(lock_cmpxchgb_mr => "cmpxchgb");
171     lock!(lock_cmpxchgw_mr => "cmpxchgw");
172     lock!(lock_cmpxchgl_mr => "cmpxchgl");
173     lock!(lock_cmpxchgq_mr => "cmpxchgq");
174     lock!(lock_cmpxchg16b_m => "cmpxchg16b");
175 
176     pub fn vcvtpd2ps_a<R: Registers>(inst: &inst::vcvtpd2ps_a<R>) -> Cow<'static, str> {
177         match inst.xmm_m128 {
178             XmmMem::Xmm(_) => "vcvtpd2ps".into(),
179             XmmMem::Mem(_) => "vcvtpd2psx".into(),
180         }
181     }
182 
183     pub fn vcvttpd2dq_a<R: Registers>(inst: &inst::vcvttpd2dq_a<R>) -> Cow<'static, str> {
184         match inst.xmm_m128 {
185             XmmMem::Xmm(_) => "vcvttpd2dq".into(),
186             XmmMem::Mem(_) => "vcvttpd2dqx".into(),
187         }
188     }
189 }
190 
191 pub mod display {
192     use crate::inst;
193     use crate::{Amode, Gpr, GprMem, Registers, Size};
194     use std::fmt;
195 
196     pub fn callq_d(f: &mut fmt::Formatter, inst: &inst::callq_d) -> fmt::Result {
197         let inst::callq_d { imm32 } = inst;
198         display_displacement(f, "callq", i64::from(imm32.value()) + 5)
199     }
200 
201     pub fn callq_m<R: Registers>(f: &mut fmt::Formatter, inst: &inst::callq_m<R>) -> fmt::Result {
202         let inst::callq_m { rm64 } = inst;
203         let op = rm64.to_string(Size::Quadword);
204         write!(f, "callq *{op}")
205     }
206 
207     /// Return the predicate string used for the immediate of a `cmp*`
208     /// instruction.
209     fn pred_as_str(imm: u8) -> &'static str {
210         match imm {
211             0 => "eq",
212             1 => "lt",
213             2 => "le",
214             3 => "unord",
215             4 => "neq",
216             5 => "nlt",
217             6 => "nle",
218             7 => "ord",
219             _ => panic!("not a valid predicate for `cmp*`"),
220         }
221     }
222 
223     pub fn cmpss_a<R: Registers>(f: &mut fmt::Formatter, inst: &inst::cmpss_a<R>) -> fmt::Result {
224         let xmm1 = inst.xmm1.to_string();
225         let xmm_m32 = inst.xmm_m32.to_string();
226         let pred = inst.imm8.value();
227         if pred > 7 {
228             let imm8 = inst.imm8.to_string();
229             write!(f, "cmpss {imm8}, {xmm_m32}, {xmm1}")
230         } else {
231             write!(f, "cmp{}ss {xmm_m32}, {xmm1}", pred_as_str(pred))
232         }
233     }
234 
235     pub fn cmpsd_a<R: Registers>(f: &mut fmt::Formatter, inst: &inst::cmpsd_a<R>) -> fmt::Result {
236         let xmm1 = inst.xmm1.to_string();
237         let xmm_m64 = inst.xmm_m64.to_string();
238         let pred = inst.imm8.value();
239         if pred > 7 {
240             let imm8 = inst.imm8.to_string();
241             write!(f, "cmpsd {imm8}, {xmm_m64}, {xmm1}")
242         } else {
243             write!(f, "cmp{}sd {xmm_m64}, {xmm1}", pred_as_str(pred))
244         }
245     }
246 
247     pub fn cmpps_a<R: Registers>(f: &mut fmt::Formatter, inst: &inst::cmpps_a<R>) -> fmt::Result {
248         let xmm1 = inst.xmm1.to_string();
249         let xmm_m128 = inst.xmm_m128.to_string();
250         let pred = inst.imm8.value();
251         if pred > 7 {
252             let imm8 = inst.imm8.to_string();
253             write!(f, "cmpps {imm8}, {xmm_m128}, {xmm1}")
254         } else {
255             write!(f, "cmp{}ps {xmm_m128}, {xmm1}", pred_as_str(pred))
256         }
257     }
258 
259     pub fn cmppd_a<R: Registers>(f: &mut fmt::Formatter, inst: &inst::cmppd_a<R>) -> fmt::Result {
260         let xmm1 = inst.xmm1.to_string();
261         let xmm_m128 = inst.xmm_m128.to_string();
262         let pred = inst.imm8.value();
263         if pred > 7 {
264             let imm8 = inst.imm8.to_string();
265             write!(f, "cmppd {imm8}, {xmm_m128}, {xmm1}")
266         } else {
267             write!(f, "cmp{}pd {xmm_m128}, {xmm1}", pred_as_str(pred))
268         }
269     }
270 
271     /// Return the predicate string used for the immediate of a `vcmp*`
272     /// instruction; this is a more complex version of `pred_as_str`.
273     fn vex_pred_as_str(imm: u8) -> &'static str {
274         match imm {
275             0x0 => "eq",
276             0x1 => "lt",
277             0x2 => "le",
278             0x3 => "unord",
279             0x4 => "neq",
280             0x5 => "nlt",
281             0x6 => "nle",
282             0x7 => "ord",
283             0x8 => "eq_uq",
284             0x9 => "nge",
285             0xa => "ngt",
286             0xb => "false",
287             0xc => "neq_oq",
288             0xd => "ge",
289             0xe => "gt",
290             0xf => "true",
291             0x10 => "eq_os",
292             0x11 => "lt_oq",
293             0x12 => "le_oq",
294             0x13 => "unord_s",
295             0x14 => "neq_us",
296             0x15 => "nlt_uq",
297             0x16 => "nle_uq",
298             0x17 => "ord_s",
299             0x18 => "eq_us",
300             0x19 => "nge_uq",
301             0x1a => "ngt_uq",
302             0x1b => "false_os",
303             0x1c => "neq_os",
304             0x1d => "ge_oq",
305             0x1e => "gt_oq",
306             0x1f => "true_us",
307             _ => panic!("not a valid predicate for `cmp*`"),
308         }
309     }
310 
311     pub fn vcmpss_b<R: Registers>(f: &mut fmt::Formatter, inst: &inst::vcmpss_b<R>) -> fmt::Result {
312         let xmm1 = inst.xmm1.to_string();
313         let xmm2 = inst.xmm2.to_string();
314         let xmm_m32 = inst.xmm_m32.to_string();
315         let pred = inst.imm8.value();
316         if pred > 0x1f {
317             let imm8 = inst.imm8.to_string();
318             write!(f, "vcmpss {imm8}, {xmm_m32}, {xmm2}, {xmm1}")
319         } else {
320             write!(
321                 f,
322                 "vcmp{}ss {xmm_m32}, {xmm2}, {xmm1}",
323                 vex_pred_as_str(pred)
324             )
325         }
326     }
327 
328     pub fn vcmpsd_b<R: Registers>(f: &mut fmt::Formatter, inst: &inst::vcmpsd_b<R>) -> fmt::Result {
329         let xmm1 = inst.xmm1.to_string();
330         let xmm2 = inst.xmm2.to_string();
331         let xmm_m64 = inst.xmm_m64.to_string();
332         let pred = inst.imm8.value();
333         if pred > 0x1f {
334             let imm8 = inst.imm8.to_string();
335             write!(f, "vcmpsd {imm8}, {xmm_m64}, {xmm2}, {xmm1}")
336         } else {
337             write!(
338                 f,
339                 "vcmp{}sd {xmm_m64}, {xmm2}, {xmm1}",
340                 vex_pred_as_str(pred)
341             )
342         }
343     }
344 
345     pub fn vcmpps_b<R: Registers>(f: &mut fmt::Formatter, inst: &inst::vcmpps_b<R>) -> fmt::Result {
346         let xmm1 = inst.xmm1.to_string();
347         let xmm2 = inst.xmm2.to_string();
348         let xmm_m128 = inst.xmm_m128.to_string();
349         let pred = inst.imm8.value();
350         if pred > 0x1f {
351             let imm8 = inst.imm8.to_string();
352             write!(f, "vcmpps {imm8}, {xmm_m128}, {xmm2}, {xmm1}")
353         } else {
354             write!(
355                 f,
356                 "vcmp{}ps {xmm_m128}, {xmm2}, {xmm1}",
357                 vex_pred_as_str(pred)
358             )
359         }
360     }
361 
362     pub fn vcmppd_b<R: Registers>(f: &mut fmt::Formatter, inst: &inst::vcmppd_b<R>) -> fmt::Result {
363         let xmm1 = inst.xmm1.to_string();
364         let xmm2 = inst.xmm2.to_string();
365         let xmm_m128 = inst.xmm_m128.to_string();
366         let pred = inst.imm8.value();
367         if pred > 0x1f {
368             let imm8 = inst.imm8.to_string();
369             write!(f, "vcmppd {imm8}, {xmm_m128}, {xmm2}, {xmm1}")
370         } else {
371             write!(
372                 f,
373                 "vcmp{}pd {xmm_m128}, {xmm2}, {xmm1}",
374                 vex_pred_as_str(pred)
375             )
376         }
377     }
378 
379     pub fn nop_1b(f: &mut fmt::Formatter, _: &inst::nop_1b) -> fmt::Result {
380         write!(f, "nop")
381     }
382 
383     pub fn nop_2b(f: &mut fmt::Formatter, _: &inst::nop_2b) -> fmt::Result {
384         write!(f, "nop")
385     }
386 
387     pub fn nop_3b(f: &mut fmt::Formatter, _: &inst::nop_3b) -> fmt::Result {
388         write!(f, "nopl (%rax)")
389     }
390 
391     pub fn nop_4b(f: &mut fmt::Formatter, _: &inst::nop_4b) -> fmt::Result {
392         write!(f, "nopl (%rax)")
393     }
394 
395     pub fn nop_5b(f: &mut fmt::Formatter, _: &inst::nop_5b) -> fmt::Result {
396         write!(f, "nopl (%rax, %rax)")
397     }
398 
399     pub fn nop_6b(f: &mut fmt::Formatter, _: &inst::nop_6b) -> fmt::Result {
400         write!(f, "nopw (%rax, %rax)")
401     }
402 
403     pub fn nop_7b(f: &mut fmt::Formatter, _: &inst::nop_7b) -> fmt::Result {
404         write!(f, "nopl (%rax)")
405     }
406 
407     pub fn nop_8b(f: &mut fmt::Formatter, _: &inst::nop_8b) -> fmt::Result {
408         write!(f, "nopl (%rax, %rax)")
409     }
410 
411     pub fn nop_9b(f: &mut fmt::Formatter, _: &inst::nop_9b) -> fmt::Result {
412         write!(f, "nopw (%rax, %rax)")
413     }
414 
415     pub fn xchgb_rm<R: Registers>(
416         f: &mut fmt::Formatter<'_>,
417         inst: &inst::xchgb_rm<R>,
418     ) -> fmt::Result {
419         let inst::xchgb_rm { r8, m8 } = inst;
420         xchg_rm::<R>(f, r8, m8, Size::Byte)
421     }
422 
423     pub fn xchgw_rm<R: Registers>(
424         f: &mut fmt::Formatter<'_>,
425         inst: &inst::xchgw_rm<R>,
426     ) -> fmt::Result {
427         let inst::xchgw_rm { r16, m16 } = inst;
428         xchg_rm::<R>(f, r16, m16, Size::Word)
429     }
430 
431     pub fn xchgl_rm<R: Registers>(
432         f: &mut fmt::Formatter<'_>,
433         inst: &inst::xchgl_rm<R>,
434     ) -> fmt::Result {
435         let inst::xchgl_rm { r32, m32 } = inst;
436         xchg_rm::<R>(f, r32, m32, Size::Doubleword)
437     }
438 
439     pub fn xchgq_rm<R: Registers>(
440         f: &mut fmt::Formatter<'_>,
441         inst: &inst::xchgq_rm<R>,
442     ) -> fmt::Result {
443         let inst::xchgq_rm { r64, m64 } = inst;
444         xchg_rm::<R>(f, r64, m64, Size::Quadword)
445     }
446 
447     /// Swap the order of printing (register first) to match Capstone.
448     fn xchg_rm<R: Registers>(
449         f: &mut fmt::Formatter<'_>,
450         reg: &Gpr<R::ReadWriteGpr>,
451         mem: &Amode<R::ReadGpr>,
452         size: Size,
453     ) -> fmt::Result {
454         let reg = reg.to_string(size);
455         let mem = mem.to_string();
456         let suffix = match size {
457             Size::Byte => "b",
458             Size::Word => "w",
459             Size::Doubleword => "l",
460             Size::Quadword => "q",
461         };
462         write!(f, "xchg{suffix} {reg}, {mem}")
463     }
464 
465     pub fn sarb_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::sarb_m1<R>) -> fmt::Result {
466         let inst::sarb_m1 { rm8 } = inst;
467         shift_m1::<R>(f, "sarb", rm8, Size::Byte)
468     }
469 
470     pub fn sarw_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::sarw_m1<R>) -> fmt::Result {
471         let inst::sarw_m1 { rm16 } = inst;
472         shift_m1::<R>(f, "sarw", rm16, Size::Word)
473     }
474 
475     pub fn sarl_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::sarl_m1<R>) -> fmt::Result {
476         let inst::sarl_m1 { rm32 } = inst;
477         shift_m1::<R>(f, "sarl", rm32, Size::Doubleword)
478     }
479 
480     pub fn sarq_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::sarq_m1<R>) -> fmt::Result {
481         let inst::sarq_m1 { rm64 } = inst;
482         shift_m1::<R>(f, "sarq", rm64, Size::Quadword)
483     }
484 
485     pub fn shlb_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::shlb_m1<R>) -> fmt::Result {
486         let inst::shlb_m1 { rm8 } = inst;
487         shift_m1::<R>(f, "shlb", rm8, Size::Byte)
488     }
489 
490     pub fn shlw_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::shlw_m1<R>) -> fmt::Result {
491         let inst::shlw_m1 { rm16 } = inst;
492         shift_m1::<R>(f, "shlw", rm16, Size::Word)
493     }
494 
495     pub fn shll_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::shll_m1<R>) -> fmt::Result {
496         let inst::shll_m1 { rm32 } = inst;
497         shift_m1::<R>(f, "shll", rm32, Size::Doubleword)
498     }
499 
500     pub fn shlq_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::shlq_m1<R>) -> fmt::Result {
501         let inst::shlq_m1 { rm64 } = inst;
502         shift_m1::<R>(f, "shlq", rm64, Size::Quadword)
503     }
504 
505     pub fn shrb_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::shrb_m1<R>) -> fmt::Result {
506         let inst::shrb_m1 { rm8 } = inst;
507         shift_m1::<R>(f, "shrb", rm8, Size::Byte)
508     }
509 
510     pub fn shrw_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::shrw_m1<R>) -> fmt::Result {
511         let inst::shrw_m1 { rm16 } = inst;
512         shift_m1::<R>(f, "shrw", rm16, Size::Word)
513     }
514 
515     pub fn shrl_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::shrl_m1<R>) -> fmt::Result {
516         let inst::shrl_m1 { rm32 } = inst;
517         shift_m1::<R>(f, "shrl", rm32, Size::Doubleword)
518     }
519 
520     pub fn shrq_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::shrq_m1<R>) -> fmt::Result {
521         let inst::shrq_m1 { rm64 } = inst;
522         shift_m1::<R>(f, "shrq", rm64, Size::Quadword)
523     }
524 
525     pub fn rorb_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::rorb_m1<R>) -> fmt::Result {
526         let inst::rorb_m1 { rm8 } = inst;
527         shift_m1::<R>(f, "rorb", rm8, Size::Byte)
528     }
529 
530     pub fn rorw_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::rorw_m1<R>) -> fmt::Result {
531         let inst::rorw_m1 { rm16 } = inst;
532         shift_m1::<R>(f, "rorw", rm16, Size::Word)
533     }
534 
535     pub fn rorl_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::rorl_m1<R>) -> fmt::Result {
536         let inst::rorl_m1 { rm32 } = inst;
537         shift_m1::<R>(f, "rorl", rm32, Size::Doubleword)
538     }
539 
540     pub fn rorq_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::rorq_m1<R>) -> fmt::Result {
541         let inst::rorq_m1 { rm64 } = inst;
542         shift_m1::<R>(f, "rorq", rm64, Size::Quadword)
543     }
544 
545     pub fn rolb_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::rolb_m1<R>) -> fmt::Result {
546         let inst::rolb_m1 { rm8 } = inst;
547         shift_m1::<R>(f, "rolb", rm8, Size::Byte)
548     }
549 
550     pub fn rolw_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::rolw_m1<R>) -> fmt::Result {
551         let inst::rolw_m1 { rm16 } = inst;
552         shift_m1::<R>(f, "rolw", rm16, Size::Word)
553     }
554 
555     pub fn roll_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::roll_m1<R>) -> fmt::Result {
556         let inst::roll_m1 { rm32 } = inst;
557         shift_m1::<R>(f, "roll", rm32, Size::Doubleword)
558     }
559 
560     pub fn rolq_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::rolq_m1<R>) -> fmt::Result {
561         let inst::rolq_m1 { rm64 } = inst;
562         shift_m1::<R>(f, "rolq", rm64, Size::Quadword)
563     }
564 
565     fn shift_m1<R: Registers>(
566         f: &mut fmt::Formatter<'_>,
567         mnemonic: &str,
568         rm: &GprMem<R::ReadWriteGpr, R::ReadGpr>,
569         size: Size,
570     ) -> fmt::Result {
571         let reg = rm.to_string(size);
572         match rm {
573             GprMem::Gpr(_) => write!(f, "{mnemonic} $1, {reg}"),
574             GprMem::Mem(_) => write!(f, "{mnemonic} {reg}"),
575         }
576     }
577 
578     pub fn jmpq_m<R: Registers>(f: &mut fmt::Formatter<'_>, jmp: &inst::jmpq_m<R>) -> fmt::Result {
579         let inst::jmpq_m { rm64 } = jmp;
580         let rm64 = rm64.to_string(Size::Quadword);
581         write!(f, "jmpq *{rm64}")
582     }
583 
584     pub fn jmp_d8(f: &mut fmt::Formatter<'_>, jmp: &inst::jmp_d8) -> fmt::Result {
585         let inst::jmp_d8 { imm8 } = jmp;
586         display_displacement(f, "jmp", i64::from(imm8.value()) + 2)
587     }
588 
589     pub fn jmp_d32(f: &mut fmt::Formatter<'_>, jmp: &inst::jmp_d32) -> fmt::Result {
590         let inst::jmp_d32 { imm32 } = jmp;
591         display_displacement(f, "jmp", i64::from(imm32.value()) + 5)
592     }
593 
594     macro_rules! jcc {
595         ($($mnemonic:tt = $j8:ident / $j32:ident;)*) => ($(
596             pub fn $j8(f: &mut fmt::Formatter<'_>, jmp: &inst::$j8) -> fmt::Result {
597                 let inst::$j8 { imm8 } = jmp;
598                 display_displacement(f, $mnemonic, i64::from(imm8.value()) + 2)
599             }
600 
601             pub fn $j32(f: &mut fmt::Formatter<'_>, jmp: &inst::$j32) -> fmt::Result {
602                 let inst::$j32 { imm32 } = jmp;
603                 display_displacement(f, $mnemonic, i64::from(imm32.value()) + 6)
604             }
605         )*)
606     }
607 
608     jcc! {
609         "ja" = ja_d8 / ja_d32;
610         "jae" = jae_d8 / jae_d32;
611         "jb" = jb_d8 / jb_d32;
612         "jbe" = jbe_d8 / jbe_d32;
613         "je" = je_d8 / je_d32;
614         "jg" = jg_d8 / jg_d32;
615         "jge" = jge_d8 / jge_d32;
616         "jl" = jl_d8 / jl_d32;
617         "jle" = jle_d8 / jle_d32;
618         "jne" = jne_d8 / jne_d32;
619         "jno" = jno_d8 / jno_d32;
620         "jnp" = jnp_d8 / jnp_d32;
621         "jns" = jns_d8 / jns_d32;
622         "jo" = jo_d8 / jo_d32;
623         "jp" = jp_d8 / jp_d32;
624         "js" = js_d8 / js_d32;
625     }
626 
627     fn display_displacement(
628         f: &mut fmt::Formatter<'_>,
629         mnemonic: &str,
630         displacement: i64,
631     ) -> fmt::Result {
632         if displacement >= 0 && displacement < 10 {
633             write!(f, "{mnemonic} {displacement}")
634         } else {
635             write!(f, "{mnemonic} {displacement:#x}")
636         }
637     }
638 }
639 
640 pub mod visit {
641     use crate::inst::*;
642     use crate::{Amode, Fixed, Gpr, GprMem, RegisterVisitor, Registers, gpr};
643 
644     pub fn mulxl_rvm<R: Registers>(mulx: &mut mulxl_rvm<R>, visitor: &mut impl RegisterVisitor<R>) {
645         visit_mulx(
646             &mut mulx.r32a,
647             &mut mulx.r32b,
648             &mut mulx.rm32,
649             &mut mulx.edx,
650             visitor,
651         )
652     }
653 
654     pub fn mulxq_rvm<R: Registers>(mulx: &mut mulxq_rvm<R>, visitor: &mut impl RegisterVisitor<R>) {
655         visit_mulx(
656             &mut mulx.r64a,
657             &mut mulx.r64b,
658             &mut mulx.rm64,
659             &mut mulx.rdx,
660             visitor,
661         )
662     }
663 
664     /// Both mulxl and mulxq have custom register allocator behavior where if the
665     /// two writable registers are the same then only one is flagged as writable.
666     /// That represents how when they're both the same only one register is written,
667     /// not both.
668     fn visit_mulx<R: Registers>(
669         ra: &mut Gpr<R::WriteGpr>,
670         rb: &mut Gpr<R::WriteGpr>,
671         src1: &mut GprMem<R::ReadGpr, R::ReadGpr>,
672         src2: &mut Fixed<R::ReadGpr, { gpr::enc::RDX }>,
673         visitor: &mut impl RegisterVisitor<R>,
674     ) {
675         if ra == rb {
676             visitor.write_gpr(ra.as_mut());
677             *rb = *ra;
678         } else {
679             visitor.write_gpr(ra.as_mut());
680             visitor.write_gpr(rb.as_mut());
681         }
682         visitor.read_gpr_mem(src1);
683         let enc = src2.expected_enc();
684         visitor.fixed_read_gpr(&mut src2.0, enc);
685     }
686 
687     pub fn lock_xaddb_mr<R: Registers>(
688         lock_xadd: &mut lock_xaddb_mr<R>,
689         visitor: &mut impl RegisterVisitor<R>,
690     ) {
691         let lock_xaddb_mr { r8, m8 } = lock_xadd;
692         lock_xadd_mr(r8, m8, visitor)
693     }
694 
695     pub fn lock_xaddw_mr<R: Registers>(
696         lock_xadd: &mut lock_xaddw_mr<R>,
697         visitor: &mut impl RegisterVisitor<R>,
698     ) {
699         let lock_xaddw_mr { r16, m16 } = lock_xadd;
700         lock_xadd_mr(r16, m16, visitor)
701     }
702 
703     pub fn lock_xaddl_mr<R: Registers>(
704         lock_xadd: &mut lock_xaddl_mr<R>,
705         visitor: &mut impl RegisterVisitor<R>,
706     ) {
707         let lock_xaddl_mr { r32, m32 } = lock_xadd;
708         lock_xadd_mr(r32, m32, visitor)
709     }
710 
711     pub fn lock_xaddq_mr<R: Registers>(
712         lock_xadd: &mut lock_xaddq_mr<R>,
713         visitor: &mut impl RegisterVisitor<R>,
714     ) {
715         let lock_xaddq_mr { r64, m64 } = lock_xadd;
716         lock_xadd_mr(r64, m64, visitor)
717     }
718 
719     /// Intel says the memory operand comes first, but regalloc requires the
720     /// register operand comes first, so the custom visit implementation here
721     /// resolves that.
722     fn lock_xadd_mr<R: Registers>(
723         reg: &mut Gpr<R::ReadWriteGpr>,
724         mem: &mut Amode<R::ReadGpr>,
725         visitor: &mut impl RegisterVisitor<R>,
726     ) {
727         visitor.read_write_gpr(reg.as_mut());
728         visitor.read_amode(mem);
729     }
730 }
731