machinst x64: refactor REX prefix emission;

This commit is contained in:
Benjamin Bouvier
2020-06-11 16:51:44 +02:00
parent be4102b205
commit 48fb9291bc

View File

@@ -76,17 +76,38 @@ impl Rex {
self self
} }
/// Return whether the W bit in the REX prefix is zero.
#[inline(always)] #[inline(always)]
fn must_clear_w(&self) -> bool { fn must_clear_w(&self) -> bool {
(self.0 & 1) != 0 (self.0 & 1) != 0
} }
/// Return whether we need to emit the REX prefix byte even if it appears
/// to be redundant (== 0x40).
#[inline(always)] #[inline(always)]
fn must_always_emit(&self) -> bool { fn must_always_emit(&self) -> bool {
(self.0 & 2) != 0 (self.0 & 2) != 0
} }
#[inline(always)]
fn emit_two_op(&self, sink: &mut MachBuffer<Inst>, enc_g: u8, enc_e: u8) {
let w = if self.must_clear_w() { 0 } else { 1 };
let r = (enc_g >> 3) & 1;
let x = 0;
let b = (enc_e >> 3) & 1;
let rex = 0x40 | (w << 3) | (r << 2) | (x << 1) | b;
if rex != 0x40 || self.must_always_emit() {
sink.put1(rex);
}
}
#[inline(always)]
fn emit_three_op(&self, sink: &mut MachBuffer<Inst>, enc_g: u8, enc_index: u8, enc_base: u8) {
let w = if self.must_clear_w() { 0 } else { 1 };
let r = (enc_g >> 3) & 1;
let x = (enc_index >> 3) & 1;
let b = (enc_base >> 3) & 1;
let rex = 0x40 | (w << 3) | (r << 2) | (x << 1) | b;
if rex != 0x40 || self.must_always_emit() {
sink.put1(rex);
}
}
} }
/// For specifying the legacy prefixes (or `None` if no prefix required) to /// For specifying the legacy prefixes (or `None` if no prefix required) to
@@ -140,26 +161,17 @@ fn emit_modrm_sib_enc_ge(
mem_e: &Addr, mem_e: &Addr,
rex: Rex, rex: Rex,
) { ) {
// General comment for this function: the registers in `memE` must be // General comment for this function: the registers in `mem_e` must be
// 64-bit integer registers, because they are part of an address // 64-bit integer registers, because they are part of an address
// expression. But `enc_g` can be derived from a register of any class. // expression. But `enc_g` can be derived from a register of any class.
let clear_rex_w = rex.must_clear_w();
let retain_redundant = rex.must_always_emit();
prefix.emit(sink); prefix.emit(sink);
match mem_e { match mem_e {
Addr::ImmReg { simm32, base } => { Addr::ImmReg { simm32, base } => {
// First, cook up the REX byte. This is easy. // First, the REX byte.
let enc_e = int_reg_enc(*base); let enc_e = int_reg_enc(*base);
let w = if clear_rex_w { 0 } else { 1 }; rex.emit_two_op(sink, enc_g, enc_e);
let r = (enc_g >> 3) & 1;
let x = 0;
let b = (enc_e >> 3) & 1;
let rex = 0x40 | (w << 3) | (r << 2) | (x << 1) | b;
if rex != 0x40 || retain_redundant {
sink.put1(rex);
}
// Now the opcode(s). These include any other prefixes the caller // Now the opcode(s). These include any other prefixes the caller
// hands to us. // hands to us.
@@ -220,14 +232,7 @@ fn emit_modrm_sib_enc_ge(
let enc_index = int_reg_enc(*reg_index); let enc_index = int_reg_enc(*reg_index);
// The rex byte. // The rex byte.
let w = if clear_rex_w { 0 } else { 1 }; rex.emit_three_op(sink, enc_g, enc_index, enc_base);
let r = (enc_g >> 3) & 1;
let x = (enc_index >> 3) & 1;
let b = (enc_base >> 3) & 1;
let rex = 0x40 | (w << 3) | (r << 2) | (x << 1) | b;
if rex != 0x40 || retain_redundant {
sink.put1(rex);
}
// All other prefixes and opcodes. // All other prefixes and opcodes.
while num_opcodes > 0 { while num_opcodes > 0 {
@@ -268,21 +273,12 @@ fn emit_modrm_enc_ge(
// don't even have to be from the same class. For example, for an // don't even have to be from the same class. For example, for an
// integer-to-FP conversion insn, one might be RegClass::I64 and the other // integer-to-FP conversion insn, one might be RegClass::I64 and the other
// RegClass::V128. // RegClass::V128.
let clear_rex_w = rex.must_clear_w();
let retain_redundant = rex.must_always_emit();
// The operand-size override. // The operand-size override.
prefix.emit(sink); prefix.emit(sink);
// The rex byte. // The rex byte.
let w = if clear_rex_w { 0 } else { 1 }; rex.emit_two_op(sink, enc_g, enc_e);
let r = (enc_g >> 3) & 1;
let x = 0;
let b = (enc_e >> 3) & 1;
let rex = 0x40 | (w << 3) | (r << 2) | (x << 1) | b;
if rex != 0x40 || retain_redundant {
sink.put1(rex);
}
// All other prefixes and opcodes. // All other prefixes and opcodes.
while num_opcodes > 0 { while num_opcodes > 0 {