Browse Source

machinst x64: refactor REX prefix emission;

pull/1882/head
Benjamin Bouvier 4 years ago
parent
commit
48fb9291bc
  1. 62
      cranelift/codegen/src/isa/x64/inst/emit.rs

62
cranelift/codegen/src/isa/x64/inst/emit.rs

@ -76,17 +76,38 @@ impl Rex {
self
}
/// Return whether the W bit in the REX prefix is zero.
#[inline(always)]
fn must_clear_w(&self) -> bool {
(self.0 & 1) != 0
}
/// Return whether we need to emit the REX prefix byte even if it appears
/// to be redundant (== 0x40).
#[inline(always)]
fn must_always_emit(&self) -> bool {
(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
@ -140,26 +161,17 @@ fn emit_modrm_sib_enc_ge(
mem_e: &Addr,
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
// 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);
match mem_e {
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 w = if clear_rex_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 || retain_redundant {
sink.put1(rex);
}
rex.emit_two_op(sink, enc_g, enc_e);
// Now the opcode(s). These include any other prefixes the caller
// hands to us.
@ -220,14 +232,7 @@ fn emit_modrm_sib_enc_ge(
let enc_index = int_reg_enc(*reg_index);
// The rex byte.
let w = if clear_rex_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 || retain_redundant {
sink.put1(rex);
}
rex.emit_three_op(sink, enc_g, enc_index, enc_base);
// All other prefixes and opcodes.
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
// integer-to-FP conversion insn, one might be RegClass::I64 and the other
// RegClass::V128.
let clear_rex_w = rex.must_clear_w();
let retain_redundant = rex.must_always_emit();
// The operand-size override.
prefix.emit(sink);
// The rex byte.
let w = if clear_rex_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 || retain_redundant {
sink.put1(rex);
}
rex.emit_two_op(sink, enc_g, enc_e);
// All other prefixes and opcodes.
while num_opcodes > 0 {

Loading…
Cancel
Save