JitIL: Added instruction combining rules for speed up.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6010 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
nodchip 2010-07-31 03:26:25 +00:00
parent 432335cda5
commit aaa083f8f0
2 changed files with 93 additions and 10 deletions

View File

@ -129,6 +129,7 @@ Fix profiled loads/stores to work safely. On 32-bit, one solution is to
#pragma warning(disable:4146) // unary minus operator applied to unsigned type, result still unsigned
#endif
#include <algorithm>
#include "IR.h"
#include "../PPCTables.h"
#include "../../CoreTiming.h"
@ -374,6 +375,22 @@ InstLoc IRBuilder::FoldAdd(InstLoc Op1, InstLoc Op2) {
return getOp1(Op1);
}
if (InstLoc negOp1 = isNeg(Op1)) {
// TODO: Test the folding below
// -A + -B --> -(A + B)
if (InstLoc negOp2 = isNeg(Op2)) {
return FoldSub(EmitIntConst(0), FoldAdd(negOp1, negOp2));
}
// -A + B --> B - A
return FoldSub(Op2, negOp1);
}
// A + -B --> A - B
if (InstLoc negOp2 = isNeg(Op2)) {
return FoldSub(Op1, negOp2);
}
// TODO: Test the folding below
// (x * i0) + x => x * (i0 + 1)
if (getOpcode(*Op1) == Mul && isImm(*getOp2(Op1)) && isSameValue(getOp1(Op1), Op2)) {
@ -425,6 +442,12 @@ InstLoc IRBuilder::FoldSub(InstLoc Op1, InstLoc Op2) {
return EmitIntConst(0);
}
// TODO: Test the folding below
// x - (-A) => x + A
if (InstLoc negOp2 = isNeg(Op2)) {
return FoldAdd(Op1, negOp2);
}
// (x - i0) => x + -i0
if (isImm(*Op2)) {
return FoldAdd(Op1, EmitIntConst(-GetImmValue(Op2)));
@ -565,6 +588,14 @@ InstLoc IRBuilder::FoldMul(InstLoc Op1, InstLoc Op2) {
return FoldAdd(FoldMul(getOp1(Op1), Op2), EmitIntConst(GetImmValue(getOp2(Op1)) * GetImmValue(Op2)));
}
// TODO: Test the folding below
// -X * -Y => X * Y
if (InstLoc negOp1 = isNeg(Op1)) {
if (InstLoc negOp2 = isNeg(Op2)) {
return FoldMul(negOp1, negOp2);
}
}
// TODO: Test the folding below
// x * (1 << y) => x << y
if (getOpcode(*Op2) == Shl && isImm(*getOp1(Op2)) && GetImmValue(getOp1(Op2)) == 1) {
@ -1017,6 +1048,12 @@ unsigned IRBuilder::isSameValue(InstLoc Op1, InstLoc Op2) const {
return true;
}
if (getNumberOfOperands(Op1) == 2 && getOpcode(*Op1) != StorePaired && getOpcode(*Op1) == getOpcode(*Op2) &&
isSameValue(getOp1(Op1), getOp1(Op2)) && isSameValue(getOp2(Op1), getOp2(Op2)))
{
return true;
}
return false;
}
@ -1028,27 +1065,44 @@ unsigned IRBuilder::isSameValue(InstLoc Op1, InstLoc Op2) const {
// 3 -> UOp
// 4 -> BiOp
unsigned IRBuilder::getComplexity(InstLoc I) const {
static unsigned complexities[256];
if (complexities[0] == 0) {
complexities[Nop] = 1;
complexities[CInt16] = 1;
complexities[CInt32] = 1;
const unsigned Opcode = getOpcode(*I);
if (Opcode == Nop || Opcode == CInt16 || Opcode == CInt32) {
return 1;
}
const unsigned numberOfOperands = getNumberOfOperands(I);
if (numberOfOperands == -1U) {
return 0;
}
return numberOfOperands + 2;
}
unsigned IRBuilder::getNumberOfOperands(InstLoc I) const {
static unsigned numberOfOperands[256];
if (numberOfOperands[0] == 0) {
std::fill_n(numberOfOperands, sizeof(numberOfOperands) / sizeof(numberOfOperands[0]), -1U);
numberOfOperands[Nop] = 0;
numberOfOperands[CInt16] = 0;
numberOfOperands[CInt32] = 0;
static unsigned ZeroOp[] = {LoadCR, LoadLink, LoadMSR, LoadGReg, LoadCTR, InterpreterBranch, LoadCarry, RFIExit, LoadFReg, LoadFRegDENToZero, LoadGQR, Int3, };
static unsigned UOp[] = {StoreLink, BranchUncond, StoreCR, StoreMSR, StoreFPRF, StoreGReg, StoreCTR, Load8, Load16, Load32, SExt16, SExt8, Cntlzw, StoreCarry, SystemCall, ShortIdleLoop, LoadSingle, LoadDouble, LoadPaired, StoreFReg, DupSingleToMReg, DupSingleToPacked, ExpandPackedToMReg, CompactMRegToPacked, FSNeg, FSRSqrt, FDNeg, FPDup0, FPDup1, FPNeg, DoubleToSingle, StoreGQR, StoreSRR, };
static unsigned BiOp[] = {BranchCond, IdleBranch, And, Xor, Sub, Or, Add, Mul, Rol, Shl, Shrl, Sarl, ICmpEq, ICmpNe, ICmpUgt, ICmpUlt, ICmpSgt, ICmpSlt, ICmpSge, ICmpSle, Store8, Store16, Store32, ICmpCRSigned, ICmpCRUnsigned, InterpreterFallback, StoreSingle, StoreDouble, StorePaired, InsertDoubleInMReg, FSMul, FSAdd, FSSub, FDMul, FDAdd, FDSub, FPAdd, FPMul, FPSub, FPMerge00, FPMerge01, FPMerge10, FPMerge11, FDCmpCR, };
for (size_t i = 0; i < sizeof(ZeroOp) / sizeof(ZeroOp[0]); ++i) {
complexities[ZeroOp[i]] = 2;
numberOfOperands[ZeroOp[i]] = 0;
}
for (size_t i = 0; i < sizeof(UOp) / sizeof(UOp[0]); ++i) {
complexities[UOp[i]] = 3;
numberOfOperands[UOp[i]] = 1;
}
for (size_t i = 0; i < sizeof(BiOp) / sizeof(BiOp[0]); ++i) {
complexities[BiOp[i]] = 4;
numberOfOperands[BiOp[i]] = 2;
}
}
return complexities[getOpcode(*I)];
return numberOfOperands[getOpcode(*I)];
}
// Performs a few simplifications for commutative operators
@ -1073,7 +1127,7 @@ void IRBuilder::simplifyCommutative(unsigned Opcode, InstLoc& Op1, InstLoc& Op2)
return;
}
// Transform: (op (op V, C1), C2) ==> (op V, (op C1, C2))
// (V op C1) op C2 => V + (C1 + C2)
if (getOpcode(*Op1) == Opcode && isImm(*getOp2(Op1)) && isImm(*Op2)) {
const InstLoc Op1Old = Op1;
const InstLoc Op2Old = Op2;
@ -1081,6 +1135,7 @@ void IRBuilder::simplifyCommutative(unsigned Opcode, InstLoc& Op1, InstLoc& Op2)
Op2 = FoldBiOp(Opcode, getOp2(Op1Old), Op2Old);
}
// ((V1 op C1) op (V2 op C2)) => ((V1 op V2) op (C1 op C2))
// Transform: (op (op V1, C1), (op V2, C2)) ==> (op (op V1, V2), (op C1,C2))
if (getOpcode(*Op1) == Opcode && isImm(*getOp2(Op1)) && getOpcode(*Op2) == Opcode && isImm(*getOp2(Op2))) {
const InstLoc Op1Old = Op1;
@ -1088,6 +1143,22 @@ void IRBuilder::simplifyCommutative(unsigned Opcode, InstLoc& Op1, InstLoc& Op2)
Op1 = FoldBiOp(Opcode, getOp1(Op1Old), getOp1(Op2Old));
Op2 = FoldBiOp(Opcode, getOp2(Op1Old), getOp2(Op2Old));
}
// ((w op x) op (y op z)) => (((w op x) op y) op z)
if (getOpcode(*Op1) == Opcode && getOpcode(*Op2) == Opcode) {
// Sort the operands where the complexities will be descending order.
std::pair<unsigned, InstLoc> ops[4];
ops[0] = std::make_pair(getComplexity(getOp1(Op1)), getOp1(Op1));
ops[1] = std::make_pair(getComplexity(getOp2(Op1)), getOp2(Op1));
ops[2] = std::make_pair(getComplexity(getOp1(Op2)), getOp1(Op2));
ops[3] = std::make_pair(getComplexity(getOp2(Op2)), getOp2(Op2));
std::sort(ops, ops + 4, std::greater<std::pair<unsigned, InstLoc> >());
const InstLoc Op1Old = Op1;
const InstLoc Op2Old = Op2;
Op1 = FoldBiOp(Opcode, FoldBiOp(Opcode, ops[0].second, ops[1].second), ops[2].second);
Op2 = ops[3].second;
}
}
bool IRBuilder::maskedValueIsZero(InstLoc Op1, InstLoc Op2) const {
@ -1114,4 +1185,13 @@ InstLoc IRBuilder::isNot(InstLoc I) const {
return NULL;
}
// Returns I' if I == (0 - I')
InstLoc IRBuilder::isNeg(InstLoc I) const {
if (getOpcode(*I) == Sub && isImm(*getOp1(I)) && GetImmValue(getOp1(I)) == 0) {
return getOp2(I);
}
return NULL;
}
}

View File

@ -557,6 +557,8 @@ public:
IRBuilder() { Reset(); }
unsigned getNumberOfOperands(InstLoc I) const;
private:
IRBuilder(IRBuilder&); // DO NOT IMPLEMENT
unsigned isSameValue(InstLoc Op1, InstLoc Op2) const;
@ -564,6 +566,7 @@ private:
void simplifyCommutative(unsigned Opcode, InstLoc& Op1, InstLoc& Op2);
bool maskedValueIsZero(InstLoc Op1, InstLoc Op2) const;
InstLoc isNot(InstLoc I) const;
InstLoc isNeg(InstLoc I) const;
std::vector<Inst> InstList; // FIXME: We must ensure this is
// continuous!