Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/assembler-x64/src/vex.rs
1692 views
1
//! Encoding logic for VEX instructions.
2
3
use crate::api::CodeSink;
4
5
/// Construct and emit the VEX prefix bytes.
6
pub enum VexPrefix {
7
TwoByte(u8),
8
ThreeByte(u8, u8),
9
}
10
11
/// The VEX prefix only ever uses the top bit (bit 3--the fourth bit) of any
12
/// HW-encoded register.
13
#[inline(always)]
14
fn invert_top_bit(enc: u8) -> u8 {
15
(!(enc >> 3)) & 1
16
}
17
18
fn use_2byte_prefix(x: u8, b: u8, w: bool, mmmmm: u8) -> bool {
19
// These bits are only represented on the 3 byte prefix, so their presence
20
// implies the use of the 3 byte prefix
21
b == 1 && x == 1 &&
22
// The presence of W1 in the opcode column implies the opcode must be
23
// encoded using the 3-byte form of the VEX prefix.
24
w == false &&
25
// The presence of 0F3A and 0F38 in the opcode column implies that
26
// opcode can only be encoded by the three-byte form of VEX.
27
!(mmmmm == 0b10 || mmmmm == 0b11)
28
}
29
30
impl VexPrefix {
31
/// Construct the [`VexPrefix`] for a ternary instruction.
32
///
33
/// Used with a single register operand:
34
/// - `reg` and `vvvv` hold HW-encoded registers.
35
/// - `b` and `x` hold the (optional) HW-encoded registers for the `rm`
36
/// operand.
37
/// - the other fields (`l`, `pp`, `mmmmm`, `w`) correspond directly to
38
/// fields in the VEX prefix.
39
#[inline]
40
#[must_use]
41
pub fn three_op(
42
reg: u8,
43
vvvv: u8,
44
(b, x): (Option<u8>, Option<u8>),
45
l: u8,
46
pp: u8,
47
mmmmm: u8,
48
w: bool,
49
) -> Self {
50
let r = invert_top_bit(reg);
51
let b = invert_top_bit(b.unwrap_or(0));
52
let x = invert_top_bit(x.unwrap_or(0));
53
54
if use_2byte_prefix(x, b, w, mmmmm) {
55
// 2-byte VEX prefix.
56
//
57
// +-----+ +-------------------+
58
// | C5h | | R | vvvv | L | pp |
59
// +-----+ +-------------------+
60
debug_assert!(vvvv <= 0b1111);
61
debug_assert!(l <= 0b1);
62
debug_assert!(pp <= 0b11);
63
let last_byte = r << 7 | (!vvvv & 0b1111) << 3 | (l & 0b1) << 2 | (pp & 0b11);
64
65
Self::TwoByte(last_byte)
66
} else {
67
// 3-byte VEX prefix.
68
//
69
// +-----+ +--------------+ +-------------------+
70
// | C4h | | RXB | m-mmmm | | W | vvvv | L | pp |
71
// +-----+ +--------------+ +-------------------+
72
debug_assert!(mmmmm >= 0b01 && mmmmm <= 0b11);
73
let second_byte = r << 7 | x << 6 | b << 5 | mmmmm;
74
75
debug_assert!(vvvv <= 0b1111);
76
debug_assert!(l <= 0b1);
77
debug_assert!(pp <= 0b11);
78
let last_byte = (w as u8) << 7 | (!vvvv & 0b1111) << 3 | (l & 0b1) << 2 | (pp & 0b11);
79
80
Self::ThreeByte(second_byte, last_byte)
81
}
82
}
83
84
/// Construct the [`VexPrefix`] for a binary instruction.
85
///
86
/// This simply but conveniently reuses [`VexPrefix::three_op`] with a
87
/// `vvvv` value of `0`.
88
#[inline]
89
#[must_use]
90
pub fn two_op(
91
reg: u8,
92
(b, x): (Option<u8>, Option<u8>),
93
l: u8,
94
pp: u8,
95
mmmmm: u8,
96
w: bool,
97
) -> Self {
98
Self::three_op(reg, 0, (b, x), l, pp, mmmmm, w)
99
}
100
101
pub(crate) fn encode(&self, sink: &mut impl CodeSink) {
102
match self {
103
VexPrefix::TwoByte(last_byte) => {
104
sink.put1(0xC5);
105
sink.put1(*last_byte);
106
}
107
VexPrefix::ThreeByte(second_byte, last_byte) => {
108
sink.put1(0xC4);
109
sink.put1(*second_byte);
110
sink.put1(*last_byte);
111
}
112
}
113
}
114
}
115
116