From 133e04541a2682e5565c18de94b0b84cfd467498 Mon Sep 17 00:00:00 2001 From: Fiora Date: Mon, 4 Aug 2014 09:48:23 -0400 Subject: [PATCH] JIT: Don't assume the reserved bits in GQRs are zero While the unused bits in the GQR SPR are probably not supposed to be set, some games set them anyways (e.g. Dirt 2), which broke the JIT code. --- Source/Core/Core/PowerPC/Jit64/Jit_LoadStorePaired.cpp | 10 ++++++++-- Source/Core/Core/PowerPC/Jit64IL/IR_X86.cpp | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStorePaired.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStorePaired.cpp index 47867c4f3f..fbff119cb7 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStorePaired.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStorePaired.cpp @@ -38,7 +38,12 @@ void Jit64::psq_st(UGeckoInstruction inst) ADD(32, R(ECX), Imm32((u32)offset)); if (update && offset) MOV(32, gpr.R(a), R(ECX)); - MOVZX(32, 16, EAX, M(&PowerPC::ppcState.spr[SPR_GQR0 + inst.I])); + // Some games (e.g. Dirt 2) incorrectly set the unused bits which breaks the lookup table code. + // Hence, we need to mask out the unused bits. The layout of the GQR register is + // UU[SCALE]UUUUU[TYPE] where SCALE is 6 bits and TYPE is 3 bits, so we have to AND with + // 0b0011111100000111, or 0x3F07. + MOV(32, R(EAX), Imm32(0x3F07)); + AND(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_GQR0 + inst.I])); MOVZX(32, 8, EDX, R(AL)); // FIXME: Fix ModR/M encoding to allow [EDX*4+disp32] without a base register! @@ -75,7 +80,8 @@ void Jit64::psq_l(UGeckoInstruction inst) MOV(32, R(ECX), gpr.R(inst.RA)); if (update && offset) MOV(32, gpr.R(inst.RA), R(ECX)); - MOVZX(32, 16, EAX, M(((char *)&GQR(inst.I)) + 2)); + MOV(32, R(EAX), Imm32(0x3F07)); + AND(32, R(EAX), M(((char *)&GQR(inst.I)) + 2)); MOVZX(32, 8, EDX, R(AL)); if (inst.W) OR(32, R(EDX), Imm8(8)); diff --git a/Source/Core/Core/PowerPC/Jit64IL/IR_X86.cpp b/Source/Core/Core/PowerPC/Jit64IL/IR_X86.cpp index 7b636073bb..584aaba32c 100644 --- a/Source/Core/Core/PowerPC/Jit64IL/IR_X86.cpp +++ b/Source/Core/Core/PowerPC/Jit64IL/IR_X86.cpp @@ -1270,7 +1270,12 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, u32 exitAddress) { // The lower 3 bits is for GQR index. The next 1 bit is for inst.W unsigned int quantreg = (*I >> 16) & 0x7; unsigned int w = *I >> 19; - Jit->MOVZX(32, 16, EAX, M(((char *)&GQR(quantreg)) + 2)); + // Some games (e.g. Dirt 2) incorrectly set the unused bits which breaks the lookup table code. + // Hence, we need to mask out the unused bits. The layout of the GQR register is + // UU[SCALE]UUUUU[TYPE] where SCALE is 6 bits and TYPE is 3 bits, so we have to AND with + // 0b0011111100000111, or 0x3F07. + Jit->MOV(32, R(EAX), Imm32(0x3F07)); + Jit->AND(32, R(EAX), M(((char *)&GQR(quantreg)) + 2)); Jit->MOVZX(32, 8, EDX, R(AL)); Jit->OR(32, R(EDX), Imm8(w << 3)); @@ -1317,7 +1322,8 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, u32 exitAddress) { regSpill(RI, EAX); regSpill(RI, EDX); u32 quantreg = *I >> 24; - Jit->MOVZX(32, 16, EAX, M(&PowerPC::ppcState.spr[SPR_GQR0 + quantreg])); + Jit->MOV(32, R(EAX), Imm32(0x3F07)); + Jit->AND(32, R(EAX), M(&PowerPC::ppcState.spr[SPR_GQR0 + quantreg])); Jit->MOVZX(32, 8, EDX, R(AL)); Jit->MOV(32, R(ECX), regLocForInst(RI, getOp2(I)));