Review comments;

This commit is contained in:
Benjamin Bouvier
2020-06-11 18:46:46 +02:00
parent 28c40ba0f7
commit 357fb11f46
2 changed files with 126 additions and 112 deletions

View File

@@ -216,6 +216,8 @@ pub enum SseOpcode {
Addsd, Addsd,
Comiss, Comiss,
Comisd, Comisd,
Cmpss,
Cmpsd,
Cvtsd2ss, Cvtsd2ss,
Cvtsd2si, Cvtsd2si,
Cvtsi2ss, Cvtsi2ss,
@@ -226,6 +228,7 @@ pub enum SseOpcode {
Cvttsd2si, Cvttsd2si,
Divss, Divss,
Divsd, Divsd,
Insertps,
Maxss, Maxss,
Maxsd, Maxsd,
Minss, Minss,
@@ -265,7 +268,8 @@ impl SseOpcode {
| SseOpcode::Subss | SseOpcode::Subss
| SseOpcode::Ucomiss | SseOpcode::Ucomiss
| SseOpcode::Sqrtss | SseOpcode::Sqrtss
| SseOpcode::Comiss => SSE, | SseOpcode::Comiss
| SseOpcode::Cmpss => SSE,
SseOpcode::Addsd SseOpcode::Addsd
| SseOpcode::Cvtsd2ss | SseOpcode::Cvtsd2ss
@@ -281,9 +285,10 @@ impl SseOpcode {
| SseOpcode::Sqrtsd | SseOpcode::Sqrtsd
| SseOpcode::Subsd | SseOpcode::Subsd
| SseOpcode::Ucomisd | SseOpcode::Ucomisd
| SseOpcode::Comisd => SSE2, | SseOpcode::Comisd
| SseOpcode::Cmpsd => SSE2,
SseOpcode::Roundss | SseOpcode::Roundsd => SSE41, SseOpcode::Insertps | SseOpcode::Roundss | SseOpcode::Roundsd => SSE41,
} }
} }
@@ -333,6 +338,9 @@ impl fmt::Debug for SseOpcode {
SseOpcode::Subsd => "subsd", SseOpcode::Subsd => "subsd",
SseOpcode::Ucomiss => "ucomiss", SseOpcode::Ucomiss => "ucomiss",
SseOpcode::Ucomisd => "ucomisd", SseOpcode::Ucomisd => "ucomisd",
SseOpcode::Cmpss => "cmpss",
SseOpcode::Cmpsd => "cmpsd",
SseOpcode::Insertps => "insertps",
}; };
write!(fmt, "{}", name) write!(fmt, "{}", name)
} }
@@ -344,26 +352,6 @@ impl ToString for SseOpcode {
} }
} }
/// Some SSE operations requiring 3 operands i, r/m, and r.
#[derive(Clone, PartialEq)]
pub enum SseRmiOpcode {
Cmpss,
Cmpsd,
Insertps,
}
impl SseRmiOpcode {
/// Which `InstructionSet` is the first supporting this opcode?
pub(crate) fn available_from(&self) -> InstructionSet {
use InstructionSet::*;
match self {
SseRmiOpcode::Cmpss => SSE,
SseRmiOpcode::Cmpsd => SSE2,
SseRmiOpcode::Insertps => SSE41,
}
}
}
/// These indicate ways of extending (widening) a value, using the Intel /// These indicate ways of extending (widening) a value, using the Intel
/// naming: B(yte) = u8, W(ord) = u16, L(ong)word = u32, Q(uad)word = u64 /// naming: B(yte) = u8, W(ord) = u16, L(ong)word = u32, Q(uad)word = u64
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]

View File

