JIT: merge fcmpx and cror

Almost all uses of boolean condition-register ops in real code seem to be
the combination fcmpx + cror (e.g. for <= or >=). This merges the two.
This commit is contained in:
Fiora 2014-10-21 02:56:38 -07:00
parent a666bb6bf6
commit 97fba41860
3 changed files with 28 additions and 6 deletions

View File

@ -276,6 +276,18 @@ void Jit64::FloatCompare(UGeckoInstruction inst, bool upper)
int a = inst.FA; int a = inst.FA;
int b = inst.FB; int b = inst.FB;
int crf = inst.CRFD; int crf = inst.CRFD;
int output[4] = { CR_SO, CR_EQ, CR_GT, CR_LT };
// Merge neighboring fcmp and cror (the primary use of cror).
UGeckoInstruction next = js.next_inst;
if (next.OPCD == 19 && next.SUBOP10 == 449 && (next.CRBA >> 2) == crf && (next.CRBB >> 2) == crf && (next.CRBD >> 2) == crf)
{
js.skipnext = true;
js.downcountAmount++;
int dst = 3 - (next.CRBD & 3);
output[3 - (next.CRBA & 3)] |= 1 << dst;
output[3 - (next.CRBB & 3)] |= 1 << dst;
}
fpr.Lock(a, b); fpr.Lock(a, b);
fpr.BindToRegister(b, true, false); fpr.BindToRegister(b, true, false);
@ -315,14 +327,14 @@ void Jit64::FloatCompare(UGeckoInstruction inst, bool upper)
pGreater = J_CC(CC_B); pGreater = J_CC(CC_B);
} }
MOV(64, R(RSCRATCH), Imm64(PPCCRToInternal(CR_EQ))); MOV(64, R(RSCRATCH), Imm64(PPCCRToInternal(output[CR_EQ_BIT])));
if (fprf) if (fprf)
OR(32, PPCSTATE(fpscr), Imm32(CR_EQ << FPRF_SHIFT)); OR(32, PPCSTATE(fpscr), Imm32(CR_EQ << FPRF_SHIFT));
continue1 = J(); continue1 = J();
SetJumpTarget(pNaN); SetJumpTarget(pNaN);
MOV(64, R(RSCRATCH), Imm64(PPCCRToInternal(CR_SO))); MOV(64, R(RSCRATCH), Imm64(PPCCRToInternal(output[CR_SO_BIT])));
if (fprf) if (fprf)
OR(32, PPCSTATE(fpscr), Imm32(CR_SO << FPRF_SHIFT)); OR(32, PPCSTATE(fpscr), Imm32(CR_SO << FPRF_SHIFT));
@ -331,13 +343,13 @@ void Jit64::FloatCompare(UGeckoInstruction inst, bool upper)
continue2 = J(); continue2 = J();
SetJumpTarget(pGreater); SetJumpTarget(pGreater);
MOV(64, R(RSCRATCH), Imm64(PPCCRToInternal(CR_GT))); MOV(64, R(RSCRATCH), Imm64(PPCCRToInternal(output[CR_GT_BIT])));
if (fprf) if (fprf)
OR(32, PPCSTATE(fpscr), Imm32(CR_GT << FPRF_SHIFT)); OR(32, PPCSTATE(fpscr), Imm32(CR_GT << FPRF_SHIFT));
continue3 = J(); continue3 = J();
SetJumpTarget(pLesser); SetJumpTarget(pLesser);
MOV(64, R(RSCRATCH), Imm64(PPCCRToInternal(CR_LT))); MOV(64, R(RSCRATCH), Imm64(PPCCRToInternal(output[CR_LT_BIT])));
if (fprf) if (fprf)
OR(32, PPCSTATE(fpscr), Imm32(CR_LT << FPRF_SHIFT)); OR(32, PPCSTATE(fpscr), Imm32(CR_LT << FPRF_SHIFT));
} }

View File

@ -406,6 +406,11 @@ static bool isCarryOp(const CodeOp& a)
return (a.opinfo->flags & FL_SET_CA) && !(a.opinfo->flags & FL_SET_OE) && a.opinfo->type == OPTYPE_INTEGER; return (a.opinfo->flags & FL_SET_CA) && !(a.opinfo->flags & FL_SET_OE) && a.opinfo->type == OPTYPE_INTEGER;
} }
static bool isCror(const CodeOp& a)
{
return a.inst.OPCD == 19 && a.inst.SUBOP10 == 449;
}
void PPCAnalyzer::ReorderInstructionsCore(u32 instructions, CodeOp* code, bool reverse, ReorderType type) void PPCAnalyzer::ReorderInstructionsCore(u32 instructions, CodeOp* code, bool reverse, ReorderType type)
{ {
// Bubbling an instruction sometimes reveals another opportunity to bubble an instruction, so do // Bubbling an instruction sometimes reveals another opportunity to bubble an instruction, so do
@ -426,7 +431,7 @@ void PPCAnalyzer::ReorderInstructionsCore(u32 instructions, CodeOp* code, bool r
CodeOp &b = code[i + increment]; CodeOp &b = code[i + increment];
// Reorder integer compares, rlwinm., and carry-affecting ops // Reorder integer compares, rlwinm., and carry-affecting ops
// (if we add more merged branch instructions, add them here!) // (if we add more merged branch instructions, add them here!)
if ((type == REORDER_CARRY && isCarryOp(a)) || (type == REORDER_CMP && (isCmp(a) || a.outputCR0))) if ((type == REORDER_CROR && isCror(a)) || (type == REORDER_CARRY && isCarryOp(a)) || (type == REORDER_CMP && (isCmp(a) || a.outputCR0)))
{ {
// once we're next to a carry instruction, don't move away! // once we're next to a carry instruction, don't move away!
if (type == REORDER_CARRY && i != start) if (type == REORDER_CARRY && i != start)
@ -454,6 +459,10 @@ void PPCAnalyzer::ReorderInstructionsCore(u32 instructions, CodeOp* code, bool r
void PPCAnalyzer::ReorderInstructions(u32 instructions, CodeOp *code) void PPCAnalyzer::ReorderInstructions(u32 instructions, CodeOp *code)
{ {
// Reorder cror instructions upwards (e.g. towards an fcmp). Technically we should be more
// picky about this, but cror seems to almost solely be used for this purpose in real code.
// Additionally, the other boolean ops seem to almost never be used.
ReorderInstructionsCore(instructions, code, true, REORDER_CROR);
// For carry, bubble instructions *towards* each other; one direction often isn't enough // For carry, bubble instructions *towards* each other; one direction often isn't enough
// to get pairs like addc/adde next to each other. // to get pairs like addc/adde next to each other.
if (HasOption(OPTION_CARRY_MERGE)) if (HasOption(OPTION_CARRY_MERGE))

View File

@ -156,7 +156,8 @@ private:
enum ReorderType enum ReorderType
{ {
REORDER_CARRY, REORDER_CARRY,
REORDER_CMP REORDER_CMP,
REORDER_CROR
}; };
void ReorderInstructionsCore(u32 instructions, CodeOp* code, bool reverse, ReorderType type); void ReorderInstructionsCore(u32 instructions, CodeOp* code, bool reverse, ReorderType type);