Skip to content

Commit 78ea103

Browse files
committed
Initial support for vex encoding for the new assembler.
1 parent 7a27724 commit 78ea103

File tree

25 files changed

+614
-80
lines changed

25 files changed

+614
-80
lines changed

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ mod encoding;
88
mod features;
99
pub mod format;
1010

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

1919
/// Abbreviated constructor for an x64 instruction.

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

+151-8
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,18 @@ 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+
wig: false,
40+
length: VexLength::default(),
41+
mmmmm: VexMMMMM::None,
42+
pp: VexPP::None,
43+
reg: 0x00,
44+
vvvv: None,
45+
imm: None,
46+
}
3747
}
3848

3949
/// Enumerate the ways x64 encodes instructions.
@@ -48,7 +58,7 @@ impl Encoding {
4858
pub fn validate(&self, operands: &[Operand]) {
4959
match self {
5060
Encoding::Rex(rex) => rex.validate(operands),
51-
Encoding::Vex(vex) => vex.validate(),
61+
Encoding::Vex(vex) => vex.validate(operands),
5262
}
5363
}
5464
}
@@ -57,7 +67,7 @@ impl fmt::Display for Encoding {
5767
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5868
match self {
5969
Encoding::Rex(rex) => write!(f, "{rex}"),
60-
Encoding::Vex(_vex) => todo!(),
70+
Encoding::Vex(vex) => write!(f, "{vex}"),
6171
}
6272
}
6373
}
@@ -408,6 +418,23 @@ impl Prefixes {
408418
&& self.group3.is_none()
409419
&& self.group4.is_none()
410420
}
421+
422+
pub fn bits(&self) -> u8 {
423+
let mut bits = 0;
424+
if self.group1.is_some() {
425+
bits |= 0b0001;
426+
}
427+
if self.group2.is_some() {
428+
bits |= 0b0010;
429+
}
430+
if self.group3.is_some() {
431+
bits |= 0b0100;
432+
}
433+
if self.group4.is_some() {
434+
bits |= 0b1000;
435+
}
436+
bits
437+
}
411438
}
412439

