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 b = inst.FB;
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.BindToRegister(b, true, false);
@ -315,14 +327,14 @@ void Jit64::FloatCompare(UGeckoInstruction inst, bool upper)
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)
OR(32, PPCSTATE(fpscr), Imm32(CR_EQ << FPRF_SHIFT));
continue1 = J();
SetJumpTarget(pNaN);
MOV(64, R(RSCRATCH), Imm64(PPCCRToInternal(CR_SO)));
MOV(64, R(RSCRATCH), Imm64(PPCCRToInternal(output[CR_SO_BIT])));
if (fprf)
OR(32, PPCSTATE(fpscr), Imm32(CR_SO << FPRF_SHIFT));
@ -331,13 +343,13 @@ void Jit64::FloatCompare(UGeckoInstruction inst, bool upper)
continue2 = J();
SetJumpTarget(pGreater);
MOV(64, R(RSCRATCH), Imm64(PPCCRToInternal(CR_GT)));
MOV(64, R(RSCRATCH), Imm64(PPCCRToInternal(output[CR_GT_BIT])));
if (fprf)
OR(32, PPCSTATE(fpscr), Imm32(CR_GT << FPRF_SHIFT));
continue3 = J();
SetJumpTarget(pLesser);
MOV(64, R(RSCRATCH), Imm64(PPCCRToInternal(CR_LT)));
MOV(64, R(RSCRATCH), Imm64(PPCCRToInternal(output[CR_LT_BIT])));
if (fprf)
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;
}
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)
{
// 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];
// Reorder integer compares, rlwinm., and carry-affecting ops
// (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!
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)
{
// 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
// to get pairs like addc/adde next to each other.
if (HasOption(OPTION_CARRY_MERGE))

View File

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