[llvm-branch-commits] [llvm] 288f3fc - [InstCombine] reduce icmp(ashr X, C1), C2 to sign-bit test

Sanjay Patel via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Mon Jan 11 12:57:56 PST 2021


Author: Sanjay Patel
Date: 2021-01-11T15:53:39-05:00
New Revision: 288f3fc5dfee0c51fc00fe10a985f93c505073eb

URL: https://github.com/llvm/llvm-project/commit/288f3fc5dfee0c51fc00fe10a985f93c505073eb
DIFF: https://github.com/llvm/llvm-project/commit/288f3fc5dfee0c51fc00fe10a985f93c505073eb.diff

LOG: [InstCombine] reduce icmp(ashr X, C1), C2 to sign-bit test

This is a more basic pattern that we should handle before trying to solve:
https://llvm.org/PR48640

There might be a better way to think about this because the pre-condition
that I came up with (number of sign bits in the compare constant) misses a
potential transform for each of ugt and ult as commented on in the test file.

Tried to model this is in Alive:
https://rise4fun.com/Alive/juX1
...but I couldn't get the ComputeNumSignBits() pre-condition to work as
expected, so replaced with leading 0/1 preconditions instead.

  Name: ugt
  Pre: countLeadingZeros(C2) <= C1 && countLeadingOnes(C2) <= C1
  %a = ashr %x, C1
  %r = icmp ugt i8 %a, C2
    =>
  %r = icmp slt i8 %x, 0

  Name: ult
  Pre: countLeadingZeros(C2) <= C1 && countLeadingOnes(C2) <= C1
  %a = ashr %x, C1
  %r = icmp ult i4 %a, C2
    =>
  %r = icmp sgt i4 %x, -1

Also approximated in Alive2:
https://alive2.llvm.org/ce/z/u5hCcz
https://alive2.llvm.org/ce/z/__szVL

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

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
    llvm/test/Transforms/InstCombine/icmp-shr.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 852def699716..9b3cfb3bd754 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -2210,6 +2210,21 @@ Instruction *InstCombinerImpl::foldICmpShrConstant(ICmpInst &Cmp,
           (ShiftedC + 1).ashr(ShAmtVal) == (C + 1))
         return new ICmpInst(Pred, X, ConstantInt::get(ShrTy, ShiftedC));
     }
