cranelift_assembler_x64/
evex.rs

1//! Encoding logic for EVEX instructions.
2
3use crate::api::CodeSink;
4
5/// EVEX prefix is always 4 bytes, byte 0 is 0x62
6pub struct EvexPrefix {
7    byte1: u8,
8    byte2: u8,
9    byte3: u8,
10}
11
12/// The EVEX prefix only ever uses the top bit (bit 3--the fourth bit) of any
13/// HW-encoded register.
14#[inline(always)]
15fn invert_top_bit(enc: u8) -> u8 {
16    (!(enc >> 3)) & 1
17}
18
19//         ┌───┬───┬───┬───┬───┬───┬───┬───┐
20// Byte 1: │ R │ X │ B │ R'│ 0 │ 0 │ m │ m │
21//         ├───┼───┼───┼───┼───┼───┼───┼───┤
22// Byte 2: │ W │ v │ v │ v │ v │ 1 │ p │ p │
23//         ├───┼───┼───┼───┼───┼───┼───┼───┤
24// Byte 3: │ z │ L'│ L │ b │ V'│ a │ a │ a │
25//         └───┴───┴───┴───┴───┴───┴───┴───┘
26
27impl EvexPrefix {
28    /// Construct the [`EvexPrefix`] for an instruction.
29    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        // byte1
47        debug_assert!(mmm <= 0b111);
48        let byte1 = r << 7 | x << 6 | b << 5 | r_prime << 4 | mmm;
49
50        // byte2
51        debug_assert!(vvvv <= 0b11111);
52        debug_assert!(pp <= 0b11);
53        let byte2 = (w as u8) << 7 | vvvv_value << 3 | 0b100 | (pp & 0b11);
54
55        // byte3
56        debug_assert!(ll < 0b11, "bits 11b are reserved (#UD); must fit in 2 bits");
57        let aaa = 0b000; // Force k0 masking register for now; eventually this should be configurable (TODO).
58        let z = 0; // Masking kind bit; not used yet (TODO) so we default to merge-masking.
59        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    /// Construct the [`EvexPrefix`] for an instruction.
69    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    /// Construct the [`EvexPrefix`] for an instruction.
82    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}