From 9f3e2ac2cc0dc2605221fcb8d1dd71feb4d6f6d5 Mon Sep 17 00:00:00 2001 From: nodchip Date: Wed, 21 Jul 2010 02:23:55 +0000 Subject: [PATCH] JitIL: Added operand folding rules for speed improvement. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5927 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp | 146 ++++++++++++++++++++ Source/Core/Core/Src/PowerPC/Jit64IL/IR.h | 3 + 2 files changed, 149 insertions(+) diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp index 90e5442cc1..4363f3ac78 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp @@ -356,24 +356,139 @@ InstLoc IRBuilder::FoldAdd(InstLoc Op1, InstLoc Op2) { GetImmValue(Op2)); return FoldAdd(Op2, Op1); } + if (isImm(*Op2)) { + // Add x 0 => x if (!GetImmValue(Op2)) return Op1; + + // Add (Add x i0) i1 => Add x (i0 + i1) if (getOpcode(*Op1) == Add && isImm(*getOp2(Op1))) { unsigned RHS = GetImmValue(Op2) + GetImmValue(getOp2(Op1)); return FoldAdd(getOp1(Op1), EmitIntConst(RHS)); } } + + // Add (Add x i0) (Add y i1) => Add (Add x y) (i0 + i1) + if (getOpcode(*Op1) == Add && getOpcode(*Op2) == Add && isImm(*getOp2(Op1)) && isImm(*getOp2(Op2))) { + return FoldAdd(FoldAdd(getOp1(Op1), getOp1(Op2)), EmitIntConst(GetImmValue(getOp2(Op1)) + GetImmValue(getOp2(Op2)))); + } + + // Add x x => Shl x 1 + if (Op1 == Op2) { + return FoldShl(Op1, EmitIntConst(1)); + } + + if (getOpcode(*Op1) == Mul && getOpcode(*Op2) == Mul) { + // TODO: Test the folding below + // Add (Mul x y) (Mul x z) => Mul(x Add(y z)) + if (isSameValue(getOp1(Op1), getOp1(Op2))) { + return FoldMul(getOp1(Op1), FoldAdd(getOp2(Op1), getOp2(Op2))); + } + + // TODO: Test the folding below + // Add (Mul x y) (Mul z x) => Mul(x Add(y z)) + if (isSameValue(getOp1(Op1), getOp2(Op2))) { + return FoldMul(getOp1(Op1), FoldAdd(getOp2(Op1), getOp1(Op2))); + } + + // TODO: Test the folding below + // Add (Mul y x) (Mul x z) => Mul(x Add(y z)) + if (isSameValue(getOp2(Op1), getOp1(Op2))) { + return FoldMul(getOp2(Op1), FoldAdd(getOp1(Op1), getOp2(Op2))); + } + + // Add (Mul y x) (Mul z x) => Mul(x Add(y z)) + if (isSameValue(getOp2(Op1), getOp2(Op2))) { + return FoldMul(getOp2(Op1), FoldAdd(getOp1(Op1), getOp1(Op2))); + } + } + return EmitBiOp(Add, Op1, Op2); } InstLoc IRBuilder::FoldSub(InstLoc Op1, InstLoc Op2) { + // Sub x, x => CInt32 0 + if (isSameValue(Op1, Op2)) { + return EmitIntConst(0); + } + + // Sub x, i0 => Add x, -i0 if (isImm(*Op2)) { return FoldAdd(Op1, EmitIntConst(-GetImmValue(Op2))); } + + // Sub (Add x i0) (Add y i1) => Add (Sub x y) (i0 - i1) + if (getOpcode(*Op1) == Add && getOpcode(*Op2) == Add && isImm(*getOp2(Op1)) && isImm(*getOp2(Op2))) { + return FoldAdd(FoldSub(getOp1(Op1), getOp1(Op2)), EmitIntConst(GetImmValue(getOp2(Op1)) - GetImmValue(getOp2(Op2)))); + } + + if (getOpcode(*Op1) == Mul && getOpcode(*Op2) == Mul) { + // TODO: Test the folding below + // Sub (Mul x y) (Mul x z) => Mul(x Sub(y z)) + if (isSameValue(getOp1(Op1), getOp1(Op2))) { + return FoldMul(getOp1(Op1), FoldSub(getOp2(Op1), getOp2(Op2))); + } + + // TODO: Test the folding below + // Sub (Mul x y) (Mul z x) => Mul(x Sub(y z)) + if (isSameValue(getOp1(Op1), getOp2(Op2))) { + return FoldMul(getOp1(Op1), FoldSub(getOp2(Op1), getOp1(Op2))); + } + + // TODO: Test the folding below + // Sub (Mul y x) (Mul x z) => Mul(x Sub(y z)) + if (isSameValue(getOp2(Op1), getOp1(Op2))) { + return FoldMul(getOp2(Op1), FoldSub(getOp1(Op1), getOp2(Op2))); + } + + // Sub (Mul y x) (Mul z x) => Mul(x Sub(y z)) + if (isSameValue(getOp2(Op1), getOp2(Op2))) { + return FoldMul(getOp2(Op1), FoldSub(getOp1(Op1), getOp1(Op2))); + } + } + return EmitBiOp(Sub, Op1, Op2); } +InstLoc IRBuilder::FoldMul(InstLoc Op1, InstLoc Op2) { + if (isImm(*Op1)) { + // Mul i0 i1 => i0 * i1 + if (isImm(*Op2)) { + return EmitIntConst(GetImmValue(Op1) * GetImmValue(Op2)); + } + + // Mul i0 x => Mul x i0 + return FoldMul(Op2, Op1); + } + + if (isImm(*Op2)) { + const unsigned imm = GetImmValue(Op2); + + // Mul x 0 => 0 + if (imm == 0) { + return EmitIntConst(0); + } + + // FIXME: The code below can be speed up by popcount, (x & -x), etc... + for (unsigned i0 = 0; i0 < 30; ++i0) { + // Mul x (1 << i0) => Shl x i0 + if (imm == (1U << i0)) { + return FoldShl(Op1, EmitIntConst(i0)); + } + + for (unsigned i1 = 0; i1 < i0; ++i1) { + // Mul x ((1 << i0) | (1 << i1)) => Add (Shl x i0) (Shl x i1) + if (imm == ((1U << i0) | ((1U << i1)))) { + return FoldAdd(FoldShl(Op1, EmitIntConst(i0)), FoldShl(Op1, EmitIntConst(i1))); + } + } + } + } + + return EmitBiOp(Mul, Op1, Op2); +} + InstLoc IRBuilder::FoldAnd(InstLoc Op1, InstLoc Op2) { if (isImm(*Op1)) { if (isImm(*Op2)) @@ -402,6 +517,13 @@ InstLoc IRBuilder::FoldAnd(InstLoc Op1, InstLoc Op2) { return Op1; } } + + // TODO: Test the folding below + // And (And x i0) (And y i1) => And (And x y) (i0 & i1) + if (getOpcode(*Op1) == And && getOpcode(*Op2) == And && isImm(*getOp2(Op1)) && isImm(*getOp2(Op2))) { + return FoldAnd(FoldAnd(getOp1(Op1), getOp1(Op2)), EmitIntConst(GetImmValue(getOp2(Op1)) & GetImmValue(getOp2(Op2)))); + } + if (Op1 == Op2) return Op1; return EmitBiOp(And, Op1, Op2); @@ -423,6 +545,12 @@ InstLoc IRBuilder::FoldOr(InstLoc Op1, InstLoc Op2) { return FoldOr(getOp1(Op1), EmitIntConst(RHS)); } } + + // Or (Or x i0) (Or y i1) => Or (Or x y) (i0 | i1) + if (getOpcode(*Op1) == Or && getOpcode(*Op2) == Or && isImm(*getOp2(Op1)) && isImm(*getOp2(Op2))) { + return FoldOr(FoldOr(getOp1(Op1), getOp1(Op2)), EmitIntConst(GetImmValue(getOp2(Op1)) | GetImmValue(getOp2(Op2)))); + } + if (Op1 == Op2) return Op1; return EmitBiOp(Or, Op1, Op2); @@ -450,6 +578,11 @@ InstLoc IRBuilder::FoldXor(InstLoc Op1, InstLoc Op2) { InstLoc IRBuilder::FoldShl(InstLoc Op1, InstLoc Op2) { if (isImm(*Op2)) { + // Shl x 0 => x + if (!GetImmValue(Op2)) { + return Op1; + } + if (isImm(*Op1)) return EmitIntConst(GetImmValue(Op1) << (GetImmValue(Op2) & 31)); } @@ -665,6 +798,7 @@ InstLoc IRBuilder::FoldBiOp(unsigned Opcode, InstLoc Op1, InstLoc Op2, unsigned switch (Opcode) { case Add: return FoldAdd(Op1, Op2); case Sub: return FoldSub(Op1, Op2); + case Mul: return FoldMul(Op1, Op2); case And: return FoldAnd(Op1, Op2); case Or: return FoldOr(Op1, Op2); case Xor: return FoldXor(Op1, Op2); @@ -696,4 +830,16 @@ unsigned IRBuilder::GetImmValue(InstLoc I) { return ConstList[*I >> 8]; } +unsigned IRBuilder::isSameValue(InstLoc Op1, InstLoc Op2) { + if (Op1 == Op2) { + return true; + } + + if (isImm(*Op1) && isImm(*Op2) && GetImmValue(Op1) == GetImmValue(Op2)) { + return true; + } + + return false; +} + } diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h index f2f77263af..a679bf57ce 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h @@ -219,6 +219,7 @@ private: InstLoc FoldAdd(InstLoc Op1, InstLoc Op2); InstLoc FoldSub(InstLoc Op1, InstLoc Op2); + InstLoc FoldMul(InstLoc Op1, InstLoc Op2); InstLoc FoldAnd(InstLoc Op1, InstLoc Op2); InstLoc FoldOr(InstLoc Op1, InstLoc Op2); InstLoc FoldRol(InstLoc Op1, InstLoc Op2); @@ -545,6 +546,8 @@ public: private: IRBuilder(IRBuilder&); // DO NOT IMPLEMENT + unsigned isSameValue(InstLoc Op1, InstLoc Op2); + std::vector InstList; // FIXME: We must ensure this is // continuous! std::vector ConstList;