@@ -56,9 +56,9 @@ fn reg_enc(reg: Reg) -> u8 {
/// - bit 1 set to 1 indicates the REX prefix must always be emitted. /// - bit 1 set to 1 indicates the REX prefix must always be emitted.
#[repr(transparent)] #[repr(transparent)]
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
struct Rex(u8); struct RexFlags(u8);
impl Rex { impl RexFlags {
/// By default, set the W field, and don't always emit. /// By default, set the W field, and don't always emit.
#[inline(always)] #[inline(always)]
fn set_w() -> Self { fn set_w() -> Self {
@@ -111,7 +111,7 @@ impl 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
/// be used at the start an instruction. A select prefix may be required for /// be used at the start an instruction. A given prefix may be required for
/// various operations, including instructions that operate on GPR, SSE, and Vex /// various operations, including instructions that operate on GPR, SSE, and Vex
/// registers. /// registers.
enum LegacyPrefix { enum LegacyPrefix {
@@ -135,31 +135,37 @@ impl LegacyPrefix {
/// This is the core 'emit' function for instructions that reference memory. /// This is the core 'emit' function for instructions that reference memory.
/// ///
/// For an instruction that has as operands a register `enc_g` and a memory /// For an instruction that has as operands a reg encoding `enc_g` and a memory address `mem_e`,
/// address `memE`, create and emit, first the REX prefix, then caller-supplied /// create and emit:
/// opcode byte(s) (`opcodes` and `num_opcodes`), then the MOD/RM byte, then /// - first the REX prefix,
/// optionally, a SIB byte, and finally optionally an immediate that will be /// - then caller-supplied opcode byte(s) (`opcodes` and `num_opcodes`),
/// derived from the `memE` operand. For most instructions up to and including /// - then the MOD/RM byte,
/// SSE4.2, that will be the whole instruction. /// - then optionally, a SIB byte,
/// - and finally optionally an immediate that will be derived from the `mem_e` operand.
/// ///
/// The opcodes are written bigendianly for the convenience of callers. For /// For most instructions up to and including SSE4.2, that will be the whole instruction: this is
/// example, if the opcode bytes to be emitted are, in this order, F3 0F 27, /// what we call "standard" instructions, and abbreviate "std" in the name here. VEX instructions
/// then the caller should pass `opcodes` == 0xF3_0F_27 and `num_opcodes` == 3. /// will require their own emitter functions.
/// ///
/// The register operand is represented here not as a `Reg` but as its hardware /// This will also work for 32-bits x86 instructions, assuming no REX prefix is provided.
/// encoding, `enc_g`. `rex` can specify special handling for the REX prefix. ///
/// By default, the REX prefix will indicate a 64-bit operation and will be /// The opcodes are written bigendianly for the convenience of callers. For example, if the opcode
/// deleted if it is redundant (0x40). Note that for a 64-bit operation, the /// bytes to be emitted are, in this order, F3 0F 27, then the caller should pass `opcodes` ==
/// REX prefix will normally never be redundant, since REX.W must be 1 to /// 0xF3_0F_27 and `num_opcodes` == 3.
///
/// The register operand is represented here not as a `Reg` but as its hardware encoding, `enc_g`.
/// `rex` can specify special handling for the REX prefix. By default, the REX prefix will
/// indicate a 64-bit operation and will be deleted if it is redundant (0x40). Note that for a
/// 64-bit operation, the REX prefix will normally never be redundant, since REX.W must be 1 to
/// indicate a 64-bit operation. /// indicate a 64-bit operation.
fn emit_modrm_sib_enc_ge( fn emit_std_enc_mem(
sink: &mut MachBuffer<Inst>, sink: &mut MachBuffer<Inst>,
prefix: LegacyPrefix, prefix: LegacyPrefix,
opcodes: u32, opcodes: u32,
mut num_opcodes: usize, mut num_opcodes: usize,
enc_g: u8, enc_g: u8,
mem_e: &Addr, mem_e: &Addr,
rex: Rex, rex: RexFlags,
) { ) {
// General comment for this function: the registers in `mem_e` 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
@@ -260,14 +266,14 @@ fn emit_modrm_sib_enc_ge(
/// ///
/// This is conceptually the same as emit_modrm_sib_enc_ge, except it is for the case where the E /// This is conceptually the same as emit_modrm_sib_enc_ge, except it is for the case where the E
/// operand is a register rather than memory. Hence it is much simpler. /// operand is a register rather than memory. Hence it is much simpler.
fn emit_modrm_enc_ge( fn emit_std_enc_enc(
sink: &mut MachBuffer<Inst>, sink: &mut MachBuffer<Inst>,
prefix: LegacyPrefix, prefix: LegacyPrefix,
opcodes: u32, opcodes: u32,
mut num_opcodes: usize, mut num_opcodes: usize,
enc_g: u8, enc_g: u8,
enc_e: u8, enc_e: u8,
rex: Rex, rex: RexFlags,
) { ) {
// EncG and EncE can be derived from registers of any class, and they // EncG and EncE can be derived from registers of any class, and they
// 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
@@ -294,31 +300,31 @@ fn emit_modrm_enc_ge(
// These are merely wrappers for the above two functions that facilitate passing // These are merely wrappers for the above two functions that facilitate passing
// actual `Reg`s rather than their encodings. // actual `Reg`s rather than their encodings.
fn emit_modrm_sib_rm_ge( fn emit_std_reg_mem(
sink: &mut MachBuffer<Inst>, sink: &mut MachBuffer<Inst>,
prefix: LegacyPrefix, prefix: LegacyPrefix,
opcodes: u32, opcodes: u32,
num_opcodes: usize, num_opcodes: usize,
reg_g: Reg, reg_g: Reg,
mem_e: &Addr, mem_e: &Addr,
rex: Rex, rex: RexFlags,
) { ) {
let enc_g = reg_enc(reg_g); let enc_g = reg_enc(reg_g);
emit_modrm_sib_enc_ge(sink, prefix, opcodes, num_opcodes, enc_g, mem_e, rex); emit_std_enc_mem(sink, prefix, opcodes, num_opcodes, enc_g, mem_e, rex);
} }
fn emit_modrm_reg_ge( fn emit_std_reg_reg(
sink: &mut MachBuffer<Inst>, sink: &mut MachBuffer<Inst>,
prefix: LegacyPrefix, prefix: LegacyPrefix,
opcodes: u32, opcodes: u32,
num_opcodes: usize, num_opcodes: usize,
reg_g: Reg, reg_g: Reg,
reg_e: Reg, reg_e: Reg,
rex: Rex, rex: RexFlags,
) { ) {
let enc_g = reg_enc(reg_g); let enc_g = reg_enc(reg_g);
let enc_e = reg_enc(reg_e); let enc_e = reg_enc(reg_e);
emit_modrm_enc_ge(sink, prefix, opcodes, num_opcodes, enc_g, enc_e, rex); emit_std_enc_enc(sink, prefix, opcodes, num_opcodes, enc_g, enc_e, rex);
} }
/// Write a suitable number of bits from an imm64 to the sink. /// Write a suitable number of bits from an imm64 to the sink.
@@ -393,14 +399,18 @@ pub(crate) fn emit(inst: &Inst, sink: &mut MachBuffer<Inst>) {
src, src,
dst: reg_g, dst: reg_g,
} => { } => {
let rex = if *is_64 { Rex::set_w() } else { Rex::clear_w() }; let rex = if *is_64 {
RexFlags::set_w()
} else {
RexFlags::clear_w()
};
if *op == AluRmiROpcode::Mul { if *op == AluRmiROpcode::Mul {
// We kinda freeloaded Mul into RMI_R_Op, but it doesn't fit the usual pattern, so // We kinda freeloaded Mul into RMI_R_Op, but it doesn't fit the usual pattern, so
// we have to special-case it. // we have to special-case it.
match src { match src {
RegMemImm::Reg { reg: reg_e } => { RegMemImm::Reg { reg: reg_e } => {
emit_modrm_reg_ge( emit_std_reg_reg(
sink, sink,
LegacyPrefix::None, LegacyPrefix::None,
0x0FAF, 0x0FAF,
@@ -412,7 +422,7 @@ pub(crate) fn emit(inst: &Inst, sink: &mut MachBuffer<Inst>) {
} }
RegMemImm::Mem { addr } => { RegMemImm::Mem { addr } => {
emit_modrm_sib_rm_ge( emit_std_reg_mem(
sink, sink,
LegacyPrefix::None, LegacyPrefix::None,
0x0FAF, 0x0FAF,
@@ -427,7 +437,7 @@ pub(crate) fn emit(inst: &Inst, sink: &mut MachBuffer<Inst>) {
let useImm8 = low8_will_sign_extend_to_32(*simm32); let useImm8 = low8_will_sign_extend_to_32(*simm32);
let opcode = if useImm8 { 0x6B } else { 0x69 }; let opcode = if useImm8 { 0x6B } else { 0x69 };
// Yes, really, reg_g twice. // Yes, really, reg_g twice.
emit_modrm_reg_ge( emit_std_reg_reg(
sink, sink,
LegacyPrefix::None, LegacyPrefix::None,
opcode, opcode,
@@ -462,7 +472,7 @@ pub(crate) fn emit(inst: &Inst, sink: &mut MachBuffer<Inst>) {
// the GNU as reference output. In other words, the // the GNU as reference output. In other words, the
// inversion exists as a result of using GNU as as a // inversion exists as a result of using GNU as as a
// gold standard. // gold standard.
emit_modrm_reg_ge( emit_std_reg_reg(
sink, sink,
LegacyPrefix::None, LegacyPrefix::None,
opcode_r, opcode_r,
@@ -477,7 +487,7 @@ pub(crate) fn emit(inst: &Inst, sink: &mut MachBuffer<Inst>) {
RegMemImm::Mem { addr } => { RegMemImm::Mem { addr } => {
// Whereas here we revert to the "normal" G-E ordering. // Whereas here we revert to the "normal" G-E ordering.
emit_modrm_sib_rm_ge( emit_std_reg_mem(
sink, sink,
LegacyPrefix::None, LegacyPrefix::None,
opcode_m, opcode_m,
@@ -493,7 +503,7 @@ pub(crate) fn emit(inst: &Inst, sink: &mut MachBuffer<Inst>) {
let opcode = if useImm8 { 0x83 } else { 0x81 }; let opcode = if useImm8 { 0x83 } else { 0x81 };
// And also here we use the "normal" G-E ordering. // And also here we use the "normal" G-E ordering.
let enc_g = int_reg_enc(reg_g.to_reg()); let enc_g = int_reg_enc(reg_g.to_reg());
emit_modrm_enc_ge( emit_std_enc_enc(
sink, sink,
LegacyPrefix::None, LegacyPrefix::None,
opcode, opcode,
@@ -530,22 +540,26 @@ pub(crate) fn emit(inst: &Inst, sink: &mut MachBuffer<Inst>) {
} }
Inst::Mov_R_R { is_64, src, dst } => { Inst::Mov_R_R { is_64, src, dst } => {
let rex = if *is_64 { Rex::set_w() } else { Rex::clear_w() }; let rex = if *is_64 {
emit_modrm_reg_ge(sink, LegacyPrefix::None, 0x89, 1, *src, dst.to_reg(), rex); RexFlags::set_w()
} else {
RexFlags::clear_w()
};
emit_std_reg_reg(sink, LegacyPrefix::None, 0x89, 1, *src, dst.to_reg(), rex);
} }
Inst::MovZX_M_R { extMode, addr, dst } => { Inst::MovZX_M_R { extMode, addr, dst } => {
match extMode { match extMode {
ExtMode::BL => { ExtMode::BL => {
// MOVZBL is (REX.W==0) 0F B6 /r // MOVZBL is (REX.W==0) 0F B6 /r
emit_modrm_sib_rm_ge( emit_std_reg_mem(
sink, sink,
LegacyPrefix::None, LegacyPrefix::None,
0x0FB6, 0x0FB6,
2, 2,
dst.to_reg(), dst.to_reg(),
addr, addr,
Rex::clear_w(), RexFlags::clear_w(),
) )
} }
@@ -555,40 +569,40 @@ pub(crate) fn emit(inst: &Inst, sink: &mut MachBuffer<Inst>) {
// encodings for MOVZBQ than for MOVZBL. AIUI they should // encodings for MOVZBQ than for MOVZBL. AIUI they should
// achieve the same, since MOVZBL is just going to zero out // achieve the same, since MOVZBL is just going to zero out
// the upper half of the destination anyway. // the upper half of the destination anyway.
emit_modrm_sib_rm_ge( emit_std_reg_mem(
sink, sink,
LegacyPrefix::None, LegacyPrefix::None,
0x0FB6, 0x0FB6,
2, 2,
dst.to_reg(), dst.to_reg(),
addr, addr,
Rex::set_w(), RexFlags::set_w(),
) )
} }
ExtMode::WL => { ExtMode::WL => {
// MOVZWL is (REX.W==0) 0F B7 /r // MOVZWL is (REX.W==0) 0F B7 /r
emit_modrm_sib_rm_ge( emit_std_reg_mem(
sink, sink,
LegacyPrefix::None, LegacyPrefix::None,
0x0FB7, 0x0FB7,
2, 2,
dst.to_reg(), dst.to_reg(),
addr, addr,
Rex::clear_w(), RexFlags::clear_w(),
) )
} }
ExtMode::WQ => { ExtMode::WQ => {
// MOVZWQ is (REX.W==1) 0F B7 /r // MOVZWQ is (REX.W==1) 0F B7 /r
emit_modrm_sib_rm_ge( emit_std_reg_mem(
sink, sink,
LegacyPrefix::None, LegacyPrefix::None,
0x0FB7, 0x0FB7,
2, 2,
dst.to_reg(), dst.to_reg(),
addr, addr,
Rex::set_w(), RexFlags::set_w(),
) )
} }
@@ -596,93 +610,93 @@ pub(crate) fn emit(inst: &Inst, sink: &mut MachBuffer<Inst>) {
// This is just a standard 32 bit load, and we rely on the // This is just a standard 32 bit load, and we rely on the
// default zero-extension rule to perform the extension. // default zero-extension rule to perform the extension.
// MOV r/m32, r32 is (REX.W==0) 8B /r // MOV r/m32, r32 is (REX.W==0) 8B /r
emit_modrm_sib_rm_ge( emit_std_reg_mem(
sink, sink,
LegacyPrefix::None, LegacyPrefix::None,
0x8B, 0x8B,
1, 1,
dst.to_reg(), dst.to_reg(),
addr, addr,
Rex::clear_w(), RexFlags::clear_w(),
) )
} }
} }
} }
Inst::Mov64_M_R { addr, dst } => emit_modrm_sib_rm_ge( Inst::Mov64_M_R { addr, dst } => emit_std_reg_mem(
sink, sink,
LegacyPrefix::None, LegacyPrefix::None,
0x8B, 0x8B,
1, 1,
dst.to_reg(), dst.to_reg(),
addr, addr,
Rex::set_w(), RexFlags::set_w(),
), ),
Inst::MovSX_M_R { extMode, addr, dst } => { Inst::MovSX_M_R { extMode, addr, dst } => {
match extMode { match extMode {
ExtMode::BL => { ExtMode::BL => {
// MOVSBL is (REX.W==0) 0F BE /r // MOVSBL is (REX.W==0) 0F BE /r
emit_modrm_sib_rm_ge( emit_std_reg_mem(
sink, sink,
LegacyPrefix::None, LegacyPrefix::None,
0x0FBE, 0x0FBE,
2, 2,
dst.to_reg(), dst.to_reg(),
addr, addr,
Rex::clear_w(), RexFlags::clear_w(),
) )
} }
ExtMode::BQ => { ExtMode::BQ => {
// MOVSBQ is (REX.W==1) 0F BE /r // MOVSBQ is (REX.W==1) 0F BE /r
emit_modrm_sib_rm_ge( emit_std_reg_mem(
sink, sink,
LegacyPrefix::None, LegacyPrefix::None,
0x0FBE, 0x0FBE,
2, 2,
dst.to_reg(), dst.to_reg(),
addr, addr,
Rex::set_w(), RexFlags::set_w(),
) )
} }
ExtMode::WL => { ExtMode::WL => {
// MOVSWL is (REX.W==0) 0F BF /r // MOVSWL is (REX.W==0) 0F BF /r
emit_modrm_sib_rm_ge( emit_std_reg_mem(
sink, sink,
LegacyPrefix::None, LegacyPrefix::None,
0x0FBF, 0x0FBF,
2, 2,
dst.to_reg(), dst.to_reg(),
addr, addr,
Rex::clear_w(), RexFlags::clear_w(),
) )
} }
ExtMode::WQ => { ExtMode::WQ => {
// MOVSWQ is (REX.W==1) 0F BF /r // MOVSWQ is (REX.W==1) 0F BF /r
emit_modrm_sib_rm_ge( emit_std_reg_mem(
sink, sink,
LegacyPrefix::None, LegacyPrefix::None,
0x0FBF, 0x0FBF,
2, 2,
dst.to_reg(), dst.to_reg(),
addr, addr,
Rex::set_w(), RexFlags::set_w(),
) )
} }
ExtMode::LQ => { ExtMode::LQ => {
// MOVSLQ is (REX.W==1) 63 /r // MOVSLQ is (REX.W==1) 63 /r
emit_modrm_sib_rm_ge( emit_std_reg_mem(
sink, sink,
LegacyPrefix::None, LegacyPrefix::None,
0x63, 0x63,
1, 1,
dst.to_reg(), dst.to_reg(),
addr, addr,
Rex::set_w(), RexFlags::set_w(),
) )
} }
} }
@@ -694,7 +708,7 @@ pub(crate) fn emit(inst: &Inst, sink: &mut MachBuffer<Inst>) {
// This is one of the few places where the presence of a // This is one of the few places where the presence of a
// redundant REX prefix changes the meaning of the // redundant REX prefix changes the meaning of the
// instruction. // instruction.
let mut rex = Rex::clear_w(); let mut rex = RexFlags::clear_w();
let enc_src = int_reg_enc(*src); let enc_src = int_reg_enc(*src);
if enc_src >= 4 && enc_src <= 7 { if enc_src >= 4 && enc_src <= 7 {
@@ -702,45 +716,45 @@ pub(crate) fn emit(inst: &Inst, sink: &mut MachBuffer<Inst>) {
}; };
// MOV r8, r/m8 is (REX.W==0) 88 /r // MOV r8, r/m8 is (REX.W==0) 88 /r
emit_modrm_sib_rm_ge(sink, LegacyPrefix::None, 0x88, 1, *src, addr, rex) emit_std_reg_mem(sink, LegacyPrefix::None, 0x88, 1, *src, addr, rex)
} }
2 => { 2 => {
// MOV r16, r/m16 is 66 (REX.W==0) 89 /r // MOV r16, r/m16 is 66 (REX.W==0) 89 /r
emit_modrm_sib_rm_ge( emit_std_reg_mem(
sink, sink,
LegacyPrefix::_66, LegacyPrefix::_66,
0x89, 0x89,
1, 1,
*src, *src,
addr, addr,
Rex::clear_w(), RexFlags::clear_w(),
) )
} }
4 => { 4 => {
// MOV r32, r/m32 is (REX.W==0) 89 /r // MOV r32, r/m32 is (REX.W==0) 89 /r
emit_modrm_sib_rm_ge( emit_std_reg_mem(
sink, sink,
LegacyPrefix::None, LegacyPrefix::None,
0x89, 0x89,
1, 1,
*src, *src,
addr, addr,
Rex::clear_w(), RexFlags::clear_w(),
) )
} }
8 => { 8 => {
// MOV r64, r/m64 is (REX.W==1) 89 /r // MOV r64, r/m64 is (REX.W==1) 89 /r
emit_modrm_sib_rm_ge( emit_std_reg_mem(
sink, sink,
LegacyPrefix::None, LegacyPrefix::None,
0x89, 0x89,
1, 1,
*src, *src,
addr, addr,
Rex::set_w(), RexFlags::set_w(),
) )
} }
@@ -761,13 +775,17 @@ pub(crate) fn emit(inst: &Inst, sink: &mut MachBuffer<Inst>) {
ShiftKind::RightS => 7, ShiftKind::RightS => 7,
}; };
let rex = if *is_64 { Rex::set_w() } else { Rex::clear_w() }; let rex = if *is_64 {
RexFlags::set_w()
} else {
RexFlags::clear_w()
};
match num_bits { match num_bits {
None => { None => {
// SHL/SHR/SAR %cl, reg32 is (REX.W==0) D3 /subopcode // SHL/SHR/SAR %cl, reg32 is (REX.W==0) D3 /subopcode
// SHL/SHR/SAR %cl, reg64 is (REX.W==1) D3 /subopcode // SHL/SHR/SAR %cl, reg64 is (REX.W==1) D3 /subopcode
emit_modrm_enc_ge(sink, LegacyPrefix::None, 0xD3, 1, subopcode, enc_dst, rex); emit_std_enc_enc(sink, LegacyPrefix::None, 0xD3, 1, subopcode, enc_dst, rex);
} }
Some(num_bits) => { Some(num_bits) => {
@@ -775,7 +793,7 @@ pub(crate) fn emit(inst: &Inst, sink: &mut MachBuffer<Inst>) {
// SHL/SHR/SAR $ib, reg64 is (REX.W==1) C1 /subopcode ib // SHL/SHR/SAR $ib, reg64 is (REX.W==1) C1 /subopcode ib
// When the shift amount is 1, there's an even shorter encoding, but we don't // When the shift amount is 1, there's an even shorter encoding, but we don't
// bother with that nicety here. // bother with that nicety here.
emit_modrm_enc_ge(sink, LegacyPrefix::None, 0xC1, 1, subopcode, enc_dst, rex); emit_std_enc_enc(sink, LegacyPrefix::None, 0xC1, 1, subopcode, enc_dst, rex);
sink.put1(*num_bits); sink.put1(*num_bits);
} }
} }
@@ -792,10 +810,10 @@ pub(crate) fn emit(inst: &Inst, sink: &mut MachBuffer<Inst>) {
} }
let mut rex = match size { let mut rex = match size {
8 => Rex::set_w(), 8 => RexFlags::set_w(),
4 | 2 => Rex::clear_w(), 4 | 2 => RexFlags::clear_w(),
1 => { 1 => {
let mut rex = Rex::clear_w(); let mut rex = RexFlags::clear_w();
// Here, a redundant REX prefix changes the meaning of the instruction. // Here, a redundant REX prefix changes the meaning of the instruction.
let enc_g = int_reg_enc(*reg_g); let enc_g = int_reg_enc(*reg_g);
if enc_g >= 4 && enc_g <= 7 { if enc_g >= 4 && enc_g <= 7 {
@@ -818,13 +836,13 @@ pub(crate) fn emit(inst: &Inst, sink: &mut MachBuffer<Inst>) {
} }
} }
// Same comment re swapped args as for Alu_RMI_R. // Same comment re swapped args as for Alu_RMI_R.
emit_modrm_reg_ge(sink, prefix, opcode, 1, *regE, *reg_g, rex); emit_std_reg_reg(sink, prefix, opcode, 1, *regE, *reg_g, rex);
} }
RegMemImm::Mem { addr } => { RegMemImm::Mem { addr } => {
let opcode = if *size == 1 { 0x3A } else { 0x3B }; let opcode = if *size == 1 { 0x3A } else { 0x3B };
// Whereas here we revert to the "normal" G-E ordering. // Whereas here we revert to the "normal" G-E ordering.
emit_modrm_sib_rm_ge(sink, prefix, opcode, 1, *reg_g, addr, rex); emit_std_reg_mem(sink, prefix, opcode, 1, *reg_g, addr, rex);
} }
RegMemImm::Imm { simm32 } => { RegMemImm::Imm { simm32 } => {
@@ -841,7 +859,7 @@ pub(crate) fn emit(inst: &Inst, sink: &mut MachBuffer<Inst>) {
// And also here we use the "normal" G-E ordering. // And also here we use the "normal" G-E ordering.
let enc_g = int_reg_enc(*reg_g); let enc_g = int_reg_enc(*reg_g);
emit_modrm_enc_ge(sink, prefix, opcode, 1, 7 /*subopcode*/, enc_g, rex); emit_std_enc_enc(sink, prefix, opcode, 1, 7 /*subopcode*/, enc_g, rex);
emit_simm(sink, if use_imm8 { 1 } else { *size }, *simm32); emit_simm(sink, if use_imm8 { 1 } else { *size }, *simm32);
} }
} }
@@ -859,14 +877,14 @@ pub(crate) fn emit(inst: &Inst, sink: &mut MachBuffer<Inst>) {
} }
RegMemImm::Mem { addr } => { RegMemImm::Mem { addr } => {
emit_modrm_sib_enc_ge( emit_std_enc_mem(
sink, sink,
LegacyPrefix::None, LegacyPrefix::None,
0xFF, 0xFF,
1, 1,
6, /*subopcode*/ 6, /*subopcode*/
addr, addr,
Rex::clear_w(), RexFlags::clear_w(),
); );
} }
@@ -896,26 +914,26 @@ pub(crate) fn emit(inst: &Inst, sink: &mut MachBuffer<Inst>) {
match dest { match dest {
RegMem::Reg { reg } => { RegMem::Reg { reg } => {
let reg_enc = int_reg_enc(*reg); let reg_enc = int_reg_enc(*reg);
emit_modrm_enc_ge( emit_std_enc_enc(
sink, sink,
LegacyPrefix::None, LegacyPrefix::None,
0xFF, 0xFF,
1, 1,
2, /*subopcode*/ 2, /*subopcode*/
reg_enc, reg_enc,
Rex::clear_w(), RexFlags::clear_w(),
); );
} }
RegMem::Mem { addr } => { RegMem::Mem { addr } => {
emit_modrm_sib_enc_ge( emit_std_enc_mem(
sink, sink,
LegacyPrefix::None, LegacyPrefix::None,
0xFF, 0xFF,
1, 1,
2, /*subopcode*/ 2, /*subopcode*/
addr, addr,
Rex::clear_w(), RexFlags::clear_w(),
); );
} }
} }
@@ -982,26 +1000,26 @@ pub(crate) fn emit(inst: &Inst, sink: &mut MachBuffer<Inst>) {
match target { match target {
RegMem::Reg { reg } => { RegMem::Reg { reg } => {
let reg_enc = int_reg_enc(*reg); let reg_enc = int_reg_enc(*reg);
emit_modrm_enc_ge( emit_std_enc_enc(
sink, sink,
LegacyPrefix::None, LegacyPrefix::None,
0xFF, 0xFF,
1, 1,
4, /*subopcode*/ 4, /*subopcode*/
reg_enc, reg_enc,
Rex::clear_w(), RexFlags::clear_w(),
); );
} }
RegMem::Mem { addr } => { RegMem::Mem { addr } => {
emit_modrm_sib_enc_ge( emit_std_enc_mem(
sink, sink,
LegacyPrefix::None, LegacyPrefix::None,
0xFF, 0xFF,
1, 1,
4, /*subopcode*/ 4, /*subopcode*/
addr, addr,
Rex::clear_w(), RexFlags::clear_w(),
); );
} }
} }
@@ -1020,7 +1038,15 @@ pub(crate) fn emit(inst: &Inst, sink: &mut MachBuffer<Inst>) {
_ => unimplemented!("XMM_R_R opcode"), _ => unimplemented!("XMM_R_R opcode"),
}; };
emit_modrm_reg_ge(sink, prefix, opcode, 2, dst.to_reg(), *src, Rex::clear_w()); emit_std_reg_reg(
sink,
prefix,
opcode,
2,
dst.to_reg(),
*src,
RexFlags::clear_w(),
);
} }
Inst::XMM_RM_R { Inst::XMM_RM_R {
@@ -1028,7 +1054,7 @@ pub(crate) fn emit(inst: &Inst, sink: &mut MachBuffer<Inst>) {
src: srcE, src: srcE,
dst: reg_g, dst: reg_g,
} => { } => {
let rex = Rex::clear_w(); let rex = RexFlags::clear_w();
let opcode = match op { let opcode = match op {
SseOpcode::Addss => 0x0F58, SseOpcode::Addss => 0x0F58,
@@ -1038,7 +1064,7 @@ pub(crate) fn emit(inst: &Inst, sink: &mut MachBuffer<Inst>) {
match srcE { match srcE {
RegMem::Reg { reg: regE } => { RegMem::Reg { reg: regE } => {
emit_modrm_reg_ge( emit_std_reg_reg(
sink, sink,
LegacyPrefix::_F3, LegacyPrefix::_F3,
opcode, opcode,
@@ -1050,7 +1076,7 @@ pub(crate) fn emit(inst: &Inst, sink: &mut MachBuffer<Inst>) {
} }
RegMem::Mem { addr } => { RegMem::Mem { addr } => {
emit_modrm_sib_rm_ge( emit_std_reg_mem(
sink, sink,
LegacyPrefix::_F3, LegacyPrefix::_F3,
opcode, opcode,