Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/assembler-x64/src/custom.rs
3068 views
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 alloc::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 alloc::string::ToString;
195
use core::fmt;
196
197
pub fn callq_d(f: &mut fmt::Formatter, inst: &inst::callq_d) -> fmt::Result {
198
let inst::callq_d { imm32 } = inst;
199
display_displacement(f, "callq", i64::from(imm32.value()) + 5)
200
}
201
202
pub fn callq_m<R: Registers>(f: &mut fmt::Formatter, inst: &inst::callq_m<R>) -> fmt::Result {
203
let inst::callq_m { rm64 } = inst;
204
let op = rm64.to_string(Size::Quadword);
205
write!(f, "callq *{op}")
206
}
207
208
/// Return the predicate string used for the immediate of a `cmp*`
209
/// instruction.
210
fn pred_as_str(imm: u8) -> &'static str {
211
match imm {
212
0 => "eq",
213
1 => "lt",
214
2 => "le",
215
3 => "unord",
216
4 => "neq",
217
5 => "nlt",
218
6 => "nle",
219
7 => "ord",
220
_ => panic!("not a valid predicate for `cmp*`"),
221
}
222
}
223
224
pub fn cmpss_a<R: Registers>(f: &mut fmt::Formatter, inst: &inst::cmpss_a<R>) -> fmt::Result {
225
let xmm1 = inst.xmm1.to_string();
226
let xmm_m32 = inst.xmm_m32.to_string();
227
let pred = inst.imm8.value();
228
if pred > 7 {
229
let imm8 = inst.imm8.to_string();
230
write!(f, "cmpss {imm8}, {xmm_m32}, {xmm1}")
231
} else {
232
write!(f, "cmp{}ss {xmm_m32}, {xmm1}", pred_as_str(pred))
233
}
234
}
235
236
pub fn cmpsd_a<R: Registers>(f: &mut fmt::Formatter, inst: &inst::cmpsd_a<R>) -> fmt::Result {
237
let xmm1 = inst.xmm1.to_string();
238
let xmm_m64 = inst.xmm_m64.to_string();
239
let pred = inst.imm8.value();
240
if pred > 7 {
241
let imm8 = inst.imm8.to_string();
242
write!(f, "cmpsd {imm8}, {xmm_m64}, {xmm1}")
243
} else {
244
write!(f, "cmp{}sd {xmm_m64}, {xmm1}", pred_as_str(pred))
245
}
246
}
247
248
pub fn cmpps_a<R: Registers>(f: &mut fmt::Formatter, inst: &inst::cmpps_a<R>) -> fmt::Result {
249
let xmm1 = inst.xmm1.to_string();
250
let xmm_m128 = inst.xmm_m128.to_string();
251
let pred = inst.imm8.value();
252
if pred > 7 {
253
let imm8 = inst.imm8.to_string();
254
write!(f, "cmpps {imm8}, {xmm_m128}, {xmm1}")
255
} else {
256
write!(f, "cmp{}ps {xmm_m128}, {xmm1}", pred_as_str(pred))
257
}
258
}
259
260
pub fn cmppd_a<R: Registers>(f: &mut fmt::Formatter, inst: &inst::cmppd_a<R>) -> fmt::Result {
261
let xmm1 = inst.xmm1.to_string();
262
let xmm_m128 = inst.xmm_m128.to_string();
263
let pred = inst.imm8.value();
264
if pred > 7 {
265
let imm8 = inst.imm8.to_string();
266
write!(f, "cmppd {imm8}, {xmm_m128}, {xmm1}")
267
} else {
268
write!(f, "cmp{}pd {xmm_m128}, {xmm1}", pred_as_str(pred))
269
}
270
}
271
272
/// Return the predicate string used for the immediate of a `vcmp*`
273
/// instruction; this is a more complex version of `pred_as_str`.
274
fn vex_pred_as_str(imm: u8) -> &'static str {
275
match imm {
276
0x0 => "eq",
277
0x1 => "lt",
278
0x2 => "le",
279
0x3 => "unord",
280
0x4 => "neq",
281
0x5 => "nlt",
282
0x6 => "nle",
283
0x7 => "ord",
284
0x8 => "eq_uq",
285
0x9 => "nge",
286
0xa => "ngt",
287
0xb => "false",
288
0xc => "neq_oq",
289
0xd => "ge",
290
0xe => "gt",
291
0xf => "true",
292
0x10 => "eq_os",
293
0x11 => "lt_oq",
294
0x12 => "le_oq",
295
0x13 => "unord_s",
296
0x14 => "neq_us",
297
0x15 => "nlt_uq",
298
0x16 => "nle_uq",
299
0x17 => "ord_s",
300
0x18 => "eq_us",
301
0x19 => "nge_uq",
302
0x1a => "ngt_uq",
303
0x1b => "false_os",
304
0x1c => "neq_os",
305
0x1d => "ge_oq",
306
0x1e => "gt_oq",
307
0x1f => "true_us",
308
_ => panic!("not a valid predicate for `cmp*`"),
309
}
310
}
311
312
pub fn vcmpss_b<R: Registers>(f: &mut fmt::Formatter, inst: &inst::vcmpss_b<R>) -> fmt::Result {
313
let xmm1 = inst.xmm1.to_string();
314
let xmm2 = inst.xmm2.to_string();
315
let xmm_m32 = inst.xmm_m32.to_string();
316
let pred = inst.imm8.value();
317
if pred > 0x1f {
318
let imm8 = inst.imm8.to_string();
319
write!(f, "vcmpss {imm8}, {xmm_m32}, {xmm2}, {xmm1}")
320
} else {
321
write!(
322
f,
323
"vcmp{}ss {xmm_m32}, {xmm2}, {xmm1}",
324
vex_pred_as_str(pred)
325
)
326
}
327
}
328
329
pub fn vcmpsd_b<R: Registers>(f: &mut fmt::Formatter, inst: &inst::vcmpsd_b<R>) -> fmt::Result {
330
let xmm1 = inst.xmm1.to_string();
331
let xmm2 = inst.xmm2.to_string();
332
let xmm_m64 = inst.xmm_m64.to_string();
333
let pred = inst.imm8.value();
334
if pred > 0x1f {
335
let imm8 = inst.imm8.to_string();
336
write!(f, "vcmpsd {imm8}, {xmm_m64}, {xmm2}, {xmm1}")
337
} else {
338
write!(
339
f,
340
"vcmp{}sd {xmm_m64}, {xmm2}, {xmm1}",
341
vex_pred_as_str(pred)
342
)
343
}
344
}
345
346
pub fn vcmpps_b<R: Registers>(f: &mut fmt::Formatter, inst: &inst::vcmpps_b<R>) -> fmt::Result {
347
let xmm1 = inst.xmm1.to_string();
348
let xmm2 = inst.xmm2.to_string();
349
let xmm_m128 = inst.xmm_m128.to_string();
350
let pred = inst.imm8.value();
351
if pred > 0x1f {
352
let imm8 = inst.imm8.to_string();
353
write!(f, "vcmpps {imm8}, {xmm_m128}, {xmm2}, {xmm1}")
354
} else {
355
write!(
356
f,
357
"vcmp{}ps {xmm_m128}, {xmm2}, {xmm1}",
358
vex_pred_as_str(pred)
359
)
360
}
361
}
362
363
pub fn vcmppd_b<R: Registers>(f: &mut fmt::Formatter, inst: &inst::vcmppd_b<R>) -> fmt::Result {
364
let xmm1 = inst.xmm1.to_string();
365
let xmm2 = inst.xmm2.to_string();
366
let xmm_m128 = inst.xmm_m128.to_string();
367
let pred = inst.imm8.value();
368
if pred > 0x1f {
369
let imm8 = inst.imm8.to_string();
370
write!(f, "vcmppd {imm8}, {xmm_m128}, {xmm2}, {xmm1}")
371
} else {
372
write!(
373
f,
374
"vcmp{}pd {xmm_m128}, {xmm2}, {xmm1}",
375
vex_pred_as_str(pred)
376
)
377
}
378
}
379
380
pub fn nop_1b(f: &mut fmt::Formatter, _: &inst::nop_1b) -> fmt::Result {
381
write!(f, "nop")
382
}
383
384
pub fn nop_2b(f: &mut fmt::Formatter, _: &inst::nop_2b) -> fmt::Result {
385
write!(f, "nop")
386
}
387
388
pub fn nop_3b(f: &mut fmt::Formatter, _: &inst::nop_3b) -> fmt::Result {
389
write!(f, "nopl (%rax)")
390
}
391
392
pub fn nop_4b(f: &mut fmt::Formatter, _: &inst::nop_4b) -> fmt::Result {
393
write!(f, "nopl (%rax)")
394
}
395
396
pub fn nop_5b(f: &mut fmt::Formatter, _: &inst::nop_5b) -> fmt::Result {
397
write!(f, "nopl (%rax, %rax)")
398
}
399
400
pub fn nop_6b(f: &mut fmt::Formatter, _: &inst::nop_6b) -> fmt::Result {
401
write!(f, "nopw (%rax, %rax)")
402
}
403
404
pub fn nop_7b(f: &mut fmt::Formatter, _: &inst::nop_7b) -> fmt::Result {
405
write!(f, "nopl (%rax)")
406
}
407
408
pub fn nop_8b(f: &mut fmt::Formatter, _: &inst::nop_8b) -> fmt::Result {
409
write!(f, "nopl (%rax, %rax)")
410
}
411
412
pub fn nop_9b(f: &mut fmt::Formatter, _: &inst::nop_9b) -> fmt::Result {
413
write!(f, "nopw (%rax, %rax)")
414
}
415
416
pub fn xchgb_rm<R: Registers>(
417
f: &mut fmt::Formatter<'_>,
418
inst: &inst::xchgb_rm<R>,
419
) -> fmt::Result {
420
let inst::xchgb_rm { r8, m8 } = inst;
421
xchg_rm::<R>(f, r8, m8, Size::Byte)
422
}
423
424
pub fn xchgw_rm<R: Registers>(
425
f: &mut fmt::Formatter<'_>,
426
inst: &inst::xchgw_rm<R>,
427
) -> fmt::Result {
428
let inst::xchgw_rm { r16, m16 } = inst;
429
xchg_rm::<R>(f, r16, m16, Size::Word)
430
}
431
432
pub fn xchgl_rm<R: Registers>(
433
f: &mut fmt::Formatter<'_>,
434
inst: &inst::xchgl_rm<R>,
435
) -> fmt::Result {
436
let inst::xchgl_rm { r32, m32 } = inst;
437
xchg_rm::<R>(f, r32, m32, Size::Doubleword)
438
}
439
440
pub fn xchgq_rm<R: Registers>(
441
f: &mut fmt::Formatter<'_>,
442
inst: &inst::xchgq_rm<R>,
443
) -> fmt::Result {
444
let inst::xchgq_rm { r64, m64 } = inst;
445
xchg_rm::<R>(f, r64, m64, Size::Quadword)
446
}
447
448
/// Swap the order of printing (register first) to match Capstone.
449
fn xchg_rm<R: Registers>(
450
f: &mut fmt::Formatter<'_>,
451
reg: &Gpr<R::ReadWriteGpr>,
452
mem: &Amode<R::ReadGpr>,
453
size: Size,
454
) -> fmt::Result {
455
let reg = reg.to_string(size);
456
let mem = mem.to_string();
457
let suffix = match size {
458
Size::Byte => "b",
459
Size::Word => "w",
460
Size::Doubleword => "l",
461
Size::Quadword => "q",
462
};
463
write!(f, "xchg{suffix} {reg}, {mem}")
464
}
465
466
pub fn sarb_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::sarb_m1<R>) -> fmt::Result {
467
let inst::sarb_m1 { rm8 } = inst;
468
shift_m1::<R>(f, "sarb", rm8, Size::Byte)
469
}
470
471
pub fn sarw_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::sarw_m1<R>) -> fmt::Result {
472
let inst::sarw_m1 { rm16 } = inst;
473
shift_m1::<R>(f, "sarw", rm16, Size::Word)
474
}
475
476
pub fn sarl_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::sarl_m1<R>) -> fmt::Result {
477
let inst::sarl_m1 { rm32 } = inst;
478
shift_m1::<R>(f, "sarl", rm32, Size::Doubleword)
479
}
480
481
pub fn sarq_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::sarq_m1<R>) -> fmt::Result {
482
let inst::sarq_m1 { rm64 } = inst;
483
shift_m1::<R>(f, "sarq", rm64, Size::Quadword)
484
}
485
486
pub fn shlb_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::shlb_m1<R>) -> fmt::Result {
487
let inst::shlb_m1 { rm8 } = inst;
488
shift_m1::<R>(f, "shlb", rm8, Size::Byte)
489
}
490
491
pub fn shlw_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::shlw_m1<R>) -> fmt::Result {
492
let inst::shlw_m1 { rm16 } = inst;
493
shift_m1::<R>(f, "shlw", rm16, Size::Word)
494
}
495
496
pub fn shll_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::shll_m1<R>) -> fmt::Result {
497
let inst::shll_m1 { rm32 } = inst;
498
shift_m1::<R>(f, "shll", rm32, Size::Doubleword)
499
}
500
501
pub fn shlq_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::shlq_m1<R>) -> fmt::Result {
502
let inst::shlq_m1 { rm64 } = inst;
503
shift_m1::<R>(f, "shlq", rm64, Size::Quadword)
504
}
505
506
pub fn shrb_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::shrb_m1<R>) -> fmt::Result {
507
let inst::shrb_m1 { rm8 } = inst;
508
shift_m1::<R>(f, "shrb", rm8, Size::Byte)
509
}
510
511
pub fn shrw_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::shrw_m1<R>) -> fmt::Result {
512
let inst::shrw_m1 { rm16 } = inst;
513
shift_m1::<R>(f, "shrw", rm16, Size::Word)
514
}
515
516
pub fn shrl_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::shrl_m1<R>) -> fmt::Result {
517
let inst::shrl_m1 { rm32 } = inst;
518
shift_m1::<R>(f, "shrl", rm32, Size::Doubleword)
519
}
520
521
pub fn shrq_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::shrq_m1<R>) -> fmt::Result {
522
let inst::shrq_m1 { rm64 } = inst;
523
shift_m1::<R>(f, "shrq", rm64, Size::Quadword)
524
}
525
526
pub fn rorb_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::rorb_m1<R>) -> fmt::Result {
527
let inst::rorb_m1 { rm8 } = inst;
528
shift_m1::<R>(f, "rorb", rm8, Size::Byte)
529
}
530
531
pub fn rorw_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::rorw_m1<R>) -> fmt::Result {
532
let inst::rorw_m1 { rm16 } = inst;
533
shift_m1::<R>(f, "rorw", rm16, Size::Word)
534
}
535
536
pub fn rorl_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::rorl_m1<R>) -> fmt::Result {
537
let inst::rorl_m1 { rm32 } = inst;
538
shift_m1::<R>(f, "rorl", rm32, Size::Doubleword)
539
}
540
541
pub fn rorq_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::rorq_m1<R>) -> fmt::Result {
542
let inst::rorq_m1 { rm64 } = inst;
543
shift_m1::<R>(f, "rorq", rm64, Size::Quadword)
544
}
545
546
pub fn rolb_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::rolb_m1<R>) -> fmt::Result {
547
let inst::rolb_m1 { rm8 } = inst;
548
shift_m1::<R>(f, "rolb", rm8, Size::Byte)
549
}
550
551
pub fn rolw_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::rolw_m1<R>) -> fmt::Result {
552
let inst::rolw_m1 { rm16 } = inst;
553
shift_m1::<R>(f, "rolw", rm16, Size::Word)
554
}
555
556
pub fn roll_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::roll_m1<R>) -> fmt::Result {
557
let inst::roll_m1 { rm32 } = inst;
558
shift_m1::<R>(f, "roll", rm32, Size::Doubleword)
559
}
560
561
pub fn rolq_m1<R: Registers>(f: &mut fmt::Formatter, inst: &inst::rolq_m1<R>) -> fmt::Result {
562
let inst::rolq_m1 { rm64 } = inst;
563
shift_m1::<R>(f, "rolq", rm64, Size::Quadword)
564
}
565
566
fn shift_m1<R: Registers>(
567
f: &mut fmt::Formatter<'_>,
568
mnemonic: &str,
569
rm: &GprMem<R::ReadWriteGpr, R::ReadGpr>,
570
size: Size,
571
) -> fmt::Result {
572
let reg = rm.to_string(size);
573
match rm {
574
GprMem::Gpr(_) => write!(f, "{mnemonic} $1, {reg}"),
575
GprMem::Mem(_) => write!(f, "{mnemonic} {reg}"),
576
}
577
}
578
579
pub fn jmpq_m<R: Registers>(f: &mut fmt::Formatter<'_>, jmp: &inst::jmpq_m<R>) -> fmt::Result {
580
let inst::jmpq_m { rm64 } = jmp;
581
let rm64 = rm64.to_string(Size::Quadword);
582
write!(f, "jmpq *{rm64}")
583
}
584
585
pub fn jmp_d8(f: &mut fmt::Formatter<'_>, jmp: &inst::jmp_d8) -> fmt::Result {
586
let inst::jmp_d8 { imm8 } = jmp;
587
display_displacement(f, "jmp", i64::from(imm8.value()) + 2)
588
}
589
590
pub fn jmp_d32(f: &mut fmt::Formatter<'_>, jmp: &inst::jmp_d32) -> fmt::Result {
591
let inst::jmp_d32 { imm32 } = jmp;
592
display_displacement(f, "jmp", i64::from(imm32.value()) + 5)
593
}
594
595
macro_rules! jcc {
596
($($mnemonic:tt = $j8:ident / $j32:ident;)*) => ($(
597
pub fn $j8(f: &mut fmt::Formatter<'_>, jmp: &inst::$j8) -> fmt::Result {
598
let inst::$j8 { imm8 } = jmp;
599
display_displacement(f, $mnemonic, i64::from(imm8.value()) + 2)
600
}
601
602
pub fn $j32(f: &mut fmt::Formatter<'_>, jmp: &inst::$j32) -> fmt::Result {
603
let inst::$j32 { imm32 } = jmp;
604
display_displacement(f, $mnemonic, i64::from(imm32.value()) + 6)
605
}
606
)*)
607
}
608
609
jcc! {
610
"ja" = ja_d8 / ja_d32;
611
"jae" = jae_d8 / jae_d32;
612
"jb" = jb_d8 / jb_d32;
613
"jbe" = jbe_d8 / jbe_d32;
614
"je" = je_d8 / je_d32;
615
"jg" = jg_d8 / jg_d32;
616
"jge" = jge_d8 / jge_d32;
617
"jl" = jl_d8 / jl_d32;
618
"jle" = jle_d8 / jle_d32;
619
"jne" = jne_d8 / jne_d32;
620
"jno" = jno_d8 / jno_d32;
621
"jnp" = jnp_d8 / jnp_d32;
622
"jns" = jns_d8 / jns_d32;
623
"jo" = jo_d8 / jo_d32;
624
"jp" = jp_d8 / jp_d32;
625
"js" = js_d8 / js_d32;
626
}
627
628
fn display_displacement(
629
f: &mut fmt::Formatter<'_>,
630
mnemonic: &str,
631
displacement: i64,
632
) -> fmt::Result {
633
if displacement >= 0 && displacement < 10 {
634
write!(f, "{mnemonic} {displacement}")
635
} else {
636
write!(f, "{mnemonic} {displacement:#x}")
637
}
638
}
639
}
640
641
pub mod visit {
642
use crate::inst::*;
643
use crate::{Amode, Fixed, Gpr, GprMem, RegisterVisitor, Registers, gpr};
644
645
pub fn mulxl_rvm<R: Registers>(mulx: &mut mulxl_rvm<R>, visitor: &mut impl RegisterVisitor<R>) {
646
visit_mulx(
647
&mut mulx.r32a,
648
&mut mulx.r32b,
649
&mut mulx.rm32,
650
&mut mulx.edx,
651
visitor,
652
)
653
}
654
655
pub fn mulxq_rvm<R: Registers>(mulx: &mut mulxq_rvm<R>, visitor: &mut impl RegisterVisitor<R>) {
656
visit_mulx(
657
&mut mulx.r64a,
658
&mut mulx.r64b,
659
&mut mulx.rm64,
660
&mut mulx.rdx,
661
visitor,
662
)
663
}
664
665
/// Both mulxl and mulxq have custom register allocator behavior where if the
666
/// two writable registers are the same then only one is flagged as writable.
667
/// That represents how when they're both the same only one register is written,
668
/// not both.
669
fn visit_mulx<R: Registers>(
670
ra: &mut Gpr<R::WriteGpr>,
671
rb: &mut Gpr<R::WriteGpr>,
672
src1: &mut GprMem<R::ReadGpr, R::ReadGpr>,
673
src2: &mut Fixed<R::ReadGpr, { gpr::enc::RDX }>,
674
visitor: &mut impl RegisterVisitor<R>,
675
) {
676
if ra == rb {
677
visitor.write_gpr(ra.as_mut());
678
*rb = *ra;
679
} else {
680
visitor.write_gpr(ra.as_mut());
681
visitor.write_gpr(rb.as_mut());
682
}
683
visitor.read_gpr_mem(src1);
684
let enc = src2.expected_enc();
685
visitor.fixed_read_gpr(&mut src2.0, enc);
686
}
687
688
pub fn lock_xaddb_mr<R: Registers>(
689
lock_xadd: &mut lock_xaddb_mr<R>,
690
visitor: &mut impl RegisterVisitor<R>,
691
) {
692
let lock_xaddb_mr { r8, m8 } = lock_xadd;
693
lock_xadd_mr(r8, m8, visitor)
694
}
695
696
pub fn lock_xaddw_mr<R: Registers>(
697
lock_xadd: &mut lock_xaddw_mr<R>,
698
visitor: &mut impl RegisterVisitor<R>,
699
) {
700
let lock_xaddw_mr { r16, m16 } = lock_xadd;
701
lock_xadd_mr(r16, m16, visitor)
702
}
703
704
pub fn lock_xaddl_mr<R: Registers>(
705
lock_xadd: &mut lock_xaddl_mr<R>,
706
visitor: &mut impl RegisterVisitor<R>,
707
) {
708
let lock_xaddl_mr { r32, m32 } = lock_xadd;
709
lock_xadd_mr(r32, m32, visitor)
710
}
711
712
pub fn lock_xaddq_mr<R: Registers>(
713
lock_xadd: &mut lock_xaddq_mr<R>,
714
visitor: &mut impl RegisterVisitor<R>,
715
) {
716
let lock_xaddq_mr { r64, m64 } = lock_xadd;
717
lock_xadd_mr(r64, m64, visitor)
718
}
719
720
/// Intel says the memory operand comes first, but regalloc requires the
721
/// register operand comes first, so the custom visit implementation here
722
/// resolves that.
723
fn lock_xadd_mr<R: Registers>(
724
reg: &mut Gpr<R::ReadWriteGpr>,
725
mem: &mut Amode<R::ReadGpr>,
726
visitor: &mut impl RegisterVisitor<R>,
727
) {
728
visitor.read_write_gpr(reg.as_mut());
729
visitor.read_amode(mem);
730
}
731
}
732
733