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