JIT: fix a corner case in crXXX

It didn't behave correctly with an input of zero, resulting in some games
breaking (at the least, Fight Night 2). This should be fixed now.

Also clean it up, add a few comments, and fix some variants of the instruction
that are so rare that they probably never got tested.
This commit is contained in:
Fiora 2014-09-08 04:16:50 -07:00
parent e8aa1fe052
commit ce494a5e4f
1 changed files with 23 additions and 15 deletions

View File

@ -45,6 +45,17 @@ void Jit64::SetCRFieldBit(int field, int bit, Gen::X64Reg in)
MOV(64, R(RSCRATCH2), PPCSTATE(cr_val[field])); MOV(64, R(RSCRATCH2), PPCSTATE(cr_val[field]));
MOVZX(32, 8, in, R(in)); MOVZX(32, 8, in, R(in));
// Gross but necessary; if the input is totally zero and we set SO or LT,
// or even just add the (1<<32), GT will suddenly end up set without us
// intending to. This can break actual games, so fix it up.
if (bit != CR_GT_BIT)
{
TEST(64, R(RSCRATCH2), R(RSCRATCH2));
FixupBranch dont_clear_gt = J_CC(CC_NZ);
BTS(64, R(RSCRATCH2), Imm8(63));
SetJumpTarget(dont_clear_gt);
}
switch (bit) switch (bit)
{ {
case CR_SO_BIT: // set bit 61 to input case CR_SO_BIT: // set bit 61 to input
@ -434,38 +445,35 @@ void Jit64::crXXX(UGeckoInstruction inst)
// instance, if the two CR bits being loaded are the same, two loads are // instance, if the two CR bits being loaded are the same, two loads are
// not required. // not required.
// USES_CR // creqv or crnand or crnor
// crandc or crorc or creqv or crnand or crnor bool negateA = inst.SUBOP10 == 289 || inst.SUBOP10 == 225 || inst.SUBOP10 == 33;
bool negateA = inst.SUBOP10 == 129 || inst.SUBOP10 == 417 || inst.SUBOP10 == 289 || inst.SUBOP10 == 225 || inst.SUBOP10 == 33; // crandc or crorc or crnand or crnor
// crnand or crnor bool negateB = inst.SUBOP10 == 129 || inst.SUBOP10 == 417 || inst.SUBOP10 == 225 || inst.SUBOP10 == 33;
bool negateB = inst.SUBOP10 == 225 || inst.SUBOP10 == 33;
GetCRFieldBit(inst.CRBA >> 2, 3 - (inst.CRBA & 3), RSCRATCH2, negateA); GetCRFieldBit(inst.CRBA >> 2, 3 - (inst.CRBA & 3), RSCRATCH, negateA);
GetCRFieldBit(inst.CRBB >> 2, 3 - (inst.CRBB & 3), RSCRATCH, negateB); GetCRFieldBit(inst.CRBB >> 2, 3 - (inst.CRBB & 3), RSCRATCH2, negateB);
// Compute combined bit // Compute combined bit
switch (inst.SUBOP10) switch (inst.SUBOP10)
{ {
case 33: // crnor: ~(A || B) == (~A && ~B) case 33: // crnor: ~(A || B) == (~A && ~B)
case 129: // crandc case 129: // crandc: A && ~B
case 257: // crand case 257: // crand: A && B
AND(8, R(RSCRATCH), R(RSCRATCH2)); AND(8, R(RSCRATCH), R(RSCRATCH2));
break; break;
case 193: // crxor case 193: // crxor: A ^ B
case 289: // creqv case 289: // creqv: ~(A ^ B) = ~A ^ B
XOR(8, R(RSCRATCH), R(RSCRATCH2)); XOR(8, R(RSCRATCH), R(RSCRATCH2));
break; break;
case 225: // crnand: ~(A && B) == (~A || ~B) case 225: // crnand: ~(A && B) == (~A || ~B)
case 417: // crorc case 417: // crorc: A || ~B
case 449: // cror case 449: // cror: A || B
OR(8, R(RSCRATCH), R(RSCRATCH2)); OR(8, R(RSCRATCH), R(RSCRATCH2));
break; break;
} }
// Store result bit in CRBD // Store result bit in CRBD
SetCRFieldBit(inst.CRBD >> 2, 3 - (inst.CRBD & 3), RSCRATCH); SetCRFieldBit(inst.CRBD >> 2, 3 - (inst.CRBD & 3), RSCRATCH);
gpr.UnlockAllX();
} }