[llvm] r292492 - [InstCombine] icmp Pred (shl nsw X, C1), C0 --> icmp Pred X, C0 >> C1

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 19 08:12:10 PST 2017


Author: spatel
Date: Thu Jan 19 10:12:10 2017
New Revision: 292492

URL: http://llvm.org/viewvc/llvm-project?rev=292492&view=rev
Log:
[InstCombine] icmp Pred (shl nsw X, C1), C0 --> icmp Pred X, C0 >> C1

Try harder to fold icmp with shl nsw as discussed here:
http://lists.llvm.org/pipermail/llvm-dev/2017-January/108749.html

This is similar to the 'shl nuw' transforms that were added with D25913.

This may eventually help solve:
https://llvm.org/bugs/show_bug.cgi?id=30773

Differential Revision: https://reviews.llvm.org/D28406


Modified:
    llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp
    llvm/trunk/test/Transforms/InstCombine/icmp-shl-nsw.ll

Modified: llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp?rev=292492&r1=292491&r2=292492&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp (original)
+++ llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp Thu Jan 19 10:12:10 2017
@@ -1912,14 +1912,42 @@ Instruction *InstCombiner::foldICmpShlCo
   Value *X = Shl->getOperand(0);
   Type *ShType = Shl->getType();
 
-  // If this is a signed comparison to 0 and the shift is sign preserving,
-  // use the shift LHS operand instead; isSignTest may change 'Pred', so only
-  // do that if we're sure to not continue on in this function.
-  if (Shl->hasNoSignedWrap() && isSignTest(Pred, *C))
-    return new ICmpInst(Pred, X, Constant::getNullValue(ShType));
+  // NSW guarantees that we are only shifting out sign bits from the high bits,
+  // so we can ASHR the compare constant without needing a mask and eliminate
+  // the shift.
+  if (Shl->hasNoSignedWrap()) {
+    if (Pred == ICmpInst::ICMP_SGT) {
+      // icmp Pred (shl nsw X, ShiftAmt), C --> icmp Pred X, (C >>s ShiftAmt)
+      APInt ShiftedC = C->ashr(*ShiftAmt);
+      return new ICmpInst(Pred, X, ConstantInt::get(ShType, ShiftedC));
+    }
+    if (Pred == ICmpInst::ICMP_EQ || Pred == ICmpInst::ICMP_NE) {
+      // This is the same code as the SGT case, but assert the pre-condition
+      // that is needed for this to work with equality predicates.
+      assert(C->ashr(*ShiftAmt).shl(*ShiftAmt) == *C &&
+             "Compare known true or false was not folded");
+      APInt ShiftedC = C->ashr(*ShiftAmt);
+      return new ICmpInst(Pred, X, ConstantInt::get(ShType, ShiftedC));
+    }
+    if (Pred == ICmpInst::ICMP_SLT) {
+      // SLE is the same as above, but SLE is canonicalized to SLT, so convert:
+      // (X << S) <=s C is equiv to X <=s (C >> S) for all C
+      // (X << S) <s (C + 1) is equiv to X <s (C >> S) + 1 if C <s SMAX
+      // (X << S) <s C is equiv to X <s ((C - 1) >> S) + 1 if C >s SMIN
+      assert(!C->isMinSignedValue() && "Unexpected icmp slt");
+      APInt ShiftedC = (*C - 1).ashr(*ShiftAmt) + 1;
+      return new ICmpInst(Pred, X, ConstantInt::get(ShType, ShiftedC));
+    }
+    // If this is a signed comparison to 0 and the shift is sign preserving,
+    // use the shift LHS operand instead; isSignTest may change 'Pred', so only
+    // do that if we're sure to not continue on in this function.
+    if (isSignTest(Pred, *C))
+      return new ICmpInst(Pred, X, Constant::getNullValue(ShType));
+  }
 
-  // A 'shl nuw' is just shifting out zeros, so adjust the compare constant
-  // and eliminate the shift.
+  // NUW guarantees that we are only shifting out zero bits from the high bits,
+  // so we can LSHR the compare constant without needing a mask and eliminate
+  // the shift.
   if (Shl->hasNoUnsignedWrap()) {
     if (Pred == ICmpInst::ICMP_UGT) {
       // icmp Pred (shl nuw X, ShiftAmt), C --> icmp Pred X, (C >>u ShiftAmt)
@@ -1945,23 +1973,14 @@ Instruction *InstCombiner::foldICmpShlCo
     }
   }
 
