summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2010-11-21 06:44:42 +0000
committerChris Lattner <sabre@nondot.org>2010-11-21 06:44:42 +0000
commit75d8f599e72c151df48a28bebc6e4e342f469b8a (patch)
tree204abb357393b3d57e53da6a821c9780ded364f2
parent79a980ad85286614bbb4c68c84ea9e3c6ed36d0d (diff)
downloadllvm-75d8f599e72c151df48a28bebc6e4e342f469b8a.tar.gz
llvm-75d8f599e72c151df48a28bebc6e4e342f469b8a.tar.bz2
llvm-75d8f599e72c151df48a28bebc6e4e342f469b8a.tar.xz
optimize:
void a(int x) { if (((1<<x)&8)==0) b(); } into "x != 3", which occurs over 100 times in 403.gcc but in no other program in llvm-test. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@119922 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Target/README.txt8
-rw-r--r--lib/Transforms/InstCombine/InstCombineCompares.cpp74
-rw-r--r--test/Transforms/InstCombine/icmp.ll38
3 files changed, 110 insertions, 10 deletions
diff --git a/lib/Target/README.txt b/lib/Target/README.txt
index 629b55d004..06661c9335 100644
--- a/lib/Target/README.txt
+++ b/lib/Target/README.txt
@@ -1699,14 +1699,6 @@ This should be optimized to a single compare. Testcase derived from gcc.
//===---------------------------------------------------------------------===//
-Missed instcombine transformation:
-void b();
-void a(int x) { if (((1<<x)&8)==0) b(); }
-
-The shift should be optimized out. Testcase derived from gcc.
-
-//===---------------------------------------------------------------------===//
-
Missed instcombine or reassociate transformation:
int a(int a, int b) { return (a==12)&(b>47)&(b<58); }
diff --git a/lib/Transforms/InstCombine/InstCombineCompares.cpp b/lib/Transforms/InstCombine/InstCombineCompares.cpp
index d7e2b72b7f..8a35a5fcf3 100644
--- a/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -1744,14 +1744,84 @@ Instruction *InstCombiner::visitICmpInst(ICmpInst &I) {
// simplify this comparison. For example, (x&4) < 8 is always true.
switch (I.getPredicate()) {
default: llvm_unreachable("Unknown icmp opcode!");
- case ICmpInst::ICMP_EQ:
+ case ICmpInst::ICMP_EQ: {
if (Op0Max.ult(Op1Min) || Op0Min.ugt(Op1Max))
return ReplaceInstUsesWith(I, ConstantInt::getFalse(I.getContext()));
+
+ // If all bits are known zero except for one, then we know at most one
+ // bit is set. If the comparison is against zero, then this is a check
+ // to see if *that* bit is set.
+ APInt Op0KnownZeroInverted = ~Op0KnownZero;
+ if (~Op1KnownZero == 0 && Op0KnownZeroInverted.isPowerOf2()) {
+ // If the LHS is an AND with the same constant, look through it.
+ Value *LHS = 0;
+ ConstantInt *LHSC = 0;
+ if (!match(Op0, m_And(m_Value(LHS), m_ConstantInt(LHSC))) ||
+ LHSC->getValue() != Op0KnownZeroInverted)
+ LHS = Op0;
+
+ // If the LHS is 1 << x, and we know the result is a power of 2 like 8,
+ // then turn "((1 << x)&8) == 0" into "x == 3".
+ Value *X = 0;
+ if (match(LHS, m_Shl(m_One(), m_Value(X)))) {
+ unsigned CmpVal = Op0KnownZeroInverted.countTrailingZeros();
+ return new ICmpInst(ICmpInst::ICMP_EQ, X,
+ ConstantInt::get(X->getType(), CmpVal));
+ }
+
+ // If the LHS is 8 >>u x, and we know the result is a power of 2 like 1,
+ // then turn "((8 >>u x)&1) == 0" into "x == 3".
+ ConstantInt *CI = 0;
+ if (Op0KnownZeroInverted == 1 &&
+ match(LHS, m_LShr(m_ConstantInt(CI), m_Value(X))) &&
+ CI->getValue().isPowerOf2()) {
+ unsigned CmpVal = CI->getValue().countTrailingZeros();
+ return new ICmpInst(ICmpInst::ICMP_EQ, X,
+ ConstantInt::get(X->getType(), CmpVal));
+ }
+ }
+
break;
- case ICmpInst::ICMP_NE:
+ }
+ case ICmpInst::ICMP_NE: {
if (Op0Max.ult(Op1Min) || Op0Min.ugt(Op1Max))
return ReplaceInstUsesWith(I, ConstantInt::getTrue(I.getContext()));
+
+ // If all bits are known zero except for one, then we know at most one
+ // bit is set. If the comparison is against zero, then this is a check
+ // to see if *that* bit is set.
+ APInt Op0KnownZeroInverted = ~Op0KnownZero;
+ if (~Op1KnownZero == 0 && Op0KnownZeroInverted.isPowerOf2()) {
+ // If the LHS is an AND with the same constant, look through it.
+ Value *LHS = 0;
+ ConstantInt *LHSC = 0;
+ if (!match(Op0, m_And(m_Value(LHS), m_ConstantInt(LHSC))) ||
+ LHSC->getValue() != Op0KnownZeroInverted)
+ LHS = Op0;
+
+ // If the LHS is 1 << x, and we know the result is a power of 2 like 8,
+ // then turn "((1 << x)&8) != 0" into "x != 3".
+ Value *X = 0;
+ if (match(LHS, m_Shl(m_One(), m_Value(X)))) {
+ unsigned CmpVal = Op0KnownZeroInverted.countTrailingZeros();
+ return new ICmpInst(ICmpInst::ICMP_NE, X,
+ ConstantInt::get(X->getType(), CmpVal));
+ }
+
+ // If the LHS is 8 >>u x, and we know the result is a power of 2 like 1,
+ // then turn "((8 >>u x)&1) != 0" into "x != 3".
+ ConstantInt *CI = 0;
+ if (Op0KnownZeroInverted == 1 &&
+ match(LHS, m_LShr(m_ConstantInt(CI), m_Value(X))) &&
+ CI->getValue().isPowerOf2()) {
+ unsigned CmpVal = CI->getValue().countTrailingZeros();
+ return new ICmpInst(ICmpInst::ICMP_NE, X,
+ ConstantInt::get(X->getType(), CmpVal));
+ }
+ }
+
break;
+ }
case ICmpInst::ICMP_ULT:
if (Op0Max.ult(Op1Min)) // A <u B -> true if max(A) < min(B)
return ReplaceInstUsesWith(I, ConstantInt::getTrue(I.getContext()));
diff --git a/test/Transforms/InstCombine/icmp.ll b/test/Transforms/InstCombine/icmp.ll
index 802957f47b..96038ca56b 100644
--- a/test/Transforms/InstCombine/icmp.ll
+++ b/test/Transforms/InstCombine/icmp.ll
@@ -154,3 +154,41 @@ entry:
; CHECK: @test16
; CHECK: ret i1 undef
}
+
+define i1 @test17(i32 %x) nounwind {
+ %shl = shl i32 1, %x
+ %and = and i32 %shl, 8
+ %cmp = icmp eq i32 %and, 0
+ ret i1 %cmp
+; CHECK: @test17
+; CHECK-NEXT: %cmp = icmp eq i32 %x, 3
+}
+
+
+define i1 @test18(i32 %x) nounwind {
+ %sh = lshr i32 8, %x
+ %and = and i32 %sh, 1
+ %cmp = icmp eq i32 %and, 0
+ ret i1 %cmp
+; CHECK: @test18
+; CHECK-NEXT: %cmp = icmp eq i32 %x, 3
+}
+
+define i1 @test19(i32 %x) nounwind {
+ %shl = shl i32 1, %x
+ %and = and i32 %shl, 8
+ %cmp = icmp eq i32 %and, 8
+ ret i1 %cmp
+; CHECK: @test19
+; CHECK-NEXT: %cmp = icmp ne i32 %x, 3
+}
+
+define i1 @test20(i32 %x) nounwind {
+ %shl = shl i32 1, %x
+ %and = and i32 %shl, 8
+ %cmp = icmp ne i32 %and, 0
+ ret i1 %cmp
+; CHECK: @test20
+; CHECK-NEXT: %cmp = icmp ne i32 %x, 3
+}
+