summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Lewycky <nicholas@mxc.ca>2008-11-21 07:33:58 +0000
committerNick Lewycky <nicholas@mxc.ca>2008-11-21 07:33:58 +0000
commit0c73079855de925bf08335fe39b0b112f3d9407a (patch)
tree551a778e44dbac57cbe75b020b9fa977080e6019
parent41e4a59f2f396519e7026011320760c6d0c179c3 (diff)
downloadllvm-0c73079855de925bf08335fe39b0b112f3d9407a.tar.gz
llvm-0c73079855de925bf08335fe39b0b112f3d9407a.tar.bz2
llvm-0c73079855de925bf08335fe39b0b112f3d9407a.tar.xz
Optimize (x/y)*y into x-(x%y) in general. Div and rem are about the same, and
a subtract is cheaper than a multiply. This generalizes an existing transform. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@59800 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Transforms/Scalar/InstructionCombining.cpp45
-rw-r--r--test/Transforms/InstCombine/2008-11-20-DivMulRem.ll34
2 files changed, 68 insertions, 11 deletions
diff --git a/lib/Transforms/Scalar/InstructionCombining.cpp b/lib/Transforms/Scalar/InstructionCombining.cpp
index e7d596773f..ee6b51cf29 100644
--- a/lib/Transforms/Scalar/InstructionCombining.cpp
+++ b/lib/Transforms/Scalar/InstructionCombining.cpp
@@ -2477,17 +2477,6 @@ Instruction *InstCombiner::visitSub(BinaryOperator &I) {
Constant *CP1 = Subtract(ConstantInt::get(I.getType(), 1), C2);
return BinaryOperator::CreateMul(Op0, CP1);
}
-
- // X - ((X / Y) * Y) --> X % Y
- if (Op1I->getOpcode() == Instruction::Mul)
- if (Instruction *I = dyn_cast<Instruction>(Op1I->getOperand(0)))
- if (Op0 == I->getOperand(0) &&
- Op1I->getOperand(1) == I->getOperand(1)) {
- if (I->getOpcode() == Instruction::SDiv)
- return BinaryOperator::CreateSRem(Op0, Op1I->getOperand(1));
- if (I->getOpcode() == Instruction::UDiv)
- return BinaryOperator::CreateURem(Op0, Op1I->getOperand(1));
- }
}
}
@@ -2622,6 +2611,40 @@ Instruction *InstCombiner::visitMul(BinaryOperator &I) {
if (Value *Op1v = dyn_castNegVal(I.getOperand(1)))
return BinaryOperator::CreateMul(Op0v, Op1v);
+ // (X / Y) * Y = X - (X % Y)
+ // (X / Y) * -Y = (X % Y) - X
+ {
+ Value *Op1 = I.getOperand(1);
+ BinaryOperator *BO = dyn_cast<BinaryOperator>(Op0);
+ if (!BO ||
+ (BO->getOpcode() != Instruction::UDiv &&
+ BO->getOpcode() != Instruction::SDiv)) {
+ Op1 = Op0;
+ BO = dyn_cast<BinaryOperator>(I.getOperand(1));
+ }
+ Value *Neg = dyn_castNegVal(Op1);
+ if (BO && BO->hasOneUse() &&
+ (BO->getOperand(1) == Op1 || BO->getOperand(1) == Neg) &&
+ (BO->getOpcode() == Instruction::UDiv ||
+ BO->getOpcode() == Instruction::SDiv)) {
+ Value *Op0BO = BO->getOperand(0), *Op1BO = BO->getOperand(1);
+
+ Instruction *Rem;
+ if (BO->getOpcode() == Instruction::UDiv)
+ Rem = BinaryOperator::CreateURem(Op0BO, Op1BO);
+ else
+ Rem = BinaryOperator::CreateSRem(Op0BO, Op1BO);
+
+ InsertNewInstBefore(Rem, I);
+ Rem->takeName(BO);
+
+ if (Op1BO == Op1)
+ return BinaryOperator::CreateSub(Op0BO, Rem);
+ else
+ return BinaryOperator::CreateSub(Rem, Op0BO);
+ }
+ }
+
if (I.getType() == Type::Int1Ty)
return BinaryOperator::CreateAnd(Op0, I.getOperand(1));
diff --git a/test/Transforms/InstCombine/2008-11-20-DivMulRem.ll b/test/Transforms/InstCombine/2008-11-20-DivMulRem.ll
new file mode 100644
index 0000000000..8c58a2ae7f
--- /dev/null
+++ b/test/Transforms/InstCombine/2008-11-20-DivMulRem.ll
@@ -0,0 +1,34 @@
+; RUN: llvm-as < %s | opt -instcombine | llvm-dis > %t
+; RUN: grep urem %t | count 3
+; RUN: grep srem %t | count 1
+; RUN: grep sub %t | count 2
+; RUN: grep add %t | count 1
+; PR3103
+
+define i8 @test1(i8 %x, i8 %y) {
+ %A = udiv i8 %x, %y
+ %B = mul i8 %A, %y
+ %C = sub i8 %x, %B
+ ret i8 %C
+}
+
+define i8 @test2(i8 %x, i8 %y) {
+ %A = sdiv i8 %x, %y
+ %B = mul i8 %A, %y
+ %C = sub i8 %x, %B
+ ret i8 %C
+}
+
+define i8 @test3(i8 %x, i8 %y) {
+ %A = udiv i8 %x, %y
+ %B = mul i8 %A, %y
+ %C = sub i8 %B, %x
+ ret i8 %C
+}
+
+define i8 @test4(i8 %x) {
+ %A = udiv i8 %x, 3
+ %B = mul i8 %A, -3
+ %C = sub i8 %x, %B
+ ret i8 %C
+}