Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/assembler-x64/meta/src/generate/format.rs
1693 views
1
//! Generate format-related Rust code; this also includes generation of encoding
2
//! Rust code.
3
use super::{Formatter, fmtln};
4
use crate::dsl;
5
6
/// Different methods of emitting a ModR/M operand and encoding various bits and
7
/// pieces of information into it. The REX/VEX formats plus the operand kinds
8
/// dictate how exactly each instruction uses this, if at all.
9
#[derive(Copy, Clone)]
10
enum ModRmStyle {
11
/// This instruction does not use a ModR/M byte.
12
None,
13
14
/// The R/M bits are encoded with `rm` which is a `Gpr` or `Xmm` (it does
15
/// not have a "mem" possibility), and the Reg/Opcode bits are encoded
16
/// with `reg`.
17
Reg { reg: ModRmReg, rm: dsl::Location },
18
19
/// The R/M bits are encoded with `rm` which is a `GprMem` or `XmmMem`, and
20
/// the Reg/Opcode bits are encoded with `reg`.
21
RegMem {
22
reg: ModRmReg,
23
rm: dsl::Location,
24
evex_scaling: Option<i8>,
25
},
26
27
/// Same as `RegMem` above except that this is also used for VEX-encoded
28
/// instructios with "/is4" which indicates that the 4th register operand
29
/// is encoded in a byte after the ModR/M byte.
30
RegMemIs4 {
31
reg: ModRmReg,
32
rm: dsl::Location,
33
is4: dsl::Location,
34
evex_scaling: Option<i8>,
35
},
36
}
37
38
/// Different methods of encoding the Reg/Opcode bits in a ModR/M byte.
39
#[derive(Copy, Clone)]
40
enum ModRmReg {
41
/// A static set of bits is used.
42
Digit(u8),
43
/// A runtime-defined register is used with this field name.
44
Reg(dsl::Location),
45
}
46
47
impl dsl::Format {
48
/// Re-order the Intel-style operand order to accommodate ATT-style
49
/// printing.
50
///
51
/// This is an unfortunate necessity to match Cranelift's current
52
/// disassembly, which uses AT&T-style printing. The plan is to eventually
53
/// transition to Intel-style printing (and avoid this awkward reordering)
54
/// once Cranelift has switched to using this assembler predominantly
55
/// (TODO).
56
#[must_use]
57
pub(crate) fn generate_att_style_operands(&self) -> String {
58
let ordered_ops: Vec<_> = self
59
.operands
60
.iter()
61
.filter(|o| !o.implicit)
62
.rev()
63
.map(|o| format!("{{{}}}", o.location))
64
.collect();
65
ordered_ops.join(", ")
66
}
67
68
#[must_use]
69
pub(crate) fn generate_implicit_operands(&self) -> String {
70
let ops: Vec<_> = self
71
.operands
72
.iter()
73
.filter(|o| o.implicit)
74
.map(|o| format!("{{{}}}", o.location))
75
.collect();
76
if ops.is_empty() {
77
String::new()
78
} else {
79
format!(" ;; implicit: {}", ops.join(", "))
80
}
81
}
82
83
pub(crate) fn generate_rex_encoding(&self, f: &mut Formatter, rex: &dsl::Rex) {
84
self.generate_prefixes(f, rex);
85
let style = self.generate_rex_prefix(f, rex);
86
rex.generate_opcodes(f, self.locations().next());
87
self.generate_modrm_byte(f, style);
88
self.generate_immediate(f, style);
89
}
90
91
pub fn generate_vex_encoding(&self, f: &mut Formatter, vex: &dsl::Vex) {
92
let style = self.generate_vex_prefix(f, vex);
93
vex.generate_opcode(f);
94
self.generate_modrm_byte(f, style);
95
self.generate_immediate(f, style);
96
}
97
98
pub fn generate_evex_encoding(&self, f: &mut Formatter, evex: &dsl::Evex) {
99
let style = self.generate_evex_prefix(f, evex);
100
evex.generate_opcode(f);
101
self.generate_modrm_byte(f, style);
102
self.generate_immediate(f, style);
103
}
104
105
/// `buf.put1(...);`
106
fn generate_prefixes(&self, f: &mut Formatter, rex: &dsl::Rex) {
107
if !rex.opcodes.prefixes.is_empty() {
108
f.empty_line();
109
f.comment("Emit prefixes.");
110
}
111
if let Some(group1) = &rex.opcodes.prefixes.group1 {
112
fmtln!(f, "buf.put1({group1});");
113
}
114
if let Some(group2) = &rex.opcodes.prefixes.group2 {
115
fmtln!(f, "buf.put1({group2});");
116
}
117
if let Some(group3) = &rex.opcodes.prefixes.group3 {
118
fmtln!(f, "buf.put1({group3});");
119
}
120
if let Some(group4) = &rex.opcodes.prefixes.group4 {
121
fmtln!(f, "buf.put1({group4});");
122
}
123
}
124
125
fn generate_rex_prefix(&self, f: &mut Formatter, rex: &dsl::Rex) -> ModRmStyle {
126
use dsl::OperandKind::{FixedReg, Imm, Mem, Reg, RegMem};
127
128
// If this instruction has only immediates there's no rex/modrm/etc, so
129
// skip everything below.
130
match self.operands_by_kind().as_slice() {
131
[] | [Imm(_)] => return ModRmStyle::None,
132
_ => {}
133
}
134
135
f.empty_line();
136
f.comment("Possibly emit REX prefix.");
137
138
let find_8bit_registers =
139
|l: &dsl::Location| l.bits() == 8 && matches!(l.kind(), Reg(_) | RegMem(_));
140
let uses_8bit = self.locations().any(find_8bit_registers);
141
fmtln!(f, "let uses_8bit = {uses_8bit};");
142
fmtln!(f, "let w_bit = {};", rex.w.as_bool());
143
let bits = "w_bit, uses_8bit";
144
145
let style = match self.operands_by_kind().as_slice() {
146
[FixedReg(dst), FixedReg(_)] | [FixedReg(dst)] | [FixedReg(dst), Imm(_)] => {
147
// TODO: don't emit REX byte here.
148
assert_eq!(rex.unwrap_digit(), None);
149
fmtln!(f, "let digit = 0;");
150
fmtln!(f, "let dst = self.{dst}.enc();");
151
fmtln!(f, "let rex = RexPrefix::with_digit(digit, dst, {bits});");
152
ModRmStyle::None
153
}
154
[Reg(dst)] => {
155
assert_eq!(rex.unwrap_digit(), None);
156
assert!(rex.opcode_mod.is_some());
157
fmtln!(f, "let dst = self.{dst}.enc();");
158
fmtln!(f, "let rex = RexPrefix::one_op(dst, {bits});");
159
ModRmStyle::None
160
}
161
[Reg(dst), Imm(_)] => match rex.unwrap_digit() {
162
Some(digit) => {
163
fmtln!(f, "let digit = 0x{digit:x};");
164
fmtln!(f, "let dst = self.{dst}.enc();");
165
fmtln!(f, "let rex = RexPrefix::two_op(digit, dst, {bits});");
166
ModRmStyle::Reg {
167
reg: ModRmReg::Digit(digit),
168
rm: *dst,
169
}
170
}
171
None => {
172
assert!(rex.opcode_mod.is_some());
173
fmtln!(f, "let dst = self.{dst}.enc();");
174
fmtln!(f, "let rex = RexPrefix::one_op(dst, {bits});");
175
ModRmStyle::None
176
}
177
},
178
[FixedReg(_), RegMem(mem)]
179
| [FixedReg(_), FixedReg(_), RegMem(mem)]
180
| [RegMem(mem), FixedReg(_)]
181
| [Mem(mem), Imm(_)]
182
| [RegMem(mem), Imm(_)]
183
| [RegMem(mem)]
184
| [FixedReg(_), FixedReg(_), FixedReg(_), FixedReg(_), Mem(mem)] => {
185
let digit = rex.unwrap_digit().unwrap();
186
fmtln!(f, "let digit = 0x{digit:x};");
187
fmtln!(f, "let rex = self.{mem}.as_rex_prefix(digit, {bits});");
188
ModRmStyle::RegMem {
189
reg: ModRmReg::Digit(digit),
190
rm: *mem,
191
evex_scaling: None,
192
}
193
}
194
[Reg(reg), RegMem(mem) | Mem(mem)]
195
| [Reg(reg), RegMem(mem), Imm(_) | FixedReg(_)]
196
| [RegMem(mem) | Mem(mem), Reg(reg)]
197
| [RegMem(mem) | Mem(mem), Reg(reg), Imm(_) | FixedReg(_)] => {
198
fmtln!(f, "let reg = self.{reg}.enc();");
199
fmtln!(f, "let rex = self.{mem}.as_rex_prefix(reg, {bits});");
200
ModRmStyle::RegMem {
201
reg: ModRmReg::Reg(*reg),
202
rm: *mem,
203
evex_scaling: None,
204
}
205
}
206
[Reg(dst), Reg(src), Imm(_)] | [Reg(dst), Reg(src)] => {
207
fmtln!(f, "let reg = self.{dst}.enc();");
208
fmtln!(f, "let rm = self.{src}.enc();");
209
fmtln!(f, "let rex = RexPrefix::two_op(reg, rm, {bits});");
210
ModRmStyle::Reg {
211
reg: ModRmReg::Reg(*dst),
212
rm: *src,
213
}
214
}
215
216
unknown => unimplemented!("unknown pattern: {unknown:?}"),
217
};
218
219
fmtln!(f, "rex.encode(buf);");
220
style
221
}
222
223
fn generate_vex_prefix(&self, f: &mut Formatter, vex: &dsl::Vex) -> ModRmStyle {
224
f.empty_line();
225
f.comment("Emit VEX prefix.");
226
fmtln!(f, "let len = {:#03b};", vex.length.vex_bits());
227
fmtln!(f, "let pp = {:#04b};", vex.pp.map_or(0b00, |pp| pp.bits()));
228
fmtln!(f, "let mmmmm = {:#07b};", vex.mmmmm.unwrap().bits());
229
fmtln!(f, "let w = {};", vex.w.as_bool());
230
let bits = "len, pp, mmmmm, w";
231
232
self.generate_vex_or_evex_prefix(f, "VexPrefix", &bits, vex.is4, None, || {
233
vex.unwrap_digit()
234
})
235
}
236
237
fn generate_evex_prefix(&self, f: &mut Formatter, evex: &dsl::Evex) -> ModRmStyle {
238
f.empty_line();
239
f.comment("Emit EVEX prefix.");
240
let ll = evex.length.evex_bits();
241
fmtln!(f, "let ll = {ll:#04b};");
242
fmtln!(f, "let pp = {:#04b};", evex.pp.map_or(0b00, |pp| pp.bits()));
243
fmtln!(f, "let mmm = {:#07b};", evex.mmm.unwrap().bits());
244
fmtln!(f, "let w = {};", evex.w.as_bool());
245
// NB: when bcast is supported in the future the `evex_scaling`
246
// calculation for `Full` and `Half` below need to be updated.
247
let bcast = false;
248
fmtln!(f, "let bcast = {bcast};");
249
let bits = format!("ll, pp, mmm, w, bcast");
250
let is4 = false;
251
252
let length_bytes = match evex.length {
253
dsl::Length::LZ | dsl::Length::LIG => unimplemented!(),
254
dsl::Length::L128 => 16,
255
dsl::Length::L256 => 32,
256
dsl::Length::L512 => 64,
257
};
258
259
// Figure out, according to table 2-34 and 2-35 in the Intel manual,
260
// what the scaling factor is for 8-bit displacements to pass through to
261
// encoding.
262
let evex_scaling = Some(match evex.tuple_type {
263
dsl::TupleType::Full => {
264
assert!(!bcast);
265
length_bytes
266
}
267
dsl::TupleType::Half => {
268
assert!(!bcast);
269
length_bytes / 2
270
}
271
dsl::TupleType::FullMem => length_bytes,
272
// FIXME: according to table 2-35 this needs to take into account
273
// "InputSize" which isn't accounted for in our `Evex` structure at
274
// this time.
275
dsl::TupleType::Tuple1Scalar => unimplemented!(),
276
dsl::TupleType::Tuple1Fixed => unimplemented!(),
277
dsl::TupleType::Tuple2 => unimplemented!(),
278
dsl::TupleType::Tuple4 => unimplemented!(),
279
dsl::TupleType::Tuple8 => 32,
280
dsl::TupleType::HalfMem => length_bytes / 2,
281
dsl::TupleType::QuarterMem => length_bytes / 4,
282
dsl::TupleType::EigthMem => length_bytes / 8,
283
dsl::TupleType::Mem128 => 16,
284
dsl::TupleType::Movddup => match evex.length {
285
dsl::Length::LZ | dsl::Length::LIG => unimplemented!(),
286
dsl::Length::L128 => 8,
287
dsl::Length::L256 => 32,
288
dsl::Length::L512 => 64,
289
},
290
});
291
292
self.generate_vex_or_evex_prefix(f, "EvexPrefix", &bits, is4, evex_scaling, || {
293
evex.unwrap_digit()
294
})
295
}
296
297
/// Helper function to generate either a vex or evex prefix, mostly handling
298
/// all the operand formats and structures here the same between the two
299
/// forms.
300
fn generate_vex_or_evex_prefix(
301
&self,
302
f: &mut Formatter,
303
prefix_type: &str,
304
bits: &str,
305
is4: bool,
306
evex_scaling: Option<i8>,
307
unwrap_digit: impl Fn() -> Option<u8>,
308
) -> ModRmStyle {
309
use dsl::OperandKind::{FixedReg, Imm, Mem, Reg, RegMem};
310
311
let style = match self.operands_by_kind().as_slice() {
312
[Reg(reg), Reg(vvvv), Reg(rm)] => {
313
assert!(!is4);
314
fmtln!(f, "let reg = self.{reg}.enc();");
315
fmtln!(f, "let vvvv = self.{vvvv}.enc();");
316
fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
317
fmtln!(
318
f,
319
"let prefix = {prefix_type}::three_op(reg, vvvv, rm, {bits});"
320
);
321
ModRmStyle::Reg {
322
reg: ModRmReg::Reg(*reg),
323
rm: *rm,
324
}
325
}
326
[Reg(reg), Reg(vvvv), RegMem(rm)]
327
| [Reg(reg), Reg(vvvv), Mem(rm)]
328
| [Reg(reg), Reg(vvvv), RegMem(rm), Imm(_) | FixedReg(_)]
329
| [Reg(reg), RegMem(rm), Reg(vvvv)] => {
330
assert!(!is4);
331
fmtln!(f, "let reg = self.{reg}.enc();");
332
fmtln!(f, "let vvvv = self.{vvvv}.enc();");
333
fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
334
fmtln!(
335
f,
336
"let prefix = {prefix_type}::three_op(reg, vvvv, rm, {bits});"
337
);
338
ModRmStyle::RegMem {
339
reg: ModRmReg::Reg(*reg),
340
rm: *rm,
341
evex_scaling,
342
}
343
}
344
[Reg(reg), Reg(vvvv), RegMem(rm), Reg(r_is4)] => {
345
assert!(is4);
346
fmtln!(f, "let reg = self.{reg}.enc();");
347
fmtln!(f, "let vvvv = self.{vvvv}.enc();");
348
fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
349
fmtln!(
350
f,
351
"let prefix = {prefix_type}::three_op(reg, vvvv, rm, {bits});"
352
);
353
ModRmStyle::RegMemIs4 {
354
reg: ModRmReg::Reg(*reg),
355
rm: *rm,
356
is4: *r_is4,
357
evex_scaling,
358
}
359
}
360
[Reg(reg_or_vvvv), RegMem(rm)]
361
| [RegMem(rm), Reg(reg_or_vvvv)]
362
| [Reg(reg_or_vvvv), RegMem(rm), Imm(_)] => match unwrap_digit() {
363
Some(digit) => {
364
assert!(!is4);
365
let vvvv = reg_or_vvvv;
366
fmtln!(f, "let reg = {digit:#x};");
367
fmtln!(f, "let vvvv = self.{vvvv}.enc();");
368
fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
369
fmtln!(
370
f,
371
"let prefix = {prefix_type}::three_op(reg, vvvv, rm, {bits});"
372
);
373
ModRmStyle::RegMem {
374
reg: ModRmReg::Digit(digit),
375
rm: *rm,
376
evex_scaling,
377
}
378
}
379
None => {
380
assert!(!is4);
381
let reg = reg_or_vvvv;
382
fmtln!(f, "let reg = self.{reg}.enc();");
383
fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
384
fmtln!(f, "let prefix = {prefix_type}::two_op(reg, rm, {bits});");
385
ModRmStyle::RegMem {
386
reg: ModRmReg::Reg(*reg),
387
rm: *rm,
388
evex_scaling,
389
}
390
}
391
},
392
[Reg(reg_or_vvvv), Reg(rm)] | [Reg(reg_or_vvvv), Reg(rm), Imm(_)] => {
393
match unwrap_digit() {
394
Some(digit) => {
395
assert!(!is4);
396
let vvvv = reg_or_vvvv;
397
fmtln!(f, "let reg = {digit:#x};");
398
fmtln!(f, "let vvvv = self.{vvvv}.enc();");
399
fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
400
fmtln!(
401
f,
402
"let prefix = {prefix_type}::three_op(reg, vvvv, rm, {bits});"
403
);
404
ModRmStyle::Reg {
405
reg: ModRmReg::Digit(digit),
406
rm: *rm,
407
}
408
}
409
None => {
410
assert!(!is4);
411
let reg = reg_or_vvvv;
412
fmtln!(f, "let reg = self.{reg}.enc();");
413
fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
414
fmtln!(f, "let prefix = {prefix_type}::two_op(reg, rm, {bits});");
415
ModRmStyle::Reg {
416
reg: ModRmReg::Reg(*reg),
417
rm: *rm,
418
}
419
}
420
}
421
}
422
[Reg(reg), Mem(rm)] | [Mem(rm), Reg(reg)] | [RegMem(rm), Reg(reg), Imm(_)] => {
423
assert!(!is4);
424
fmtln!(f, "let reg = self.{reg}.enc();");
425
fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");
426
fmtln!(f, "let prefix = {prefix_type}::two_op(reg, rm, {bits});");
427
ModRmStyle::RegMem {
428
reg: ModRmReg::Reg(*reg),
429
rm: *rm,
430
evex_scaling,
431
}
432
}
433
unknown => unimplemented!("unknown pattern: {unknown:?}"),
434
};
435
436
fmtln!(f, "prefix.encode(buf);");
437
style
438
}
439
440
fn generate_modrm_byte(&self, f: &mut Formatter, modrm_style: ModRmStyle) {
441
let operands = self.operands_by_kind();
442
let bytes_at_end = match operands.as_slice() {
443
[.., dsl::OperandKind::Imm(imm)] => imm.bytes(),
444
_ => match modrm_style {
445
ModRmStyle::RegMemIs4 { .. } => 1,
446
_ => 0,
447
},
448
};
449
450
f.empty_line();
451
452
match modrm_style {
453
ModRmStyle::None => f.comment("No need to emit a ModRM byte."),
454
_ => f.comment("Emit ModR/M byte."),
455
}
456
457
match modrm_style {
458
ModRmStyle::None => {}
459
ModRmStyle::RegMem {
460
reg,
461
rm,
462
evex_scaling,
463
}
464
| ModRmStyle::RegMemIs4 {
465
reg,
466
rm,
467
is4: _,
468
evex_scaling,
469
} => {
470
match reg {
471
ModRmReg::Reg(reg) => fmtln!(f, "let reg = self.{reg}.enc();"),
472
ModRmReg::Digit(digit) => fmtln!(f, "let reg = {digit:#x};"),
473
}
474
fmtln!(
475
f,
476
"self.{rm}.encode_rex_suffixes(buf, reg, {bytes_at_end}, {evex_scaling:?});"
477
);
478
}
479
ModRmStyle::Reg { reg, rm } => {
480
match reg {
481
ModRmReg::Reg(reg) => fmtln!(f, "let reg = self.{reg}.enc();"),
482
ModRmReg::Digit(digit) => fmtln!(f, "let reg = {digit:#x};"),
483
}
484
fmtln!(f, "self.{rm}.encode_modrm(buf, reg);");
485
}
486
}
487
}
488
489
fn generate_immediate(&self, f: &mut Formatter, modrm_style: ModRmStyle) {
490
use dsl::OperandKind::Imm;
491
match self.operands_by_kind().as_slice() {
492
[prefix @ .., Imm(imm)] => {
493
assert!(!prefix.iter().any(|o| matches!(o, Imm(_))));
494
f.empty_line();
495
f.comment("Emit immediate.");
496
fmtln!(f, "self.{imm}.encode(buf);");
497
}
498
unknown => {
499
if let ModRmStyle::RegMemIs4 { is4, .. } = modrm_style {
500
fmtln!(f, "buf.put1(self.{is4}.enc() << 4);");
501
}
502
503
// Do nothing: no immediates expected.
504
assert!(!unknown.iter().any(|o| matches!(o, Imm(_))));
505
}
506
}
507
}
508
}
509
510
impl dsl::Rex {
511
// `buf.put1(...);`
512
fn generate_opcodes(&self, f: &mut Formatter, first_op: Option<&dsl::Location>) {
513
f.empty_line();
514
f.comment("Emit opcode(s).");
515
if self.opcodes.escape {
516
fmtln!(f, "buf.put1(0x0f);");
517
}
518
if self.opcode_mod.is_some() {
519
let first_op = first_op.expect("Expected first operand for opcode_mod");
520
assert!(matches!(first_op.kind(), dsl::OperandKind::Reg(_)));
521
fmtln!(f, "let low_bits = self.{first_op}.enc() & 0b111;");
522
fmtln!(f, "buf.put1(0x{:x} | low_bits);", self.opcodes.primary);
523
} else {
524
fmtln!(f, "buf.put1(0x{:x});", self.opcodes.primary);
525
}
526
if let Some(secondary) = self.opcodes.secondary {
527
fmtln!(f, "buf.put1(0x{:x});", secondary);
528
}
529
}
530
}
531
532
impl dsl::Vex {
533
// `buf.put1(...);`
534
fn generate_opcode(&self, f: &mut Formatter) {
535
f.empty_line();
536
f.comment("Emit opcode.");
537
fmtln!(f, "buf.put1(0x{:x});", self.opcode);
538
}
539
}
540
541
impl dsl::Evex {
542
// `buf.put1(...);`
543
fn generate_opcode(&self, f: &mut Formatter) {
544
f.empty_line();
545
f.comment("Emit opcode.");
546
fmtln!(f, "buf.put1(0x{:x});", self.opcode);
547
}
548
}
549
550