+
+    // If the compare constant has significant bits above the lowest sign-bit,
+    // then convert an unsigned cmp to a test of the sign-bit:
+    // (ashr X, ShiftC) u> C --> X s< 0
+    // (ashr X, ShiftC) u< C --> X s> -1
+    if (C.getBitWidth() > 2 && C.getNumSignBits() <= ShAmtVal) {
+      if (Pred == CmpInst::ICMP_UGT) {
+        return new ICmpInst(CmpInst::ICMP_SLT, X,
+                            ConstantInt::getNullValue(ShrTy));
+      }
+      if (Pred == CmpInst::ICMP_ULT) {
+        return new ICmpInst(CmpInst::ICMP_SGT, X,
+                            ConstantInt::getAllOnesValue(ShrTy));
+      }
+    }
   } else {
     if (Pred == CmpInst::ICMP_ULT || (Pred == CmpInst::ICMP_UGT && IsExact)) {
       // icmp ult (lshr X, ShAmtC), C --> icmp ult X, (C << ShAmtC)

diff  --git a/llvm/test/Transforms/InstCombine/icmp-shr.ll b/llvm/test/Transforms/InstCombine/icmp-shr.ll
index 22f61d2d5e6a..ad3eb713aa19 100644
--- a/llvm/test/Transforms/InstCombine/icmp-shr.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-shr.ll
@@ -507,6 +507,10 @@ define <2 x i1> @exact_eq0_multiuse(<2 x i32> %x, <2 x i32> %y) {
   ret <2 x i1> %cmp
 }
 
+; Verify conversions of ashr+icmp to a sign-bit test.
+
+; negative test, but 
diff erent transform possible
+
 define i1 @ashr_ugt_0(i4 %x) {
 ; CHECK-LABEL: @ashr_ugt_0(
 ; CHECK-NEXT:    [[R:%.*]] = icmp ugt i4 [[X:%.*]], 1
@@ -517,6 +521,8 @@ define i1 @ashr_ugt_0(i4 %x) {
   ret i1 %r
 }
 
+; negative test
+
 define i1 @ashr_ugt_1(i4 %x) {
 ; CHECK-LABEL: @ashr_ugt_1(
 ; CHECK-NEXT:    [[S:%.*]] = ashr i4 [[X:%.*]], 1
@@ -528,6 +534,8 @@ define i1 @ashr_ugt_1(i4 %x) {
   ret i1 %r
 }
 
+; negative test
+
 define i1 @ashr_ugt_2(i4 %x) {
 ; CHECK-LABEL: @ashr_ugt_2(
 ; CHECK-NEXT:    [[S:%.*]] = ashr i4 [[X:%.*]], 1
@@ -539,6 +547,9 @@ define i1 @ashr_ugt_2(i4 %x) {
   ret i1 %r
 }
 
+; negative test
+; TODO: This is a sign-bit test, but we don't recognize the pattern.
+
 define i1 @ashr_ugt_3(i4 %x) {
 ; CHECK-LABEL: @ashr_ugt_3(
 ; CHECK-NEXT:    [[S:%.*]] = ashr i4 [[X:%.*]], 1
@@ -552,8 +563,7 @@ define i1 @ashr_ugt_3(i4 %x) {
 
 define i1 @ashr_ugt_4(i4 %x) {
 ; CHECK-LABEL: @ashr_ugt_4(
-; CHECK-NEXT:    [[S:%.*]] = ashr i4 [[X:%.*]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp ugt i4 [[S]], 4
+; CHECK-NEXT:    [[R:%.*]] = icmp slt i4 [[X:%.*]], 0
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %s = ashr i4 %x, 1
@@ -563,8 +573,7 @@ define i1 @ashr_ugt_4(i4 %x) {
 
 define i1 @ashr_ugt_5(i4 %x) {
 ; CHECK-LABEL: @ashr_ugt_5(
-; CHECK-NEXT:    [[S:%.*]] = ashr i4 [[X:%.*]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp ugt i4 [[S]], 5
+; CHECK-NEXT:    [[R:%.*]] = icmp slt i4 [[X:%.*]], 0
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %s = ashr i4 %x, 1
@@ -574,8 +583,7 @@ define i1 @ashr_ugt_5(i4 %x) {
 
 define i1 @ashr_ugt_6(i4 %x) {
 ; CHECK-LABEL: @ashr_ugt_6(
-; CHECK-NEXT:    [[S:%.*]] = ashr i4 [[X:%.*]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp ugt i4 [[S]], 6
+; CHECK-NEXT:    [[R:%.*]] = icmp slt i4 [[X:%.*]], 0
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %s = ashr i4 %x, 1
@@ -595,8 +603,7 @@ define i1 @ashr_ugt_7(i4 %x) {
 
 define i1 @ashr_ugt_8(i4 %x) {
 ; CHECK-LABEL: @ashr_ugt_8(
-; CHECK-NEXT:    [[S:%.*]] = ashr i4 [[X:%.*]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp ugt i4 [[S]], -8
+; CHECK-NEXT:    [[R:%.*]] = icmp slt i4 [[X:%.*]], 0
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %s = ashr i4 %x, 1
@@ -606,8 +613,7 @@ define i1 @ashr_ugt_8(i4 %x) {
 
 define i1 @ashr_ugt_9(i4 %x) {
 ; CHECK-LABEL: @ashr_ugt_9(
-; CHECK-NEXT:    [[S:%.*]] = ashr i4 [[X:%.*]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp ugt i4 [[S]], -7
+; CHECK-NEXT:    [[R:%.*]] = icmp slt i4 [[X:%.*]], 0
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %s = ashr i4 %x, 1
@@ -617,8 +623,7 @@ define i1 @ashr_ugt_9(i4 %x) {
 
 define i1 @ashr_ugt_10(i4 %x) {
 ; CHECK-LABEL: @ashr_ugt_10(
-; CHECK-NEXT:    [[S:%.*]] = ashr i4 [[X:%.*]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp ugt i4 [[S]], -6
+; CHECK-NEXT:    [[R:%.*]] = icmp slt i4 [[X:%.*]], 0
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %s = ashr i4 %x, 1
@@ -628,8 +633,7 @@ define i1 @ashr_ugt_10(i4 %x) {
 
 define i1 @ashr_ugt_11(i4 %x) {
 ; CHECK-LABEL: @ashr_ugt_11(
-; CHECK-NEXT:    [[S:%.*]] = ashr i4 [[X:%.*]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp ugt i4 [[S]], -5
+; CHECK-NEXT:    [[R:%.*]] = icmp slt i4 [[X:%.*]], 0
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %s = ashr i4 %x, 1
@@ -637,6 +641,8 @@ define i1 @ashr_ugt_11(i4 %x) {
   ret i1 %r
 }
 
+; negative test
+
 define i1 @ashr_ugt_12(i4 %x) {
 ; CHECK-LABEL: @ashr_ugt_12(
 ; CHECK-NEXT:    [[S:%.*]] = ashr i4 [[X:%.*]], 1
@@ -648,6 +654,8 @@ define i1 @ashr_ugt_12(i4 %x) {
   ret i1 %r
 }
 
+; negative test
+
 define i1 @ashr_ugt_13(i4 %x) {
 ; CHECK-LABEL: @ashr_ugt_13(
 ; CHECK-NEXT:    [[S:%.*]] = ashr i4 [[X:%.*]], 1
@@ -659,6 +667,8 @@ define i1 @ashr_ugt_13(i4 %x) {
   ret i1 %r
 }
 
+; negative test, but 
diff erent transform possible
+
 define i1 @ashr_ugt_14(i4 %x) {
 ; CHECK-LABEL: @ashr_ugt_14(
 ; CHECK-NEXT:    [[R:%.*]] = icmp ugt i4 [[X:%.*]], -3
@@ -669,6 +679,8 @@ define i1 @ashr_ugt_14(i4 %x) {
   ret i1 %r
 }
 
+; negative test, but simplifies
+
 define i1 @ashr_ugt_15(i4 %x) {
 ; CHECK-LABEL: @ashr_ugt_15(
 ; CHECK-NEXT:    ret i1 false
@@ -678,6 +690,8 @@ define i1 @ashr_ugt_15(i4 %x) {
   ret i1 %r
 }
 
+; negative test, but simplifies
+
 define i1 @ashr_ult_0(i4 %x) {
 ; CHECK-LABEL: @ashr_ult_0(
 ; CHECK-NEXT:    ret i1 false
@@ -687,6 +701,8 @@ define i1 @ashr_ult_0(i4 %x) {
   ret i1 %r
 }
 
+; negative test, but 
diff erent transform possible
+
 define i1 @ashr_ult_1(i4 %x) {
 ; CHECK-LABEL: @ashr_ult_1(
 ; CHECK-NEXT:    [[R:%.*]] = icmp ult i4 [[X:%.*]], 2
@@ -697,6 +713,8 @@ define i1 @ashr_ult_1(i4 %x) {
   ret i1 %r
 }
 
+; negative test
+
 define i1 @ashr_ult_2(i4 %x) {
 ; CHECK-LABEL: @ashr_ult_2(
 ; CHECK-NEXT:    [[S:%.*]] = ashr i4 [[X:%.*]], 1
@@ -708,6 +726,8 @@ define i1 @ashr_ult_2(i4 %x) {
   ret i1 %r
 }
 
+; negative test
+
 define i1 @ashr_ult_3(i4 %x) {
 ; CHECK-LABEL: @ashr_ult_3(
 ; CHECK-NEXT:    [[S:%.*]] = ashr i4 [[X:%.*]], 1
@@ -721,8 +741,7 @@ define i1 @ashr_ult_3(i4 %x) {
 
 define i1 @ashr_ult_4(i4 %x) {
 ; CHECK-LABEL: @ashr_ult_4(
-; CHECK-NEXT:    [[S:%.*]] = ashr i4 [[X:%.*]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp ult i4 [[S]], 4
+; CHECK-NEXT:    [[R:%.*]] = icmp sgt i4 [[X:%.*]], -1
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %s = ashr i4 %x, 1
@@ -732,8 +751,7 @@ define i1 @ashr_ult_4(i4 %x) {
 
 define i1 @ashr_ult_5(i4 %x) {
 ; CHECK-LABEL: @ashr_ult_5(
-; CHECK-NEXT:    [[S:%.*]] = ashr i4 [[X:%.*]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp ult i4 [[S]], 5
+; CHECK-NEXT:    [[R:%.*]] = icmp sgt i4 [[X:%.*]], -1
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %s = ashr i4 %x, 1
@@ -743,8 +761,7 @@ define i1 @ashr_ult_5(i4 %x) {
 
 define i1 @ashr_ult_6(i4 %x) {
 ; CHECK-LABEL: @ashr_ult_6(
-; CHECK-NEXT:    [[S:%.*]] = ashr i4 [[X:%.*]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp ult i4 [[S]], 6
+; CHECK-NEXT:    [[R:%.*]] = icmp sgt i4 [[X:%.*]], -1
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %s = ashr i4 %x, 1
@@ -754,8 +771,7 @@ define i1 @ashr_ult_6(i4 %x) {
 
 define i1 @ashr_ult_7(i4 %x) {
 ; CHECK-LABEL: @ashr_ult_7(
-; CHECK-NEXT:    [[S:%.*]] = ashr i4 [[X:%.*]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp ult i4 [[S]], 7
+; CHECK-NEXT:    [[R:%.*]] = icmp sgt i4 [[X:%.*]], -1
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %s = ashr i4 %x, 1
@@ -775,8 +791,7 @@ define i1 @ashr_ult_8(i4 %x) {
 
 define i1 @ashr_ult_9(i4 %x) {
 ; CHECK-LABEL: @ashr_ult_9(
-; CHECK-NEXT:    [[S:%.*]] = ashr i4 [[X:%.*]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp ult i4 [[S]], -7
+; CHECK-NEXT:    [[R:%.*]] = icmp sgt i4 [[X:%.*]], -1
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %s = ashr i4 %x, 1
@@ -786,8 +801,7 @@ define i1 @ashr_ult_9(i4 %x) {
 
 define i1 @ashr_ult_10(i4 %x) {
 ; CHECK-LABEL: @ashr_ult_10(
-; CHECK-NEXT:    [[S:%.*]] = ashr i4 [[X:%.*]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp ult i4 [[S]], -6
+; CHECK-NEXT:    [[R:%.*]] = icmp sgt i4 [[X:%.*]], -1
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %s = ashr i4 %x, 1
@@ -797,8 +811,7 @@ define i1 @ashr_ult_10(i4 %x) {
 
 define i1 @ashr_ult_11(i4 %x) {
 ; CHECK-LABEL: @ashr_ult_11(
-; CHECK-NEXT:    [[S:%.*]] = ashr i4 [[X:%.*]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp ult i4 [[S]], -5
+; CHECK-NEXT:    [[R:%.*]] = icmp sgt i4 [[X:%.*]], -1
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %s = ashr i4 %x, 1
@@ -806,6 +819,9 @@ define i1 @ashr_ult_11(i4 %x) {
   ret i1 %r
 }
 
+; negative test
+; TODO: This is a sign-bit test, but we don't recognize the pattern.
+
 define i1 @ashr_ult_12(i4 %x) {
 ; CHECK-LABEL: @ashr_ult_12(
 ; CHECK-NEXT:    [[S:%.*]] = ashr i4 [[X:%.*]], 1
@@ -817,6 +833,8 @@ define i1 @ashr_ult_12(i4 %x) {
   ret i1 %r
 }
 
+; negative test
+
 define i1 @ashr_ult_13(i4 %x) {
 ; CHECK-LABEL: @ashr_ult_13(
 ; CHECK-NEXT:    [[S:%.*]] = ashr i4 [[X:%.*]], 1
@@ -828,6 +846,8 @@ define i1 @ashr_ult_13(i4 %x) {
   ret i1 %r
 }
 
+; negative test
+
 define i1 @ashr_ult_14(i4 %x) {
 ; CHECK-LABEL: @ashr_ult_14(
 ; CHECK-NEXT:    [[S:%.*]] = ashr i4 [[X:%.*]], 1
@@ -839,6 +859,8 @@ define i1 @ashr_ult_14(i4 %x) {
   ret i1 %r
 }
 
+; negative test, but 
diff erent transform possible
+
 define i1 @ashr_ult_15(i4 %x) {
 ; CHECK-LABEL: @ashr_ult_15(
 ; CHECK-NEXT:    [[R:%.*]] = icmp ult i4 [[X:%.*]], -2


        


More information about the llvm-branch-commits mailing list