1 pub mod encode {
2     use crate::{CodeSink, KnownOffsetTable, inst};
3 
4     /// `NOP`
5     pub fn nop_1b(_: &inst::nop_1b, buf: &mut impl CodeSink, _: &impl KnownOffsetTable) {
6         buf.put1(0x90);
7     }
8 
9     /// `66 NOP`
10     pub fn nop_2b(_: &inst::nop_2b, buf: &mut impl CodeSink, _: &impl KnownOffsetTable) {
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, _: &impl KnownOffsetTable) {
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, _: &impl KnownOffsetTable) {
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, _: &impl KnownOffsetTable) {
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, _: &impl KnownOffsetTable) {
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, _: &impl KnownOffsetTable) {
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, _: &impl KnownOffsetTable) {
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, _: &impl KnownOffsetTable) {
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, Registers, Size};
194     use std::fmt;
195 
196     pub fn pseudo_op(imm: u8) -> &'static str {
197         match imm {
198             0 => "eq",
199             1 => "lt",
200             2 => "le",
201             3 => "unord",
202             4 => "neq",
203             5 => "nlt",
204             6 => "nle",
205             7 => "ord",
206             _ => panic!("not a valid immediate for pseudo op"),
207         }
208     }
209 
210     pub fn cmpps_a<R: Registers>(f: &mut fmt::Formatter, inst: &inst::cmpps_a<R>) -> fmt::Result {
211         let xmm1 = inst.xmm1.to_string();
212         let xmm_m128 = inst.xmm_m128.to_string();
213         let imm8 = inst.imm8.to_string();
214         if inst.imm8.value() > 7 {
215             return write!(f, "{} {imm8}, {xmm_m128}, {xmm1}", inst.mnemonic());
216         }
217         let name = format!("cmp{}ps", pseudo_op(inst.imm8.value()));
218         write!(f, "{name} {xmm_m128}, {xmm1}")
219     }
220 
221     pub fn cmpss_a<R: Registers>(f: &mut fmt::Formatter, inst: &inst::cmpss_a<R>) -> fmt::Result {
222         let xmm1 = inst.xmm1.to_string();
223         let xmm_m32 = inst.xmm_m32.to_string();
224         let imm8 = inst.imm8.to_string();
225         if inst.imm8.value() > 7 {
226             return write!(f, "{} {imm8}, {xmm_m32}, {xmm1}", inst.mnemonic());
227         }
228         let name = format!("cmp{}ss", pseudo_op(inst.imm8.value()));
229         write!(f, "{name} {xmm_m32}, {xmm1}")
230     }
231 
232     pub fn cmpsd_a<R: Registers>(f: &mut fmt::Formatter, inst: &inst::cmpsd_a<R>) -> fmt::Result {
233         let xmm1 = inst.xmm1.to_string();
234         let xmm_m64 = inst.xmm_m64.to_string();
235         let imm8 = inst.imm8.to_string();
236         if inst.imm8.value() > 7 {
237             return write!(f, "{} {imm8}, {xmm_m64}, {xmm1}", inst.mnemonic());
238         }
239         let name = format!("cmp{}sd", pseudo_op(inst.imm8.value()));
240         write!(f, "{name} {xmm_m64}, {xmm1}")
241     }
242 
243     pub fn cmppd_a<R: Registers>(f: &mut fmt::Formatter, inst: &inst::cmppd_a<R>) -> fmt::Result {
244         let xmm1 = inst.xmm1.to_string();
245         let xmm_m128 = inst.xmm_m128.to_string();
246         let imm8 = inst.imm8.to_string();
247         if inst.imm8.value() > 7 {
248             return write!(f, "{} {imm8}, {xmm_m128}, {xmm1}", inst.mnemonic());
249         }
250         let name = format!("cmp{}pd", pseudo_op(inst.imm8.value()));
251         write!(f, "{name} {xmm_m128}, {xmm1}")
252     }
253 
254     pub fn nop_1b(f: &mut fmt::Formatter, _: &inst::nop_1b) -> fmt::Result {
255         write!(f, "nop")
256     }
257 
258     pub fn nop_2b(f: &mut fmt::Formatter, _: &inst::nop_2b) -> fmt::Result {
259         write!(f, "nop")
260     }
261 
262     pub fn nop_3b(f: &mut fmt::Formatter, _: &inst::nop_3b) -> fmt::Result {
263         write!(f, "nopl (%rax)")
264     }
265 
266     pub fn nop_4b(f: &mut fmt::Formatter, _: &inst::nop_4b) -> fmt::Result {
267         write!(f, "nopl (%rax)")
268     }
269 
270     pub fn nop_5b(f: &mut fmt::Formatter, _: &inst::nop_5b) -> fmt::Result {
271         write!(f, "nopl (%rax, %rax)")
272     }
273 
274     pub fn nop_6b(f: &mut fmt::Formatter, _: &inst::nop_6b) -> fmt::Result {
275         write!(f, "nopw (%rax, %rax)")
276     }
277 
278     pub fn nop_7b(f: &mut fmt::Formatter, _: &inst::nop_7b) -> fmt::Result {
279         write!(f, "nopl (%rax)")
280     }
281 
282     pub fn nop_8b(f: &mut fmt::Formatter, _: &inst::nop_8b) -> fmt::Result {
283         write!(f, "nopl (%rax, %rax)")
284     }
285 
286     pub fn nop_9b(f: &mut fmt::Formatter, _: &inst::nop_9b) -> fmt::Result {
287         write!(f, "nopw (%rax, %rax)")
288     }
289 
290     pub fn xchgb_rm<R: Registers>(
291         f: &mut fmt::Formatter<'_>,
292         inst: &inst::xchgb_rm<R>,
293     ) -> fmt::Result {
294         let inst::xchgb_rm { r8, m8 } = inst;
295         xchg_rm::<R>(f, r8, m8, Size::Byte)
296     }
297 
298     pub fn xchgw_rm<R: Registers>(
299         f: &mut fmt::Formatter<'_>,
300         inst: &inst::xchgw_rm<R>,
301     ) -> fmt::Result {
302         let inst::xchgw_rm { r16, m16 } = inst;
303         xchg_rm::<R>(f, r16, m16, Size::Word)
304     }
305 
306     pub fn xchgl_rm<R: Registers>(
307         f: &mut fmt::Formatter<'_>,
308         inst: &inst::xchgl_rm<R>,
309     ) -> fmt::Result {
310         let inst::xchgl_rm { r32, m32 } = inst;
311         xchg_rm::<R>(f, r32, m32, Size::Doubleword)
312     }
313 
314     pub fn xchgq_rm<R: Registers>(
315         f: &mut fmt::Formatter<'_>,
316         inst: &inst::xchgq_rm<R>,
317     ) -> fmt::Result {
318         let inst::xchgq_rm { r64, m64 } = inst;
319         xchg_rm::<R>(f, r64, m64, Size::Quadword)
320     }
321 
322     /// Swap the order of printing (register first) to match Capstone.
323     fn xchg_rm<R: Registers>(
324         f: &mut fmt::Formatter<'_>,
325         reg: &Gpr<R::ReadWriteGpr>,
326         mem: &Amode<R::ReadGpr>,
327         size: Size,
328     ) -> fmt::Result {
329         let reg = reg.to_string(size);
330         let mem = mem.to_string();
331         let suffix = match size {
332             Size::Byte => "b",
333             Size::Word => "w",
334             Size::Doubleword => "l",
335             Size::Quadword => "q",
336         };
337         write!(f, "xchg{suffix} {reg}, {mem}")
338     }
339 }
340 
341 pub mod visit {
342     use crate::inst::*;
343     use crate::{Amode, Fixed, Gpr, GprMem, RegisterVisitor, Registers, gpr};
344 
345     pub fn mulxl_rvm<R: Registers>(mulx: &mut mulxl_rvm<R>, visitor: &mut impl RegisterVisitor<R>) {
346         visit_mulx(
347             &mut mulx.r32a,
348             &mut mulx.r32b,
349             &mut mulx.rm32,
350             &mut mulx.edx,
351             visitor,
352         )
353     }
354 
355     pub fn mulxq_rvm<R: Registers>(mulx: &mut mulxq_rvm<R>, visitor: &mut impl RegisterVisitor<R>) {
356         visit_mulx(
357             &mut mulx.r64a,
358             &mut mulx.r64b,
359             &mut mulx.rm64,
360             &mut mulx.rdx,
361             visitor,
362         )
363     }
364 
365     /// Both mulxl and mulxq have custom register allocator behavior where if the
366     /// two writable registers are the same then only one is flagged as writable.
367     /// That represents how when they're both the same only one register is written,
368     /// not both.
369     fn visit_mulx<R: Registers>(
370         ra: &mut Gpr<R::WriteGpr>,
371         rb: &mut Gpr<R::WriteGpr>,
372         src1: &mut GprMem<R::ReadGpr, R::ReadGpr>,
373         src2: &mut Fixed<R::ReadGpr, { gpr::enc::RDX }>,
374         visitor: &mut impl RegisterVisitor<R>,
375     ) {
376         if ra == rb {
377             visitor.write_gpr(ra.as_mut());
378             *rb = *ra;
379         } else {
380             visitor.write_gpr(ra.as_mut());
381             visitor.write_gpr(rb.as_mut());
382         }
383         visitor.read_gpr_mem(src1);
384         let enc = src2.expected_enc();
385         visitor.fixed_read_gpr(&mut src2.0, enc);
386     }
387 
388     pub fn lock_xaddb_mr<R: Registers>(
389         lock_xadd: &mut lock_xaddb_mr<R>,
390         visitor: &mut impl RegisterVisitor<R>,
391     ) {
392         let lock_xaddb_mr { r8, m8 } = lock_xadd;
393         lock_xadd_mr(r8, m8, visitor)
394     }
395 
396     pub fn lock_xaddw_mr<R: Registers>(
397         lock_xadd: &mut lock_xaddw_mr<R>,
398         visitor: &mut impl RegisterVisitor<R>,
399     ) {
400         let lock_xaddw_mr { r16, m16 } = lock_xadd;
401         lock_xadd_mr(r16, m16, visitor)
402     }
403 
404     pub fn lock_xaddl_mr<R: Registers>(
405         lock_xadd: &mut lock_xaddl_mr<R>,
406         visitor: &mut impl RegisterVisitor<R>,
407     ) {
408         let lock_xaddl_mr { r32, m32 } = lock_xadd;
409         lock_xadd_mr(r32, m32, visitor)
410     }
411 
412     pub fn lock_xaddq_mr<R: Registers>(
413         lock_xadd: &mut lock_xaddq_mr<R>,
414         visitor: &mut impl RegisterVisitor<R>,
415     ) {
416         let lock_xaddq_mr { r64, m64 } = lock_xadd;
417         lock_xadd_mr(r64, m64, visitor)
418     }
419 
420     /// Intel says the memory operand comes first, but regalloc requires the
421     /// register operand comes first, so the custom visit implementation here
422     /// resolves that.
423     fn lock_xadd_mr<R: Registers>(
424         reg: &mut Gpr<R::ReadWriteGpr>,
425         mem: &mut Amode<R::ReadGpr>,
426         visitor: &mut impl RegisterVisitor<R>,
427     ) {
428         visitor.read_write_gpr(reg.as_mut());
429         visitor.read_amode(mem);
430     }
431 }
432