cranelift_assembler_x64/
evex.rs1use crate::api::CodeSink;
4
5pub struct EvexPrefix {
7 byte1: u8,
8 byte2: u8,
9 byte3: u8,
10}
11
12#[inline(always)]
15fn invert_top_bit(enc: u8) -> u8 {
16 (!(enc >> 3)) & 1
17}
18
19impl EvexPrefix {
28 pub fn new(
30 reg: u8,
31 vvvv: u8,
32 (b, x): (Option<u8>, Option<u8>),
33 ll: u8,
34 pp: u8,
35 mmm: u8,
36 w: bool,
37 broadcast: bool,
38 ) -> Self {
39 let r = invert_top_bit(reg);
40 let r_prime = invert_top_bit(reg >> 1);
41 let b = invert_top_bit(b.unwrap_or(0));
42 let x = invert_top_bit(x.unwrap_or(0));
43 let vvvv_value = !vvvv & 0b1111;
44 let v_prime = !(vvvv >> 4) & 0b1;
45
46 debug_assert!(mmm <= 0b111);
48 let byte1 = r << 7 | x << 6 | b << 5 | r_prime << 4 | mmm;
49
50 debug_assert!(vvvv <= 0b11111);
52 debug_assert!(pp <= 0b11);
53 let byte2 = (w as u8) << 7 | vvvv_value << 3 | 0b100 | (pp & 0b11);
54
55 debug_assert!(ll < 0b11, "bits 11b are reserved (#UD); must fit in 2 bits");
57 let aaa = 0b000; let z = 0; let byte3 = z | ll << 5 | (broadcast as u8) << 4 | v_prime << 3 | aaa;
60
61 Self {
62 byte1,
63 byte2,
64 byte3,
65 }
66 }
67
68 pub fn two_op(
70 reg: u8,
71 (b, x): (Option<u8>, Option<u8>),
72 ll: u8,
73 pp: u8,
74 mmm: u8,
75 w: bool,
76 broadcast: bool,
77 ) -> Self {
78 EvexPrefix::new(reg, 0, (b, x), ll, pp, mmm, w, broadcast)
79 }
80
81 pub fn three_op(
83 reg: u8,
84 vvvv: u8,
85 (b, x): (Option<u8>, Option<u8>),
86 ll: u8,
87 pp: u8,
88 mmm: u8,
89 w: bool,
90 broadcast: bool,
91 ) -> Self {
92 EvexPrefix::new(reg, vvvv, (b, x), ll, pp, mmm, w, broadcast)
93 }
94
95 pub(crate) fn encode(&self, sink: &mut impl CodeSink) {
96 sink.put1(0x62);
97 sink.put1(self.byte1);
98 sink.put1(self.byte2);
99 sink.put1(self.byte3);
100 }
101}