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:
parent
432335cda5
commit
aaa083f8f0
|
@ -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
|
#pragma warning(disable:4146) // unary minus operator applied to unsigned type, result still unsigned
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include "IR.h"
|
#include "IR.h"
|
||||||
#include "../PPCTables.h"
|
#include "../PPCTables.h"
|
||||||
#include "../../CoreTiming.h"
|
#include "../../CoreTiming.h"
|
||||||
|
@ -374,6 +375,22 @@ InstLoc IRBuilder::FoldAdd(InstLoc Op1, InstLoc Op2) {
|
||||||
return getOp1(Op1);
|
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
|
// TODO: Test the folding below
|
||||||
// (x * i0) + x => x * (i0 + 1)
|
// (x * i0) + x => x * (i0 + 1)
|
||||||
if (getOpcode(*Op1) == Mul && isImm(*getOp2(Op1)) && isSameValue(getOp1(Op1), Op2)) {
|
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);
|
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
|
// (x - i0) => x + -i0
|
||||||
if (isImm(*Op2)) {
|
if (isImm(*Op2)) {
|
||||||
return FoldAdd(Op1, EmitIntConst(-GetImmValue(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)));
|
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
|
// TODO: Test the folding below
|
||||||
// x * (1 << y) => x << y
|
// x * (1 << y) => x << y
|
||||||
if (getOpcode(*Op2) == Shl && isImm(*getOp1(Op2)) && GetImmValue(getOp1(Op2)) == 1) {
|
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;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1028,27 +1065,44 @@ unsigned IRBuilder::isSameValue(InstLoc Op1, InstLoc Op2) const {
|
||||||
// 3 -> UOp
|
// 3 -> UOp
|
||||||
// 4 -> BiOp
|
// 4 -> BiOp
|
||||||
unsigned IRBuilder::getComplexity(InstLoc I) const {
|
unsigned IRBuilder::getComplexity(InstLoc I) const {
|
||||||
static unsigned complexities[256];
|
const unsigned Opcode = getOpcode(*I);
|
||||||
if (complexities[0] == 0) {
|
if (Opcode == Nop || Opcode == CInt16 || Opcode == CInt32) {
|
||||||
complexities[Nop] = 1;
|
return 1;
|
||||||
complexities[CInt16] = 1;
|
}
|
||||||
complexities[CInt32] = 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 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 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, };
|
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) {
|
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) {
|
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) {
|
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
|
// Performs a few simplifications for commutative operators
|
||||||
|
@ -1073,7 +1127,7 @@ void IRBuilder::simplifyCommutative(unsigned Opcode, InstLoc& Op1, InstLoc& Op2)
|
||||||
return;
|
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)) {
|
if (getOpcode(*Op1) == Opcode && isImm(*getOp2(Op1)) && isImm(*Op2)) {
|
||||||
const InstLoc Op1Old = Op1;
|
const InstLoc Op1Old = Op1;
|
||||||
const InstLoc Op2Old = Op2;
|
const InstLoc Op2Old = Op2;
|
||||||
|
@ -1081,6 +1135,7 @@ void IRBuilder::simplifyCommutative(unsigned Opcode, InstLoc& Op1, InstLoc& Op2)
|
||||||
Op2 = FoldBiOp(Opcode, getOp2(Op1Old), Op2Old);
|
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))
|
// 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))) {
|
if (getOpcode(*Op1) == Opcode && isImm(*getOp2(Op1)) && getOpcode(*Op2) == Opcode && isImm(*getOp2(Op2))) {
|
||||||
const InstLoc Op1Old = Op1;
|
const InstLoc Op1Old = Op1;
|
||||||
|
@ -1088,6 +1143,22 @@ void IRBuilder::simplifyCommutative(unsigned Opcode, InstLoc& Op1, InstLoc& Op2)
|
||||||
Op1 = FoldBiOp(Opcode, getOp1(Op1Old), getOp1(Op2Old));
|
Op1 = FoldBiOp(Opcode, getOp1(Op1Old), getOp1(Op2Old));
|
||||||
Op2 = FoldBiOp(Opcode, getOp2(Op1Old), getOp2(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 {
|
bool IRBuilder::maskedValueIsZero(InstLoc Op1, InstLoc Op2) const {
|
||||||
|
@ -1114,4 +1185,13 @@ InstLoc IRBuilder::isNot(InstLoc I) const {
|
||||||
return NULL;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -557,6 +557,8 @@ public:
|
||||||
|
|
||||||
IRBuilder() { Reset(); }
|
IRBuilder() { Reset(); }
|
||||||
|
|
||||||
|
unsigned getNumberOfOperands(InstLoc I) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IRBuilder(IRBuilder&); // DO NOT IMPLEMENT
|
IRBuilder(IRBuilder&); // DO NOT IMPLEMENT
|
||||||
unsigned isSameValue(InstLoc Op1, InstLoc Op2) const;
|
unsigned isSameValue(InstLoc Op1, InstLoc Op2) const;
|
||||||
|
@ -564,6 +566,7 @@ private:
|
||||||
void simplifyCommutative(unsigned Opcode, InstLoc& Op1, InstLoc& Op2);
|
void simplifyCommutative(unsigned Opcode, InstLoc& Op1, InstLoc& Op2);
|
||||||
bool maskedValueIsZero(InstLoc Op1, InstLoc Op2) const;
|
bool maskedValueIsZero(InstLoc Op1, InstLoc Op2) const;
|
||||||
InstLoc isNot(InstLoc I) const;
|
InstLoc isNot(InstLoc I) const;
|
||||||
|
InstLoc isNeg(InstLoc I) const;
|
||||||
|
|
||||||
std::vector<Inst> InstList; // FIXME: We must ensure this is
|
std::vector<Inst> InstList; // FIXME: We must ensure this is
|
||||||
// continuous!
|
// continuous!
|
||||||
|
|
Loading…
Reference in New Issue