cranelift_assembler_x64/
custom.rs

1pub 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
75pub 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
191pub 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
640pub 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}