diff --git a/Source/Core/Common/x64Emitter.cpp b/Source/Core/Common/x64Emitter.cpp index cc243810c1..f18ea9fd3a 100644 --- a/Source/Core/Common/x64Emitter.cpp +++ b/Source/Core/Common/x64Emitter.cpp @@ -1469,11 +1469,21 @@ void OpArg::WriteNormalOp(XEmitter* emit, bool toRM, NormalOp op, const OpArg& o // mov reg64, imm64 else if (op == NormalOp::MOV) { - emit->Write8(0xB8 + (offsetOrBaseReg & 7)); - emit->Write64((u64)operand.offset); - return; + // movabs reg64, imm64 (10 bytes) + if (static_cast(operand.offset) != static_cast(operand.offset)) + { + emit->Write8(0xB8 + (offsetOrBaseReg & 7)); + emit->Write64(operand.offset); + return; + } + // mov reg64, simm32 (7 bytes) + emit->Write8(op_def.imm32); + immToWrite = 32; + } + else + { + ASSERT_MSG(DYNA_REC, 0, "WriteNormalOp - Only MOV can take 64-bit imm"); } - ASSERT_MSG(DYNA_REC, 0, "WriteNormalOp - Only MOV can take 64-bit imm"); } else { @@ -1581,6 +1591,12 @@ void XEmitter::XOR(int bits, const OpArg& a1, const OpArg& a2) } void XEmitter::MOV(int bits, const OpArg& a1, const OpArg& a2) { + if (bits == 64 && a1.IsSimpleReg() && a2.scale == SCALE_IMM64 && + a2.offset == static_cast(a2.offset)) + { + WriteNormalOp(32, NormalOp::MOV, a1, a2.AsImm32()); + return; + } if (a1.IsSimpleReg() && a2.IsSimpleReg() && a1.GetSimpleReg() == a2.GetSimpleReg()) ERROR_LOG(DYNA_REC, "Redundant MOV @ %p - bug in JIT?", code); WriteNormalOp(bits, NormalOp::MOV, a1, a2); diff --git a/Source/UnitTests/Common/x64EmitterTest.cpp b/Source/UnitTests/Common/x64EmitterTest.cpp index 4de8bf99ad..ff0c64b876 100644 --- a/Source/UnitTests/Common/x64EmitterTest.cpp +++ b/Source/UnitTests/Common/x64EmitterTest.cpp @@ -35,7 +35,10 @@ const std::vector reg8names{ }; const std::vector reg8hnames{ - {AH, "ah"}, {BH, "bh"}, {CH, "ch"}, {DH, "dh"}, + {AH, "ah"}, + {BH, "bh"}, + {CH, "ch"}, + {DH, "dh"}, }; const std::vector reg16names{ @@ -306,10 +309,12 @@ TEST_F(x64EmitterTest, CMOVcc_Register) emitter->CMOVcc(32, RAX, R(R12), cc.cc); emitter->CMOVcc(16, RAX, R(R12), cc.cc); - ExpectDisassembly("cmov" + cc.name + " rax, r12 " - "cmov" + - cc.name + " eax, r12d " - "cmov" + + ExpectDisassembly("cmov" + cc.name + + " rax, r12 " + "cmov" + + cc.name + + " eax, r12d " + "cmov" + cc.name + " ax, r12w"); } } @@ -379,10 +384,12 @@ TEST_F(x64EmitterTest, MOVNT_DQ_PS_PD) emitter->MOVNTDQ(MatR(RAX), r.reg); emitter->MOVNTPS(MatR(RAX), r.reg); emitter->MOVNTPD(MatR(RAX), r.reg); - ExpectDisassembly("movntdq dqword ptr ds:[rax], " + r.name + " " - "movntps dqword ptr ds:[rax], " + - r.name + " " - "movntpd dqword ptr ds:[rax], " + + ExpectDisassembly("movntdq dqword ptr ds:[rax], " + r.name + + " " + "movntps dqword ptr ds:[rax], " + + r.name + + " " + "movntpd dqword ptr ds:[rax], " + r.name); } } @@ -547,6 +554,24 @@ TWO_OP_ARITH_TEST(OR) TWO_OP_ARITH_TEST(XOR) TWO_OP_ARITH_TEST(MOV) +TEST_F(x64EmitterTest, MOV_Imm64) +{ + for (size_t i = 0; i < reg64names.size(); i++) + { + emitter->MOV(64, R(reg64names[i].reg), Imm64(0xDEADBEEFDEADBEEF)); + EXPECT_EQ(emitter->GetCodePtr(), code_buffer + 10); + ExpectDisassembly("mov " + reg64names[i].name + ", 0xdeadbeefdeadbeef"); + + emitter->MOV(64, R(reg64names[i].reg), Imm64(0xFFFFFFFFDEADBEEF)); + EXPECT_EQ(emitter->GetCodePtr(), code_buffer + 7); + ExpectDisassembly("mov " + reg64names[i].name + ", 0xffffffffdeadbeef"); + + emitter->MOV(64, R(reg64names[i].reg), Imm64(0xDEADBEEF)); + EXPECT_EQ(emitter->GetCodePtr(), code_buffer + 5 + (i > 7)); + ExpectDisassembly("mov " + reg32names[i].name + ", 0xdeadbeef"); + } +} + // TODO: Disassembler inverts operands here. // TWO_OP_ARITH_TEST(XCHG) // TWO_OP_ARITH_TEST(TEST) @@ -558,7 +583,8 @@ TEST_F(x64EmitterTest, BSWAP) int bits; std::vector regs; } regsets[] = { - {32, reg32names}, {64, reg64names}, + {32, reg32names}, + {64, reg64names}, }; for (const auto& regset : regsets) for (const auto& r : regset.regs) @@ -871,7 +897,8 @@ TWO_OP_SSE_TEST(PMOVZXDQ, "qword") std::string out_name; \ std::string size; \ } regsets[] = { \ - {32, reg32names, "eax", "dword"}, {64, reg64names, "rax", "qword"}, \ + {32, reg32names, "eax", "dword"}, \ + {64, reg64names, "rax", "qword"}, \ }; \ for (const auto& regset : regsets) \ for (const auto& r : regset.regs) \ @@ -903,7 +930,8 @@ VEX_RMR_TEST(BZHI) std::string out_name; \ std::string size; \ } regsets[] = { \ - {32, reg32names, "eax", "dword"}, {64, reg64names, "rax", "qword"}, \ + {32, reg32names, "eax", "dword"}, \ + {64, reg64names, "rax", "qword"}, \ }; \ for (const auto& regset : regsets) \ for (const auto& r : regset.regs) \ @@ -934,7 +962,8 @@ VEX_RRM_TEST(ANDN) std::string out_name; \ std::string size; \ } regsets[] = { \ - {32, reg32names, "eax", "dword"}, {64, reg64names, "rax", "qword"}, \ + {32, reg32names, "eax", "dword"}, \ + {64, reg64names, "rax", "qword"}, \ }; \ for (const auto& regset : regsets) \ for (const auto& r : regset.regs) \ @@ -963,7 +992,8 @@ VEX_RM_TEST(BLSI) std::string out_name; \ std::string size; \ } regsets[] = { \ - {32, reg32names, "eax", "dword"}, {64, reg64names, "rax", "qword"}, \ + {32, reg32names, "eax", "dword"}, \ + {64, reg64names, "rax", "qword"}, \ }; \ for (const auto& regset : regsets) \ for (const auto& r : regset.regs) \