Skip to content

Commit f3763e4

Browse files
jlb6740abrown
andauthored
Initial support for vex encoding for the new assembler. (#10754)
* Initial support for vex encoding for the new assembler. * Addressing many PR comments: Remove ymm and zmm support, cleanup, etc --------- Co-authored-by: Andrew Brown <[email protected]>
1 parent 10e71fa commit f3763e4

File tree

25 files changed

+551
-153
lines changed

25 files changed

+551
-153
lines changed

cranelift/assembler-x64/meta/src/dsl.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ mod features;
99
pub mod format;
1010

1111
pub use encoding::{
12-
Encoding, Group1Prefix, Group2Prefix, Group3Prefix, Group4Prefix, Opcodes, Prefixes, Rex,
12+
Encoding, Group1Prefix, Group2Prefix, Group3Prefix, Group4Prefix, Opcodes, Prefixes, Rex, Vex,
13+
VexLength, VexMMMMM, VexPP, rex, vex,
1314
};
14-
pub use encoding::{rex, vex};
1515
pub use features::{ALL_FEATURES, Feature, Features};
1616
pub use format::{Extension, Format, Location, Mutability, Operand, OperandKind, RegClass};
1717
pub use format::{align, fmt, implicit, r, rw, sxl, sxq, sxw, w};

cranelift/assembler-x64/meta/src/dsl/encoding.rs

Lines changed: 118 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,15 @@ pub fn rex(opcode: impl Into<Opcodes>) -> Rex {
3232

3333
/// An abbreviated constructor for VEX-encoded instructions.
3434
#[must_use]
35-
pub fn vex() -> Vex {
36-
Vex {}
35+
pub fn vex(opcode: impl Into<Opcodes>) -> Vex {
36+
Vex {
37+
opcodes: opcode.into(),
38+
w: false,
39+
length: VexLength::_128,
40+
mmmmm: VexMMMMM::None,
41+
pp: VexPP::None,
42+
imm: None,
43+
}
3744
}
3845

3946
/// Enumerate the ways x64 encodes instructions.
@@ -48,7 +55,7 @@ impl Encoding {
4855
pub fn validate(&self, operands: &[Operand]) {
4956
match self {
5057
Encoding::Rex(rex) => rex.validate(operands),
51-
Encoding::Vex(vex) => vex.validate(),
58+
Encoding::Vex(vex) => vex.validate(operands),
5259
}
5360
}
5461
}
@@ -57,7 +64,7 @@ impl fmt::Display for Encoding {
5764
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5865
match self {
5966
Encoding::Rex(rex) => write!(f, "{rex}"),
60-
Encoding::Vex(_vex) => todo!(),
67+
Encoding::Vex(vex) => write!(f, "{vex}"),
6168
}
6269
}
6370
}
@@ -563,7 +570,7 @@ pub enum Imm {
563570
}
564571

565572
impl Imm {
566-
fn bits(&self) -> u8 {
573+
fn bits(&self) -> u16 {
567574
match self {
568575
Imm::None => 0,
569576
Imm::ib => 8,
@@ -586,10 +593,113 @@ impl fmt::Display for Imm {
586593
}
587594
}
588595

589-
pub struct Vex {}
596+
pub struct Vex {
597+
pub opcodes: Opcodes,
598+
pub w: bool,
599+
pub length: VexLength,
600+
pub mmmmm: VexMMMMM,
601+
pub pp: VexPP,
602+
pub imm: Option<u8>,
603+
}
604+
605+
#[derive(PartialEq)]
606+
pub enum VexPP {
607+
None,
608+
/// Operand size override -- here, denoting "16-bit operation".
609+
_66,
610+
/// REPNE, but no specific meaning here -- is just an opcode extension.
611+
_F2,
612+
/// REP/REPE, but no specific meaning here -- is just an opcode extension.
613+
_F3,
614+
}
615+
616+
impl fmt::Display for VexPP {
617+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
618+
match self {
619+
VexPP::None => write!(f, "None"),
620+
VexPP::_66 => write!(f, "_66"),
621+
VexPP::_F3 => write!(f, "_F3"),
622+
VexPP::_F2 => write!(f, "_F2"),
623+
}
624+
}
625+
}
626+
627+
pub enum VexLength {
628+
_128,
629+
}
630+
631+
impl fmt::Display for VexLength {
632+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
633+
match self {
634+
VexLength::_128 => write!(f, "_128"),
635+
}
636+
}
637+
}
638+
639+
#[derive(PartialEq)]
640+
pub enum VexMMMMM {
641+
None,
642+
_OF,
643+
/// Operand size override -- here, denoting "16-bit operation".
644+
_OF3A,
645+
/// The lock prefix.
646+
_OF38,
647+
}
648+
649+
impl fmt::Display for VexMMMMM {
650+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
651+
match self {
652+
VexMMMMM::None => write!(f, "None"),
653+
VexMMMMM::_OF => write!(f, "_0F"),
654+
VexMMMMM::_OF3A => write!(f, "_OF3A"),
655+
VexMMMMM::_OF38 => write!(f, "_OF38"),
656+
}
657+
}
658+
}
659+
660+
/// Describe the register index to use. This wrapper is a type-safe way to pass
661+
/// around the registers defined in `inst/regs.rs`.
662+
#[derive(Debug, Copy, Clone, Default)]
663+
pub struct Register(u8);
664+
impl From<u8> for Register {
665+
fn from(reg: u8) -> Self {
666+
debug_assert!(reg < 16);
667+
Self(reg)
668+
}
669+
}
670+
impl Into<u8> for Register {
671+
fn into(self) -> u8 {
672+
self.0
673+
}
674+
}
590675

591676
impl Vex {
592-
fn validate(&self) {
593-
todo!()
677+
pub fn length(self, length: VexLength) -> Self {
678+
Self { length, ..self }
679+
}
680+
pub fn pp(self, pp: VexPP) -> Self {
681+
Self { pp, ..self }
682+
}
683+
pub fn mmmmm(self, mmmmm: VexMMMMM) -> Self {
684+
Self { mmmmm, ..self }
685+
}
686+
687+
fn validate(&self, _operands: &[Operand]) {}
688+
}
689+
690+
impl From<Vex> for Encoding {
691+
fn from(vex: Vex) -> Encoding {
692+
Encoding::Vex(vex)
693+
}
694+
}
695+
696+
impl fmt::Display for Vex {
697+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
698+
write!(f, "VEX")?;
699+
match self.length {
700+
VexLength::_128 => write!(f, ".128")?,
701+
}
702+
write!(f, " {:#04x}", self.opcodes.primary)?;
703+
Ok(())
594704
}
595705
}

cranelift/assembler-x64/meta/src/dsl/format.rs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,6 @@ pub enum Location {
300300
rm64,
301301

302302
// XMM registers, and their memory forms.
303-
xmm,
304303
xmm_m32,
305304
xmm_m64,
306305
xmm_m128,
@@ -310,25 +309,28 @@ pub enum Location {
310309
m16,
311310
m32,
312311
m64,
312+
xmm1,
313+
xmm2,
314+
xmm3,
313315
}
314316

315317
impl Location {
316318
/// Return the number of bits accessed.
317319
#[must_use]
318-
pub fn bits(&self) -> u8 {
320+
pub fn bits(&self) -> u16 {
319321
use Location::*;
320322
match self {
321323
al | cl | imm8 | r8 | rm8 | m8 => 8,
322324
ax | dx | imm16 | r16 | rm16 | m16 => 16,
323325
eax | edx | imm32 | r32 | rm32 | m32 | xmm_m32 => 32,
324326
rax | rdx | r64 | rm64 | m64 | xmm_m64 => 64,
325-
xmm | xmm_m128 => 128,
327+
xmm1 | xmm2 | xmm3 | xmm_m128 => 128,
326328
}
327329
}
328330

329331
/// Return the number of bytes accessed, for convenience.
330332
#[must_use]
331-
pub fn bytes(&self) -> u8 {
333+
pub fn bytes(&self) -> u16 {
332334
self.bits() / 8
333335
}
334336

@@ -338,8 +340,8 @@ impl Location {
338340
use Location::*;
339341
match self {
340342
al | ax | eax | rax | cl | dx | edx | rdx | imm8 | imm16 | imm32 | r8 | r16 | r32
341-
| r64 | xmm => false,
342-
rm8 | rm16 | rm32 | rm64 | xmm_m32 | xmm_m64 | xmm_m128 | m8 | m16 | m32 | m64 => true,
343+
| r64 | xmm1 | xmm2 | xmm3 => false,
344+
rm8 | rm16 | rm32 | rm64 | m8 | m16 | m32 | m64 | xmm_m32 | xmm_m64 | xmm_m128 => true,
343345
}
344346
}
345347

@@ -351,7 +353,8 @@ impl Location {
351353
match self {
352354
imm8 | imm16 | imm32 => false,
353355
al | ax | eax | rax | cl | dx | edx | rdx | r8 | r16 | r32 | r64 | rm8 | rm16
354-
| rm32 | rm64 | xmm | xmm_m32 | xmm_m64 | xmm_m128 | m8 | m16 | m32 | m64 => true,
356+
| rm32 | rm64 | m8 | m16 | m32 | m64 | xmm1 | xmm2 | xmm3 | xmm_m32 | xmm_m64
357+
| xmm_m128 => true,
355358
}
356359
}
357360

@@ -362,7 +365,7 @@ impl Location {
362365
match self {
363366
al | ax | eax | rax | cl | dx | edx | rdx => OperandKind::FixedReg(*self),
364367
imm8 | imm16 | imm32 => OperandKind::Imm(*self),
365-
r8 | r16 | r32 | r64 | xmm => OperandKind::Reg(*self),
368+
r8 | r16 | r32 | r64 | xmm1 | xmm2 | xmm3 => OperandKind::Reg(*self),
366369
rm8 | rm16 | rm32 | rm64 | xmm_m32 | xmm_m64 | xmm_m128 => OperandKind::RegMem(*self),
367370
m8 | m16 | m32 | m64 => OperandKind::Mem(*self),
368371
}
@@ -379,7 +382,7 @@ impl Location {
379382
imm8 | imm16 | imm32 | m8 | m16 | m32 | m64 => None,
380383
al | ax | eax | rax | cl | dx | edx | rdx | r8 | r16 | r32 | r64 | rm8 | rm16
381384
| rm32 | rm64 => Some(RegClass::Gpr),
382-
xmm | xmm_m32 | xmm_m64 | xmm_m128 => Some(RegClass::Xmm),
385+
xmm1 | xmm2 | xmm3 | xmm_m32 | xmm_m64 | xmm_m128 => Some(RegClass::Xmm),
383386
}
384387
}
385388
}
@@ -410,7 +413,6 @@ impl core::fmt::Display for Location {
410413
rm32 => write!(f, "rm32"),
411414
rm64 => write!(f, "rm64"),
412415

413-
xmm => write!(f, "xmm"),
414416
xmm_m32 => write!(f, "xmm_m32"),
415417
xmm_m64 => write!(f, "xmm_m64"),
416418
xmm_m128 => write!(f, "xmm_m128"),
@@ -419,6 +421,10 @@ impl core::fmt::Display for Location {
419421
m16 => write!(f, "m16"),
420422
m32 => write!(f, "m32"),
421423
m64 => write!(f, "m64"),
424+
425+
xmm1 => write!(f, "xmm1"),
426+
xmm2 => write!(f, "xmm2"),
427+
xmm3 => write!(f, "xmm3"),
422428
}
423429
}
424430
}

cranelift/assembler-x64/meta/src/generate/format.rs

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
//! Generate format-related Rust code; this also includes generation of encoding
22
//! Rust code.
3-
43
use super::{Formatter, fmtln};
54
use crate::dsl;
65

@@ -48,6 +47,38 @@ impl dsl::Format {
4847
self.generate_immediate(f);
4948
}
5049

50+
pub fn generate_vex_encoding(&self, f: &mut Formatter, vex: &dsl::Vex) {
51+
use dsl::OperandKind::{Reg, RegMem};
52+
f.empty_line();
53+
f.comment("Emit New VEX prefix.");
54+
55+
match self.operands_by_kind().as_slice() {
56+
[Reg(xmm1), Reg(xmm2), RegMem(xmm_m128)] => {
57+
fmtln!(
58+
f,
59+
"vex_instruction::<R>(
60+
0x{:0x},
61+
VexVectorLength::{},
62+
VexPP::{},
63+
OpcodeMap::{},
64+
self.{}.enc(),
65+
Some(self.{}.enc()),
66+
Some(self.{}),
67+
{}).encode(buf, off);",
68+
vex.opcodes.primary,
69+
vex.length.to_string(),
70+
vex.pp.to_string(),
71+
vex.mmmmm.to_string(),
72+
xmm1,
73+
xmm2,
74+
xmm_m128,
75+
"None"
76+
);
77+
}
78+
_ => unimplemented!(),
79+
}
80+
}
81+
5182
/// `buf.put1(...);`
5283
fn generate_prefixes(&self, f: &mut Formatter, rex: &dsl::Rex) {
5384
if !rex.opcodes.prefixes.is_empty() {
@@ -135,9 +166,9 @@ impl dsl::Format {
135166
fmtln!(f, "let rex = self.{dst}.as_rex_prefix(src, {bits});");
136167
}
137168

138-
[Reg(dst), Reg(xmm), Imm(_)] | [Reg(dst), Reg(xmm)] => {
169+
[Reg(dst), Reg(xmm2), Imm(_)] | [Reg(dst), Reg(xmm2)] => {
139170
fmtln!(f, "let reg = self.{dst}.enc();");
140-
fmtln!(f, "let rm = self.xmm.enc();");
171+
fmtln!(f, "let rm = self.xmm2.enc();");
141172
fmtln!(f, "let rex = RexPrefix::two_op(reg, rm, {bits});");
142173
}
143174

@@ -197,8 +228,8 @@ impl dsl::Format {
197228
);
198229
}
199230

200-
[Reg(dst), Reg(xmm), Imm(_)] | [Reg(dst), Reg(xmm)] => {
201-
fmtln!(f, "self.xmm.encode_modrm(buf, self.{dst}.enc());");
231+
[Reg(dst), Reg(xmm2), Imm(_)] | [Reg(dst), Reg(xmm2)] => {
232+
fmtln!(f, "self.xmm2.encode_modrm(buf, self.{dst}.enc());");
202233
}
203234

204235
unknown => unimplemented!("unknown pattern: {unknown:?}"),

cranelift/assembler-x64/meta/src/generate/inst.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ impl dsl::Inst {
140140

141141
match &self.encoding {
142142
dsl::Encoding::Rex(rex) => self.format.generate_rex_encoding(f, rex),
143-
dsl::Encoding::Vex(_) => todo!(),
143+
dsl::Encoding::Vex(vex) => self.format.generate_vex_encoding(f, vex),
144144
}
145145
},
146146
);

cranelift/assembler-x64/meta/src/generate/operand.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ impl dsl::Operand {
2525
}
2626
r8 | r16 | r32 | r64 => format!("Gpr<R::{mut_}Gpr>"),
2727
rm8 | rm16 | rm32 | rm64 => format!("GprMem<R::{mut_}Gpr, R::ReadGpr>"),
28-
xmm => format!("Xmm<R::{mut_}Xmm>"),
28+
xmm1 | xmm2 | xmm3 => {
29+
format!("Xmm<R::{mut_}Xmm>")
30+
}
2931
xmm_m32 | xmm_m64 | xmm_m128 => {
3032
format!("XmmMem<R::{mut_}Xmm, R::ReadGpr>")
3133
}
@@ -53,7 +55,7 @@ impl dsl::Location {
5355
Some(size) => format!("self.{self}.to_string({size})"),
5456
None => unreachable!(),
5557
},
56-
xmm | xmm_m32 | xmm_m64 | xmm_m128 | m8 | m16 | m32 | m64 => {
58+
xmm_m32 | xmm_m64 | xmm1 | xmm2 | xmm3 | xmm_m128 | m8 | m16 | m32 | m64 => {
5759
format!("self.{self}.to_string()")
5860
}
5961
}
@@ -72,7 +74,7 @@ impl dsl::Location {
7274
m8 | m16 | m32 | m64 => {
7375
panic!("no need to generate a size for memory-only access")
7476
}
75-
xmm | xmm_m32 | xmm_m64 | xmm_m128 => {
77+
xmm_m32 | xmm_m64 | xmm1 | xmm2 | xmm3 | xmm_m128 => {
7678
panic!("no need to generate a size for XMM-sized access")
7779
}
7880
}

0 commit comments

Comments
 (0)