diff --git a/src/dynarmic/backend/x64/emit_x64_memory.cpp.inc b/src/dynarmic/backend/x64/emit_x64_memory.cpp.inc index 55008ca2..f1666700 100644 --- a/src/dynarmic/backend/x64/emit_x64_memory.cpp.inc +++ b/src/dynarmic/backend/x64/emit_x64_memory.cpp.inc @@ -75,6 +75,14 @@ void AxxEmitX64::EmitMemoryRead(AxxEmitContext& ctx, IR::Inst* inst) { return; } + if (ordered && bitsize == 128) { + // Required for atomic 128-bit loads/stores + ctx.reg_alloc.ScratchGpr(HostLoc::RAX); + ctx.reg_alloc.ScratchGpr(HostLoc::RBX); + ctx.reg_alloc.ScratchGpr(HostLoc::RCX); + ctx.reg_alloc.ScratchGpr(HostLoc::RDX); + } + const Xbyak::Reg64 vaddr = ctx.reg_alloc.UseGpr(args[0]); const int value_idx = bitsize == 128 ? ctx.reg_alloc.ScratchXmm().getIdx() : ctx.reg_alloc.ScratchGpr().getIdx(); @@ -145,6 +153,14 @@ void AxxEmitX64::EmitMemoryWrite(AxxEmitContext& ctx, IR::Inst* inst) { return; } + if (ordered && bitsize == 128) { + // Required for atomic 128-bit loads/stores + ctx.reg_alloc.ScratchGpr(HostLoc::RAX); + ctx.reg_alloc.ScratchGpr(HostLoc::RBX); + ctx.reg_alloc.ScratchGpr(HostLoc::RCX); + ctx.reg_alloc.ScratchGpr(HostLoc::RDX); + } + const Xbyak::Reg64 vaddr = ctx.reg_alloc.UseGpr(args[0]); const int value_idx = bitsize == 128 ? ctx.reg_alloc.UseXmm(args[1]).getIdx() @@ -305,6 +321,14 @@ void AxxEmitX64::EmitExclusiveReadMemoryInline(AxxEmitContext& ctx, IR::Inst* in auto args = ctx.reg_alloc.GetArgumentInfo(inst); const bool ordered = true; + if (ordered && bitsize == 128) { + // Required for atomic 128-bit loads/stores + ctx.reg_alloc.ScratchGpr(HostLoc::RAX); + ctx.reg_alloc.ScratchGpr(HostLoc::RBX); + ctx.reg_alloc.ScratchGpr(HostLoc::RCX); + ctx.reg_alloc.ScratchGpr(HostLoc::RDX); + } + const Xbyak::Reg64 vaddr = ctx.reg_alloc.UseGpr(args[0]); const int value_idx = bitsize == 128 ? ctx.reg_alloc.ScratchXmm().getIdx() : ctx.reg_alloc.ScratchGpr().getIdx(); const Xbyak::Reg64 tmp = ctx.reg_alloc.ScratchGpr(); diff --git a/src/dynarmic/backend/x64/emit_x64_memory.h b/src/dynarmic/backend/x64/emit_x64_memory.h index 983abb56..e92ed729 100644 --- a/src/dynarmic/backend/x64/emit_x64_memory.h +++ b/src/dynarmic/backend/x64/emit_x64_memory.h @@ -201,10 +201,13 @@ template<> template const void* EmitReadMemoryMov(BlockOfCode& code, int value_idx, const Xbyak::RegExp& addr, bool ordered) { if (ordered) { - if constexpr (bitsize == 128) { - code.mfence(); - } else { + if constexpr (bitsize != 128) { code.xor_(Xbyak::Reg32{value_idx}, Xbyak::Reg32{value_idx}); + } else { + code.xor_(eax, eax); + code.xor_(ebx, ebx); + code.xor_(ecx, ecx); + code.xor_(edx, edx); } const void* fastmem_location = code.getCurr(); @@ -226,8 +229,16 @@ const void* EmitReadMemoryMov(BlockOfCode& code, int value_idx, const Xbyak::Reg code.xadd(qword[addr], Xbyak::Reg64{value_idx}); break; case 128: - // TODO (HACK): Detect CPUs where this load is not atomic - code.movaps(Xbyak::Xmm{value_idx}, xword[addr]); + code.lock(); + code.cmpxchg16b(xword[addr]); + if (code.HasHostFeature(HostFeature::SSE41)) { + code.movq(Xbyak::Xmm{value_idx}, rax); + code.pinsrq(Xbyak::Xmm{value_idx}, rdx, 1); + } else { + code.movq(Xbyak::Xmm{value_idx}, rax); + code.movq(xmm0, rdx); + code.punpcklqdq(Xbyak::Xmm{value_idx}, xmm0); + } break; default: ASSERT_FALSE("Invalid bitsize"); @@ -261,6 +272,20 @@ const void* EmitReadMemoryMov(BlockOfCode& code, int value_idx, const Xbyak::Reg template const void* EmitWriteMemoryMov(BlockOfCode& code, const Xbyak::RegExp& addr, int value_idx, bool ordered) { if (ordered) { + if constexpr (bitsize == 128) { + code.xor_(eax, eax); + code.xor_(edx, edx); + if (code.HasHostFeature(HostFeature::SSE41)) { + code.movq(rbx, Xbyak::Xmm{value_idx}); + code.pextrq(rcx, Xbyak::Xmm{value_idx}, 1); + } else { + code.movaps(xmm0, Xbyak::Xmm{value_idx}); + code.movq(rbx, xmm0); + code.punpckhqdq(xmm0, xmm0); + code.movq(rcx, xmm0); + } + } + const void* fastmem_location = code.getCurr(); switch (bitsize) { case 8: @@ -275,10 +300,14 @@ const void* EmitWriteMemoryMov(BlockOfCode& code, const Xbyak::RegExp& addr, int case 64: code.xchg(qword[addr], Xbyak::Reg64{value_idx}); break; - case 128: - code.movaps(xword[addr], Xbyak::Xmm{value_idx}); - code.mfence(); + case 128: { + Xbyak::Label loop; + code.L(loop); + code.lock(); + code.cmpxchg16b(xword[addr]); + code.jnz(loop); break; + } default: ASSERT_FALSE("Invalid bitsize"); }