-  if (Cmp.isEquality()) {
+  if (Cmp.isEquality() && Shl->hasOneUse()) {
+    // Strength-reduce the shift into an 'and'.
+    Constant *Mask = ConstantInt::get(
+        ShType,
+        APInt::getLowBitsSet(TypeBits, TypeBits - ShiftAmt->getZExtValue()));
+    Value *And = Builder->CreateAnd(X, Mask, Shl->getName() + ".mask");
     Constant *LShrC = ConstantInt::get(ShType, C->lshr(*ShiftAmt));
-
-    // If the shift is NSW and we compare to 0, then it is just shifting out
-    // sign bits, no need for an AND either.
-    if (Shl->hasNoSignedWrap() && *C == 0)
-      return new ICmpInst(Pred, X, LShrC);
-
-    if (Shl->hasOneUse()) {
-      // Otherwise, strength-reduce the shift into an 'and'.
-      Constant *Mask = ConstantInt::get(
-          ShType,
-          APInt::getLowBitsSet(TypeBits, TypeBits - ShiftAmt->getZExtValue()));
-
-      Value *And = Builder->CreateAnd(X, Mask, Shl->getName() + ".mask");
-      return new ICmpInst(Pred, And, LShrC);
-    }
+    return new ICmpInst(Pred, And, LShrC);
   }
 
   // Otherwise, if this is a comparison of the sign bit, simplify to and/test.

Modified: llvm/trunk/test/Transforms/InstCombine/icmp-shl-nsw.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/icmp-shl-nsw.ll?rev=292492&r1=292491&r2=292492&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/icmp-shl-nsw.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/icmp-shl-nsw.ll Thu Jan 19 10:12:10 2017
@@ -73,8 +73,7 @@ define <2 x i1> @icmp_shl_nsw_eq_vec(<2
 
 define i1 @icmp_sgt1(i8 %x) {
 ; CHECK-LABEL: @icmp_sgt1(
-; CHECK-NEXT:    [[SHL_MASK:%.*]] = and i8 %x, 127
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 [[SHL_MASK]], 64
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 %x, -64
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %shl = shl nsw i8 %x, 1
@@ -84,8 +83,7 @@ define i1 @icmp_sgt1(i8 %x) {
 
 define i1 @icmp_sgt2(i8 %x) {
 ; CHECK-LABEL: @icmp_sgt2(
-; CHECK-NEXT:    [[SHL:%.*]] = shl nsw i8 %x, 1
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[SHL]], -127
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 %x, -64
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %shl = shl nsw i8 %x, 1
@@ -95,8 +93,7 @@ define i1 @icmp_sgt2(i8 %x) {
 
 define i1 @icmp_sgt3(i8 %x) {
 ; CHECK-LABEL: @icmp_sgt3(
-; CHECK-NEXT:    [[SHL:%.*]] = shl nsw i8 %x, 1
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[SHL]], -16
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 %x, -8
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %shl = shl nsw i8 %x, 1
@@ -106,8 +103,7 @@ define i1 @icmp_sgt3(i8 %x) {
 
 define i1 @icmp_sgt4(i8 %x) {
 ; CHECK-LABEL: @icmp_sgt4(
-; CHECK-NEXT:    [[SHL:%.*]] = shl nsw i8 %x, 1
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[SHL]], -2
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 %x, -1
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %shl = shl nsw i8 %x, 1
@@ -120,8 +116,7 @@ define i1 @icmp_sgt4(i8 %x) {
 
 define i1 @icmp_sgt5(i8 %x) {
 ; CHECK-LABEL: @icmp_sgt5(
-; CHECK-NEXT:    [[SHL:%.*]] = shl nsw i8 %x, 1
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[SHL]], 1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 %x, 0
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %shl = shl nsw i8 %x, 1
@@ -131,8 +126,7 @@ define i1 @icmp_sgt5(i8 %x) {
 
 define i1 @icmp_sgt6(i8 %x) {
 ; CHECK-LABEL: @icmp_sgt6(
-; CHECK-NEXT:    [[SHL:%.*]] = shl nsw i8 %x, 1
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[SHL]], 16
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 %x, 8
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %shl = shl nsw i8 %x, 1
@@ -142,8 +136,7 @@ define i1 @icmp_sgt6(i8 %x) {
 
 define i1 @icmp_sgt7(i8 %x) {
 ; CHECK-LABEL: @icmp_sgt7(
-; CHECK-NEXT:    [[SHL:%.*]] = shl nsw i8 %x, 1
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[SHL]], 124
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 %x, 62
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %shl = shl nsw i8 %x, 1
@@ -155,8 +148,7 @@ define i1 @icmp_sgt7(i8 %x) {
 
 define i1 @icmp_sgt8(i8 %x) {
 ; CHECK-LABEL: @icmp_sgt8(
-; CHECK-NEXT:    [[SHL_MASK:%.*]] = and i8 %x, 127
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[SHL_MASK]], 63
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 %x, 63
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %shl = shl nsw i8 %x, 1
@@ -170,8 +162,7 @@ define i1 @icmp_sgt8(i8 %x) {
 
 define i1 @icmp_sgt9(i8 %x) {
 ; CHECK-LABEL: @icmp_sgt9(
-; CHECK-NEXT:    [[SHL_MASK:%.*]] = and i8 %x, 1
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[SHL_MASK]], 0
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 %x, -1
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %shl = shl nsw i8 %x, 7
@@ -181,8 +172,7 @@ define i1 @icmp_sgt9(i8 %x) {
 
 define i1 @icmp_sgt10(i8 %x) {
 ; CHECK-LABEL: @icmp_sgt10(
-; CHECK-NEXT:    [[SHL:%.*]] = shl nsw i8 %x, 7
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[SHL]], -127
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 %x, -1
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %shl = shl nsw i8 %x, 7
@@ -192,8 +182,7 @@ define i1 @icmp_sgt10(i8 %x) {
 
 define i1 @icmp_sgt11(i8 %x) {
 ; CHECK-LABEL: @icmp_sgt11(
-; CHECK-NEXT:    [[SHL:%.*]] = shl nsw i8 %x, 7
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 [[SHL]], -2
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt i8 %x, -1
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %shl = shl nsw i8 %x, 7
@@ -205,8 +194,7 @@ define i1 @icmp_sgt11(i8 %x) {
 
 define <2 x i1> @icmp_sgt11_vec(<2 x i8> %x) {
 ; CHECK-LABEL: @icmp_sgt11_vec(
-; CHECK-NEXT:    [[SHL:%.*]] = shl nsw <2 x i8> %x, <i8 7, i8 7>
-; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt <2 x i8> [[SHL]], <i8 -2, i8 -2>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp sgt <2 x i8> %x, <i8 -1, i8 -1>
 ; CHECK-NEXT:    ret <2 x i1> [[CMP]]
 ;
   %shl = shl nsw <2 x i8> %x, <i8 7, i8 7>
@@ -226,8 +214,7 @@ define <2 x i1> @icmp_sgt11_vec(<2 x i8>
 
 define i1 @icmp_sle1(i8 %x) {
 ; CHECK-LABEL: @icmp_sle1(
-; CHECK-NEXT:    [[SHL_MASK:%.*]] = and i8 %x, 127
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[SHL_MASK]], 64
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 %x, -64
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %shl = shl nsw i8 %x, 1
@@ -237,8 +224,7 @@ define i1 @icmp_sle1(i8 %x) {
 
 define i1 @icmp_sle2(i8 %x) {
 ; CHECK-LABEL: @icmp_sle2(
-; CHECK-NEXT:    [[SHL:%.*]] = shl nsw i8 %x, 1
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[SHL]], -126
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 %x, -63
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %shl = shl nsw i8 %x, 1
@@ -248,8 +234,7 @@ define i1 @icmp_sle2(i8 %x) {
 
 define i1 @icmp_sle3(i8 %x) {
 ; CHECK-LABEL: @icmp_sle3(
-; CHECK-NEXT:    [[SHL:%.*]] = shl nsw i8 %x, 1
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[SHL]], -15
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 %x, -7
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %shl = shl nsw i8 %x, 1
@@ -259,8 +244,7 @@ define i1 @icmp_sle3(i8 %x) {
 
 define i1 @icmp_sle4(i8 %x) {
 ; CHECK-LABEL: @icmp_sle4(
-; CHECK-NEXT:    [[SHL:%.*]] = shl nsw i8 %x, 1
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[SHL]], -1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 %x, 0
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %shl = shl nsw i8 %x, 1
@@ -273,8 +257,7 @@ define i1 @icmp_sle4(i8 %x) {
 
 define i1 @icmp_sle5(i8 %x) {
 ; CHECK-LABEL: @icmp_sle5(
-; CHECK-NEXT:    [[SHL:%.*]] = shl nsw i8 %x, 1
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[SHL]], 2
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 %x, 1
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %shl = shl nsw i8 %x, 1
@@ -284,8 +267,7 @@ define i1 @icmp_sle5(i8 %x) {
 
 define i1 @icmp_sle6(i8 %x) {
 ; CHECK-LABEL: @icmp_sle6(
-; CHECK-NEXT:    [[SHL:%.*]] = shl nsw i8 %x, 1
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[SHL]], 17
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 %x, 9
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %shl = shl nsw i8 %x, 1
@@ -295,8 +277,7 @@ define i1 @icmp_sle6(i8 %x) {
 
 define i1 @icmp_sle7(i8 %x) {
 ; CHECK-LABEL: @icmp_sle7(
-; CHECK-NEXT:    [[SHL:%.*]] = shl nsw i8 %x, 1
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[SHL]], 125
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 %x, 63
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %shl = shl nsw i8 %x, 1
@@ -308,8 +289,7 @@ define i1 @icmp_sle7(i8 %x) {
 
 define i1 @icmp_sle8(i8 %x) {
 ; CHECK-LABEL: @icmp_sle8(
-; CHECK-NEXT:    [[SHL_MASK:%.*]] = and i8 %x, 127
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 [[SHL_MASK]], 63
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 %x, 63
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %shl = shl nsw i8 %x, 1
@@ -323,8 +303,7 @@ define i1 @icmp_sle8(i8 %x) {
 
 define i1 @icmp_sle9(i8 %x) {
 ; CHECK-LABEL: @icmp_sle9(
-; CHECK-NEXT:    [[SHL_MASK:%.*]] = and i8 %x, 1
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 [[SHL_MASK]], 0
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 %x, -1
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %shl = shl nsw i8 %x, 7
@@ -334,8 +313,7 @@ define i1 @icmp_sle9(i8 %x) {
 
 define i1 @icmp_sle10(i8 %x) {
 ; CHECK-LABEL: @icmp_sle10(
-; CHECK-NEXT:    [[SHL:%.*]] = shl nsw i8 %x, 7
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[SHL]], -126
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 %x, 0
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %shl = shl nsw i8 %x, 7
@@ -345,8 +323,7 @@ define i1 @icmp_sle10(i8 %x) {
 
 define i1 @icmp_sle11(i8 %x) {
 ; CHECK-LABEL: @icmp_sle11(
-; CHECK-NEXT:    [[SHL:%.*]] = shl nsw i8 %x, 7
-; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[SHL]], -1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 %x, 0
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %shl = shl nsw i8 %x, 7
@@ -359,8 +336,7 @@ define i1 @icmp_sle11(i8 %x) {
 
 define i1 @icmp_eq1(i8 %x) {
 ; CHECK-LABEL: @icmp_eq1(
-; CHECK-NEXT:    [[SHL_MASK:%.*]] = and i8 %x, 127
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[SHL_MASK]], 6
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 %x, 6
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %shl = shl nsw i8 %x, 1
@@ -370,8 +346,7 @@ define i1 @icmp_eq1(i8 %x) {
 
 define i1 @icmp_ne1(i8 %x) {
 ; CHECK-LABEL: @icmp_ne1(
-; CHECK-NEXT:    [[SHL_MASK:%.*]] = and i8 %x, 3
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 [[SHL_MASK]], 2
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 %x, -2
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %shl = shl nsw i8 %x, 6




More information about the llvm-commits mailing list