413440
pub enum Group1Prefix {
@@ -584,7 +611,7 @@ pub enum Imm {
584611
}
585612

586613
impl Imm {
587-
fn bits(&self) -> u8 {
614+
fn bits(&self) -> u16 {
588615
match self {
589616
Imm::None => 0,
590617
Imm::ib => 8,
@@ -607,10 +634,126 @@ impl fmt::Display for Imm {
607634
}
608635
}
609636

610-
pub struct Vex {}
637+
pub struct Vex {
638+
pub opcodes: Opcodes,
639+
pub w: bool,
640+
pub wig: bool,
641+
pub length: VexLength,
642+
pub mmmmm: VexMMMMM,
643+
pub pp: VexPP,
644+
pub reg: u8,
645+
pub vvvv: Option<Register>,
646+
pub imm: Option<u8>,
647+
}
648+
649+
#[derive(PartialEq)]
650+
pub enum VexPP {
651+
None,
652+
/// Operand size override -- here, denoting "16-bit operation".
653+
_66,
654+
/// REPNE, but no specific meaning here -- is just an opcode extension.
655+
_F2,
656+
/// REP/REPE, but no specific meaning here -- is just an opcode extension.
657+
_F3,
658+
}
659+
660+
impl fmt::Display for VexPP {
661+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
662+
match self {
663+
VexPP::None => write!(f, "None"),
664+
VexPP::_66 => write!(f, "_66"),
665+
VexPP::_F3 => write!(f, "_F3"),
666+
VexPP::_F2 => write!(f, "_F2"),
667+
}
668+
}
669+
}
670+
671+
#[derive(PartialEq)]
672+
pub enum VexMMMMM {
673+
None,
674+
_OF,
675+
/// Operand size override -- here, denoting "16-bit operation".
676+
_OF3A,
677+
/// The lock prefix.
678+
_OF38,
679+
}
680+
681+
impl fmt::Display for VexMMMMM {
682+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
683+
match self {
684+
VexMMMMM::None => write!(f, "None"),
685+
VexMMMMM::_OF => write!(f, "_0F"),
686+
VexMMMMM::_OF3A => write!(f, "_OF3A"),
687+
VexMMMMM::_OF38 => write!(f, "_OF38"),
688+
}
689+
}
690+
}
691+
692+
pub enum VexLength {
693+
_128,
694+
_256,
695+
}
696+
697+
impl VexLength {
698+
/// Encode the `L` bit.
699+
pub fn bits(&self) -> u8 {
700+
match self {
701+
Self::_128 => 0b0,
702+
Self::_256 => 0b1,
703+
}
704+
}
705+
}
706+
707+
impl Default for VexLength {
708+
fn default() -> Self {
709+
Self::_128
710+
}
711+
}
712+
713+
/// Describe the register index to use. This wrapper is a type-safe way to pass
714+
/// around the registers defined in `inst/regs.rs`.
715+
#[derive(Debug, Copy, Clone, Default)]
716+
pub struct Register(u8);
717+
impl From<u8> for Register {
718+
fn from(reg: u8) -> Self {
719+
debug_assert!(reg < 16);
720+
Self(reg)
721+
}
722+
}
723+
impl Into<u8> for Register {
724+
fn into(self) -> u8 {
725+
self.0
726+
}
727+
}
611728

612729
impl Vex {
613-
fn validate(&self) {
614-
todo!()
730+
pub fn length(self, length: VexLength) -> Self {
731+
Self { length, ..self }
732+
}
733+
pub fn pp(self, pp: VexPP) -> Self {
734+
Self { pp, ..self }
735+
}
736+
pub fn mmmmm(self, mmmmm: VexMMMMM) -> Self {
737+
Self { mmmmm, ..self }
738+
}
739+
740+
fn validate(&self, _operands: &[Operand]) {}
741+
}
742+
743+
impl From<Vex> for Encoding {
744+
fn from(vex: Vex) -> Encoding {
745+
Encoding::Vex(vex)
746+
}
747+
}
748+
749+
impl fmt::Display for Vex {
750+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
751+
write!(f, "VEX")?;
752+
match self.length {
753+
VexLength::_128 => write!(f, ".128")?,
754+
VexLength::_256 => write!(f, ".256")?,
755+
}
756+
write!(f, " {:#04x}", self.opcodes.primary)?;
757+
Ok(())
615758
}
616759
}

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

+59-13
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,16 @@ pub fn r(op: impl Into<Operand>) -> Operand {
5252
op
5353
}
5454

55+
#[must_use]
56+
pub fn w(location: Location) -> Operand {
57+
Operand {
58+
location,
59+
mutability: Mutability::Write,
60+
extension: Extension::None,
61+
align: false,
62+
}
63+
}
64+
5565
/// An abbreviated constructor for a memory operand that requires alignment.
5666
pub fn align(location: Location) -> Operand {
5767
assert!(location.uses_memory());
@@ -277,35 +287,47 @@ pub enum Location {
277287
rm64,
278288

279289
// XMM registers, and their memory forms.
280-
xmm,
281290
xmm_m32,
282291
xmm_m64,
283292
xmm_m128,
293+
ymm_m256,
294+
zmm_m512,
284295

285296
// Memory-only locations.
286297
m8,
287298
m16,
288299
m32,
289300
m64,
301+
xmm1,
302+
xmm2,
303+
xmm3,
304+
ymm1,
305+
ymm2,
306+
ymm3,
307+
zmm1,
308+
zmm2,
309+
zmm3,
290310
}
291311

292312
impl Location {
293313
/// Return the number of bits accessed.
294314
#[must_use]
295-
pub fn bits(&self) -> u8 {
315+
pub fn bits(&self) -> u16 {
296316
use Location::*;
297317
match self {
298318
al | cl | imm8 | r8 | rm8 | m8 => 8,
299319
ax | imm16 | r16 | rm16 | m16 => 16,
300320
eax | imm32 | r32 | rm32 | m32 | xmm_m32 => 32,
301321
rax | r64 | rm64 | m64 | xmm_m64 => 64,
302-
xmm | xmm_m128 => 128,
322+
xmm1 | xmm2 | xmm3 | xmm_m128 => 128,
323+
ymm1 | ymm2 | ymm3 | ymm_m256 => 256,
324+
zmm1 | zmm2 | zmm3 | zmm_m512 => 512,
303325
}
304326
}
305327

306328
/// Return the number of bytes accessed, for convenience.
307329
#[must_use]
308-
pub fn bytes(&self) -> u8 {
330+
pub fn bytes(&self) -> u16 {
309331
self.bits() / 8
310332
}
311333

@@ -314,8 +336,10 @@ impl Location {
314336
pub fn uses_memory(&self) -> bool {
315337
use Location::*;
316338
match self {
317-
al | cl | ax | eax | rax | imm8 | imm16 | imm32 | r8 | r16 | r32 | r64 | xmm => false,
318-
rm8 | rm16 | rm32 | rm64 | xmm_m32 | xmm_m64 | xmm_m128 | m8 | m16 | m32 | m64 => true,
339+
al | cl | ax | eax | rax | imm8 | imm16 | imm32 | r8 | r16 | r32 | r64 | xmm1
340+
| xmm2 | xmm3 | ymm1 | ymm2 | ymm3 | zmm1 | zmm2 | zmm3 => false,
341+
rm8 | rm16 | rm32 | rm64 | xmm_m32 | xmm_m64 | m8 | m16 | m32 | m64 | xmm_m128
342+
| ymm_m256 | zmm_m512 => true,
319343
}
320344
}
321345

@@ -326,8 +350,9 @@ impl Location {
326350
use Location::*;
327351
match self {
328352
imm8 | imm16 | imm32 => false,
329-
al | ax | eax | rax | cl | r8 | r16 | r32 | r64 | rm8 | rm16 | rm32 | rm64 | xmm
330-
| xmm_m32 | xmm_m64 | xmm_m128 | m8 | m16 | m32 | m64 => true,
353+
al | ax | eax | rax | cl | r8 | r16 | r32 | r64 | rm8 | rm16 | rm32 | rm64 | m8
354+
| m16 | m32 | m64 | xmm1 | xmm2 | xmm3 | xmm_m32 | xmm_m64 | ymm1 | ymm2 | ymm3
355+
| zmm1 | zmm2 | zmm3 | xmm_m128 | ymm_m256 | zmm_m512 => true,
331356
}
332357
}
333358

@@ -338,8 +363,12 @@ impl Location {
338363
match self {
339364
al | ax | eax | rax | cl => OperandKind::FixedReg(*self),
340365
imm8 | imm16 | imm32 => OperandKind::Imm(*self),
341-
r8 | r16 | r32 | r64 | xmm => OperandKind::Reg(*self),
342-
rm8 | rm16 | rm32 | rm64 | xmm_m32 | xmm_m64 | xmm_m128 => OperandKind::RegMem(*self),
366+
r8 | r16 | r32 | r64 | xmm1 | xmm2 | xmm3 | ymm1 | ymm2 | ymm3 | zmm1 | zmm2 | zmm3 => {
367+
OperandKind::Reg(*self)
368+
}
369+
rm8 | rm16 | rm32 | rm64 | xmm_m32 | xmm_m64 | xmm_m128 | ymm_m256 | zmm_m512 => {
370+
OperandKind::RegMem(*self)
371+
}
343372
m8 | m16 | m32 | m64 => OperandKind::Mem(*self),
344373
}
345374
}
@@ -356,7 +385,8 @@ impl Location {
356385
al | ax | eax | rax | cl | r8 | r16 | r32 | r64 | rm8 | rm16 | rm32 | rm64 => {
357386
Some(RegClass::Gpr)
358387
}
359-
xmm | xmm_m32 | xmm_m64 | xmm_m128 => Some(RegClass::Xmm),
388+
xmm1 | xmm2 | xmm3 | ymm1 | ymm2 | ymm3 | zmm1 | zmm2 | zmm3 | xmm_m32 | xmm_m64
389+
| xmm_m128 | ymm_m256 | zmm_m512 => Some(RegClass::Xmm),
360390
}
361391
}
362392
}
@@ -384,15 +414,28 @@ impl core::fmt::Display for Location {
384414
rm32 => write!(f, "rm32"),
385415
rm64 => write!(f, "rm64"),
386416

387-
xmm => write!(f, "xmm"),
388417
xmm_m32 => write!(f, "xmm_m32"),
389418
xmm_m64 => write!(f, "xmm_m64"),
390419
xmm_m128 => write!(f, "xmm_m128"),
420+
ymm_m256 => write!(f, "ymm_m256"),
421+
zmm_m512 => write!(f, "zmm_m512"),
391422

392423
m8 => write!(f, "m8"),
393424
m16 => write!(f, "m16"),
394425
m32 => write!(f, "m32"),
395426
m64 => write!(f, "m64"),
427+
428+
xmm1 => write!(f, "xmm1"),
429+
xmm2 => write!(f, "xmm2"),
430+
xmm3 => write!(f, "xmm3"),
431+
432+
ymm1 => write!(f, "ymm1"),
433+
ymm2 => write!(f, "ymm2"),
434+
ymm3 => write!(f, "ymm3"),
435+
436+
zmm1 => write!(f, "zmm1"),
437+
zmm2 => write!(f, "zmm2"),
438+
zmm3 => write!(f, "zmm3"),
396439
}
397440
}
398441
}
@@ -423,6 +466,7 @@ pub enum OperandKind {
423466
pub enum Mutability {
424467
Read,
425468
ReadWrite,
469+
Write,
426470
}
427471

428472
impl Mutability {
@@ -432,6 +476,7 @@ impl Mutability {
432476
pub fn is_read(&self) -> bool {
433477
match self {
434478
Mutability::Read | Mutability::ReadWrite => true,
479+
Mutability::Write => false,
435480
}
436481
}
437482

@@ -441,7 +486,7 @@ impl Mutability {
441486
pub fn is_write(&self) -> bool {
442487
match self {
443488
Mutability::Read => false,
444-
Mutability::ReadWrite => true,
489+
Mutability::ReadWrite | Mutability::Write => true,
445490
}
446491
}
447492
}
@@ -457,6 +502,7 @@ impl core::fmt::Display for Mutability {
457502
match self {
458503
Self::Read => write!(f, "r"),
459504
Self::ReadWrite => write!(f, "rw"),
505+
Self::Write => write!(f, "w"),
460506
}
461507
}
462508
}

0 commit comments

Comments
 (0)