From 6dc7cf29f3b938330ea0947756b827b5de493daf Mon Sep 17 00:00:00 2001 From: Fiora Date: Fri, 2 Jan 2015 13:38:24 -0800 Subject: [PATCH] JIT: implement crset special case Rebel Strike seems to use this one. --- Source/Core/Core/PowerPC/Jit64/Jit.h | 1 + .../PowerPC/Jit64/Jit_SystemRegisters.cpp | 42 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.h b/Source/Core/Core/PowerPC/Jit64/Jit.h index 48b8e5ada3..7da231d70e 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.h +++ b/Source/Core/Core/PowerPC/Jit64/Jit.h @@ -133,6 +133,7 @@ public: // Clobbers RDX. void SetCRFieldBit(int field, int bit, Gen::X64Reg in); void ClearCRFieldBit(int field, int bit); + void SetCRFieldBit(int field, int bit); // Generates a branch that will check if a given bit of a CR register part // is set or not. diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp index af5a187f91..b5b91e9fb7 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp @@ -112,6 +112,41 @@ void Jit64::ClearCRFieldBit(int field, int bit) // We don't need to set bit 32; the cases where that's needed only come up when setting bits, not clearing. } +void Jit64::SetCRFieldBit(int field, int bit) +{ + MOV(64, R(RSCRATCH), PPCSTATE(cr_val[field])); + if (bit != CR_GT_BIT) + { + TEST(64, R(RSCRATCH), R(RSCRATCH)); + FixupBranch dont_clear_gt = J_CC(CC_NZ); + BTS(64, R(RSCRATCH), Imm8(63)); + SetJumpTarget(dont_clear_gt); + } + + switch (bit) + { + case CR_SO_BIT: + BTS(64, PPCSTATE(cr_val[field]), Imm8(61)); + break; + + case CR_EQ_BIT: + SHR(64, R(RSCRATCH), Imm8(32)); + SHL(64, R(RSCRATCH), Imm8(32)); + break; + + case CR_GT_BIT: + BTR(64, PPCSTATE(cr_val[field]), Imm8(63)); + break; + + case CR_LT_BIT: + BTS(64, PPCSTATE(cr_val[field]), Imm8(62)); + break; + } + + BTS(64, R(RSCRATCH), Imm8(32)); + MOV(64, PPCSTATE(cr_val[field]), R(RSCRATCH)); +} + FixupBranch Jit64::JumpIfCRFieldBit(int field, int bit, bool jump_if_set) { switch (bit) @@ -506,6 +541,13 @@ void Jit64::crXXX(UGeckoInstruction inst) return; } + // Special case: crset + if (inst.CRBA == inst.CRBB && inst.CRBA == inst.CRBD && inst.SUBOP10 == 289) + { + SetCRFieldBit(inst.CRBD >> 2, 3 - (inst.CRBD & 3)); + return; + } + // TODO(delroth): Potential optimizations could be applied here. For // instance, if the two CR bits being loaded are the same, two loads are // not required.