machinst x64: fix encoding of movzx/movsx with non-ABCD input registers;

Using an input register that doesn't belong to the ABCD family (al,
etc.) as the source of movsx/movzx requires a redundant REX prefix, that
was not emitted.
This commit is contained in:
Benjamin Bouvier
2020-07-23 14:12:12 +02:00
parent de4923356a
commit 2e3ad3227d
2 changed files with 55 additions and 20 deletions

View File

@@ -815,7 +815,7 @@ pub(crate) fn emit(
dst, dst,
srcloc, srcloc,
} => { } => {
let (opcodes, num_opcodes, rex_flags) = match ext_mode { let (opcodes, num_opcodes, mut rex_flags) = match ext_mode {
ExtMode::BL => { ExtMode::BL => {
// MOVZBL is (REX.W==0) 0F B6 /r // MOVZBL is (REX.W==0) 0F B6 /r
(0x0FB6, 2, RexFlags::clear_w()) (0x0FB6, 2, RexFlags::clear_w())
@@ -847,7 +847,18 @@ pub(crate) fn emit(
}; };
match src { match src {
RegMem::Reg { reg: src } => emit_std_reg_reg( RegMem::Reg { reg: src } => {
match ext_mode {
ExtMode::BL | ExtMode::BQ => {
// A redundant REX prefix must be emitted for certain register inputs.
let enc_src = int_reg_enc(*src);
if enc_src >= 4 && enc_src <= 7 {
rex_flags.always_emit();
};
}
_ => {}
}
emit_std_reg_reg(
sink, sink,
LegacyPrefix::None, LegacyPrefix::None,
opcodes, opcodes,
@@ -855,7 +866,9 @@ pub(crate) fn emit(
dst.to_reg(), dst.to_reg(),
*src, *src,
rex_flags, rex_flags,
), )
}
RegMem::Mem { addr: src } => { RegMem::Mem { addr: src } => {
let src = &src.finalize(state); let src = &src.finalize(state);
@@ -912,7 +925,7 @@ pub(crate) fn emit(
dst, dst,
srcloc, srcloc,
} => { } => {
let (opcodes, num_opcodes, rex_flags) = match ext_mode { let (opcodes, num_opcodes, mut rex_flags) = match ext_mode {
ExtMode::BL => { ExtMode::BL => {
// MOVSBL is (REX.W==0) 0F BE /r // MOVSBL is (REX.W==0) 0F BE /r
(0x0FBE, 2, RexFlags::clear_w()) (0x0FBE, 2, RexFlags::clear_w())
@@ -936,7 +949,18 @@ pub(crate) fn emit(
}; };
match src { match src {
RegMem::Reg { reg: src } => emit_std_reg_reg( RegMem::Reg { reg: src } => {
match ext_mode {
ExtMode::BL | ExtMode::BQ => {
// A redundant REX prefix must be emitted for certain register inputs.
let enc_src = int_reg_enc(*src);
if enc_src >= 4 && enc_src <= 7 {
rex_flags.always_emit();
};
}
_ => {}
}
emit_std_reg_reg(
sink, sink,
LegacyPrefix::None, LegacyPrefix::None,
opcodes, opcodes,
@@ -944,7 +968,8 @@ pub(crate) fn emit(
dst.to_reg(), dst.to_reg(),
*src, *src,
rex_flags, rex_flags,
), )
}
RegMem::Mem { addr: src } => { RegMem::Mem { addr: src } => {
let src = &src.finalize(state); let src = &src.finalize(state);

View File

@@ -1401,6 +1401,11 @@ fn test_x64_emit() {
// ======================================================== // ========================================================
// MovZX_RM_R // MovZX_RM_R
insns.push((
Inst::movzx_rm_r(ExtMode::BL, RegMem::reg(rdi), w_rdi, None),
"400FB6FF",
"movzbl %dil, %edi",
));
insns.push(( insns.push((
Inst::movzx_rm_r(ExtMode::BL, RegMem::reg(rax), w_rsi, None), Inst::movzx_rm_r(ExtMode::BL, RegMem::reg(rax), w_rsi, None),
"0FB6F0", "0FB6F0",
@@ -1723,6 +1728,11 @@ fn test_x64_emit() {
// ======================================================== // ========================================================
// MovSX_RM_R // MovSX_RM_R
insns.push((
Inst::movsx_rm_r(ExtMode::BL, RegMem::reg(rdi), w_rdi, None),
"400FBEFF",
"movsbl %dil, %edi",
));
insns.push(( insns.push((
Inst::movsx_rm_r(ExtMode::BL, RegMem::reg(rcx), w_rsi, None), Inst::movsx_rm_r(ExtMode::BL, RegMem::reg(rcx), w_rsi, None),
"0FBEF1", "0FBEF1",