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,15 +847,28 @@ pub(crate) fn emit(
}; };
match src { match src {
RegMem::Reg { reg: src } => emit_std_reg_reg( RegMem::Reg { reg: src } => {
sink, match ext_mode {
LegacyPrefix::None, ExtMode::BL | ExtMode::BQ => {
opcodes, // A redundant REX prefix must be emitted for certain register inputs.
num_opcodes, let enc_src = int_reg_enc(*src);
dst.to_reg(), if enc_src >= 4 && enc_src <= 7 {
*src, rex_flags.always_emit();
rex_flags, };
), }
_ => {}
}
emit_std_reg_reg(
sink,
LegacyPrefix::None,
opcodes,
num_opcodes,
dst.to_reg(),
*src,
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,15 +949,27 @@ pub(crate) fn emit(
}; };
match src { match src {
RegMem::Reg { reg: src } => emit_std_reg_reg( RegMem::Reg { reg: src } => {
sink, match ext_mode {
LegacyPrefix::None, ExtMode::BL | ExtMode::BQ => {
opcodes, // A redundant REX prefix must be emitted for certain register inputs.
num_opcodes, let enc_src = int_reg_enc(*src);
dst.to_reg(), if enc_src >= 4 && enc_src <= 7 {
*src, rex_flags.always_emit();
rex_flags, };
), }
_ => {}
}
emit_std_reg_reg(
sink,
LegacyPrefix::None,
opcodes,
num_opcodes,
dst.to_reg(),
*src,
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",