[llvm] 0be0a12 - [ValueTracking] improve analysis for "C << X" and "C >> X"

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 9 09:56:41 PST 2021


Author: Sanjay Patel
Date: 2021-02-09T12:38:06-05:00
New Revision: 0be0a1237cb9d9a0228cf27dacfcd0b95749d7ee

URL: https://github.com/llvm/llvm-project/commit/0be0a1237cb9d9a0228cf27dacfcd0b95749d7ee
DIFF: https://github.com/llvm/llvm-project/commit/0be0a1237cb9d9a0228cf27dacfcd0b95749d7ee.diff

LOG: [ValueTracking] improve analysis for "C << X" and "C >> X"

This is based on the example/comments in:
https://llvm.org/PR48984

I tried just lifting the restriction in computeKnownBitsFromShiftOperator()
as suggested in the bug report, but that doesn't catch all of the cases
shown here. I didn't step through to see exactly why that happened. But it
seems like a reasonable compromise to cheaply check the special-case of
shifting a constant.

There's a slight regression on a cmp transform as noted, but this is likely
the more important/common pattern, so we can fix that icmp pattern later if
needed.

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

Added: 
    

Modified: 
    llvm/lib/Analysis/ValueTracking.cpp
    llvm/test/Transforms/InstCombine/and2.ll
    llvm/test/Transforms/InstCombine/lshr-and-negC-icmpeq-zero.ll
    llvm/test/Transforms/InstCombine/shift.ll
    llvm/test/Transforms/InstCombine/signbit-shl-and-icmpeq-zero.ll
    llvm/test/Transforms/InstCombine/zext-or-icmp.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 6bb629285edc..567d674ec721 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -1229,6 +1229,10 @@ static void computeKnownBitsFromOperator(const Operator *I,
     };
     computeKnownBitsFromShiftOperator(I, DemandedElts, Known, Known2, Depth, Q,
                                       KF);
+    // Trailing zeros of a right-shifted constant never decrease.
+    const APInt *C;
+    if (match(I->getOperand(0), m_APInt(C)))
+      Known.Zero.setLowBits(C->countTrailingZeros());
     break;
   }
   case Instruction::LShr: {
@@ -1237,6 +1241,10 @@ static void computeKnownBitsFromOperator(const Operator *I,
     };
     computeKnownBitsFromShiftOperator(I, DemandedElts, Known, Known2, Depth, Q,
                                       KF);
+    // Leading zeros of a left-shifted constant never decrease.
+    const APInt *C;
+    if (match(I->getOperand(0), m_APInt(C)))
+      Known.Zero.setHighBits(C->countLeadingZeros());
     break;
   }
   case Instruction::AShr: {

diff  --git a/llvm/test/Transforms/InstCombine/and2.ll b/llvm/test/Transforms/InstCombine/and2.ll
index 6b12e26ab5f3..9795134fffee 100644
--- a/llvm/test/Transforms/InstCombine/and2.ll
+++ b/llvm/test/Transforms/InstCombine/and2.ll
@@ -181,26 +181,22 @@ define <2 x i8> @and1_shl1_is_cmp_eq_0_vec_undef(<2 x i8> %x) {
   ret <2 x i8> %and
 }
 
-; (1 >> x) & 1 --> zext(x == 0)
+; The mask is unnecessary.
 
 define i8 @and1_lshr1_is_cmp_eq_0(i8 %x) {
 ; CHECK-LABEL: @and1_lshr1_is_cmp_eq_0(
-; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
-; CHECK-NEXT:    [[AND:%.*]] = zext i1 [[TMP1]] to i8
-; CHECK-NEXT:    ret i8 [[AND]]
+; CHECK-NEXT:    [[SH:%.*]] = lshr i8 1, [[X:%.*]]
+; CHECK-NEXT:    ret i8 [[SH]]
 ;
   %sh = lshr i8 1, %x
   %and = and i8 %sh, 1
   ret i8 %and
 }
 
-; Don't do it if the shift has another use.
-
 define i8 @and1_lshr1_is_cmp_eq_0_multiuse(i8 %x) {
 ; CHECK-LABEL: @and1_lshr1_is_cmp_eq_0_multiuse(
 ; CHECK-NEXT:    [[SH:%.*]] = lshr i8 1, [[X:%.*]]
-; CHECK-NEXT:    [[AND:%.*]] = and i8 [[SH]], 1
-; CHECK-NEXT:    [[ADD:%.*]] = add nuw nsw i8 [[SH]], [[AND]]
+; CHECK-NEXT:    [[ADD:%.*]] = shl nuw nsw i8 [[SH]], 1
 ; CHECK-NEXT:    ret i8 [[ADD]]
 ;
   %sh = lshr i8 1, %x
@@ -209,13 +205,12 @@ define i8 @and1_lshr1_is_cmp_eq_0_multiuse(i8 %x) {
   ret i8 %add
 }
 
-; (1 >> x) & 1 --> zext(x == 0)
+; The mask is unnecessary.
 
 define <2 x i8> @and1_lshr1_is_cmp_eq_0_vec(<2 x i8> %x) {
 ; CHECK-LABEL: @and1_lshr1_is_cmp_eq_0_vec(
-; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq <2 x i8> [[X:%.*]], zeroinitializer
-; CHECK-NEXT:    [[AND:%.*]] = zext <2 x i1> [[TMP1]] to <2 x i8>
-; CHECK-NEXT:    ret <2 x i8> [[AND]]
+; CHECK-NEXT:    [[SH:%.*]] = lshr <2 x i8> <i8 1, i8 1>, [[X:%.*]]
+; CHECK-NEXT:    ret <2 x i8> [[SH]]
 ;
   %sh = lshr <2 x i8> <i8 1, i8 1>, %x
   %and = and <2 x i8> %sh, <i8 1, i8 1>

diff  --git a/llvm/test/Transforms/InstCombine/lshr-and-negC-icmpeq-zero.ll b/llvm/test/Transforms/InstCombine/lshr-and-negC-icmpeq-zero.ll
index b81796fae3c5..571ca8e2ce84 100644
--- a/llvm/test/Transforms/InstCombine/lshr-and-negC-icmpeq-zero.ll
+++ b/llvm/test/Transforms/InstCombine/lshr-and-negC-icmpeq-zero.ll
@@ -179,12 +179,13 @@ define i1 @scalar_lshr_and_negC_eq_extra_use_lshr_and(i32 %x, i32 %y, i32 %z, i3
 
 ; Negative tests
 
-; X is constant
+; TODO: This could be reduced to lshr+icmp ult.
 
 define i1 @scalar_i32_lshr_and_negC_eq_X_is_constant1(i32 %y) {
 ; CHECK-LABEL: @scalar_i32_lshr_and_negC_eq_X_is_constant1(
 ; CHECK-NEXT:    [[LSHR:%.*]] = lshr i32 12345, [[Y:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp ult i32 [[LSHR]], 8
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[LSHR]], 16376
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i32 [[AND]], 0
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %lshr = lshr i32 12345, %y
@@ -193,10 +194,13 @@ define i1 @scalar_i32_lshr_and_negC_eq_X_is_constant1(i32 %y) {
   ret i1 %r
 }
 
+; TODO: This could be reduced to lshr+icmp ult.
+
 define i1 @scalar_i32_lshr_and_negC_eq_X_is_constant2(i32 %y) {
 ; CHECK-LABEL: @scalar_i32_lshr_and_negC_eq_X_is_constant2(
 ; CHECK-NEXT:    [[LSHR:%.*]] = lshr i32 268435456, [[Y:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp ult i32 [[LSHR]], 8
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[LSHR]], 536870904
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i32 [[AND]], 0
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %lshr = lshr i32 268435456, %y

diff  --git a/llvm/test/Transforms/InstCombine/shift.ll b/llvm/test/Transforms/InstCombine/shift.ll
index d181be35ebad..2c5c4a7dbe1c 100644
--- a/llvm/test/Transforms/InstCombine/shift.ll
+++ b/llvm/test/Transforms/InstCombine/shift.ll
@@ -1799,7 +1799,7 @@ define void @ashr_out_of_range_1(i177* %A) {
 define i8 @lshr_mask_demand(i8 %x) {
 ; CHECK-LABEL: @lshr_mask_demand(
 ; CHECK-NEXT:    [[S:%.*]] = lshr i8 63, [[X:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = and i8 [[S]], -32
+; CHECK-NEXT:    [[R:%.*]] = and i8 [[S]], 32
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
   %s = lshr i8 63, %x ; 0b00111111
@@ -1810,7 +1810,7 @@ define i8 @lshr_mask_demand(i8 %x) {
 define i8 @shl_mask_demand(i8 %x) {
 ; CHECK-LABEL: @shl_mask_demand(
 ; CHECK-NEXT:    [[S:%.*]] = shl i8 12, [[X:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = and i8 [[S]], 7
+; CHECK-NEXT:    [[R:%.*]] = and i8 [[S]], 4
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
   %s = shl i8 12, %x ; 0b00001100

diff  --git a/llvm/test/Transforms/InstCombine/signbit-shl-and-icmpeq-zero.ll b/llvm/test/Transforms/InstCombine/signbit-shl-and-icmpeq-zero.ll
index 1d76fa5ffa37..b0791598b56a 100644
--- a/llvm/test/Transforms/InstCombine/signbit-shl-and-icmpeq-zero.ll
+++ b/llvm/test/Transforms/InstCombine/signbit-shl-and-icmpeq-zero.ll
@@ -187,10 +187,7 @@ define i1 @scalar_i32_signbit_shl_and_eq_extra_use_shl_and(i32 %x, i32 %y, i32 %
 
 define i1 @scalar_i32_signbit_shl_and_eq_X_is_constant1(i32 %y) {
 ; CHECK-LABEL: @scalar_i32_signbit_shl_and_eq_X_is_constant1(
-; CHECK-NEXT:    [[SHL:%.*]] = shl i32 -2147483648, [[Y:%.*]]
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[SHL]], 12345
-; CHECK-NEXT:    [[R:%.*]] = icmp eq i32 [[AND]], 0
-; CHECK-NEXT:    ret i1 [[R]]
+; CHECK-NEXT:    ret i1 true
 ;
   %shl = shl i32 2147483648, %y
   %and = and i32 %shl, 12345
@@ -200,10 +197,7 @@ define i1 @scalar_i32_signbit_shl_and_eq_X_is_constant1(i32 %y) {
 
 define i1 @scalar_i32_signbit_shl_and_eq_X_is_constant2(i32 %y) {
 ; CHECK-LABEL: @scalar_i32_signbit_shl_and_eq_X_is_constant2(
-; CHECK-NEXT:    [[SHL:%.*]] = shl i32 -2147483648, [[Y:%.*]]
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[SHL]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp eq i32 [[AND]], 0
-; CHECK-NEXT:    ret i1 [[R]]
+; CHECK-NEXT:    ret i1 true
 ;
   %shl = shl i32 2147483648, %y
   %and = and i32 %shl, 1
@@ -219,7 +213,7 @@ define i1 @scalar_i32_signbit_shl_and_slt(i32 %x, i32 %y) {
 ; CHECK-LABEL: @scalar_i32_signbit_shl_and_slt(
 ; CHECK-NEXT:    [[SHL:%.*]] = shl i32 -2147483648, [[Y:%.*]]
 ; CHECK-NEXT:    [[AND:%.*]] = and i32 [[SHL]], [[X:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp slt i32 [[AND]], 0
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i32 [[AND]], 0
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %shl = shl i32 2147483648, %y
@@ -232,10 +226,7 @@ define i1 @scalar_i32_signbit_shl_and_slt(i32 %x, i32 %y) {
 
 define i1 @scalar_i32_signbit_shl_and_eq_nonzero(i32 %x, i32 %y) {
 ; CHECK-LABEL: @scalar_i32_signbit_shl_and_eq_nonzero(
-; CHECK-NEXT:    [[SHL:%.*]] = shl i32 -2147483648, [[Y:%.*]]
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[SHL]], [[X:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp eq i32 [[AND]], 1
-; CHECK-NEXT:    ret i1 [[R]]
+; CHECK-NEXT:    ret i1 false
 ;
   %shl = shl i32 2147483648, %y
   %and = and i32 %shl, %x

diff  --git a/llvm/test/Transforms/InstCombine/zext-or-icmp.ll b/llvm/test/Transforms/InstCombine/zext-or-icmp.ll
index a77aa7ac7ebd..7ef482cea835 100644
--- a/llvm/test/Transforms/InstCombine/zext-or-icmp.ll
+++ b/llvm/test/Transforms/InstCombine/zext-or-icmp.ll
@@ -49,10 +49,7 @@ define i32 @dont_widen_undef() {
 ; CHECK-NEXT:    br label [[BLOCK2]]
 ; CHECK:       block2:
 ; CHECK-NEXT:    [[CMP_I:%.*]] = phi i1 [ false, [[BLOCK1:%.*]] ], [ true, [[ENTRY:%.*]] ]
-; CHECK-NEXT:    [[M_011:%.*]] = phi i32 [ 0, [[BLOCK1]] ], [ 33, [[ENTRY]] ]
-; CHECK-NEXT:    [[M_1_OP:%.*]] = lshr i32 1, [[M_011]]
-; CHECK-NEXT:    [[SEXT_MASK:%.*]] = and i32 [[M_1_OP]], 65535
-; CHECK-NEXT:    [[CMP115:%.*]] = icmp ne i32 [[SEXT_MASK]], 0
+; CHECK-NEXT:    [[CMP115:%.*]] = phi i1 [ true, [[BLOCK1]] ], [ false, [[ENTRY]] ]
 ; CHECK-NEXT:    [[CMP1:%.*]] = or i1 [[CMP_I]], [[CMP115]]
 ; CHECK-NEXT:    [[CONV2:%.*]] = zext i1 [[CMP1]] to i32
 ; CHECK-NEXT:    ret i32 [[CONV2]]
@@ -82,10 +79,7 @@ define i32 @dont_widen_undef_logical() {
 ; CHECK-NEXT:    br label [[BLOCK2]]
 ; CHECK:       block2:
 ; CHECK-NEXT:    [[CMP_I:%.*]] = phi i1 [ false, [[BLOCK1:%.*]] ], [ true, [[ENTRY:%.*]] ]
-; CHECK-NEXT:    [[M_011:%.*]] = phi i32 [ 0, [[BLOCK1]] ], [ 33, [[ENTRY]] ]
-; CHECK-NEXT:    [[M_1_OP:%.*]] = lshr i32 1, [[M_011]]
-; CHECK-NEXT:    [[SEXT_MASK:%.*]] = and i32 [[M_1_OP]], 65535
-; CHECK-NEXT:    [[CMP115:%.*]] = icmp ne i32 [[SEXT_MASK]], 0
+; CHECK-NEXT:    [[CMP115:%.*]] = phi i1 [ true, [[BLOCK1]] ], [ false, [[ENTRY]] ]
 ; CHECK-NEXT:    [[CMP1:%.*]] = or i1 [[CMP_I]], [[CMP115]]
 ; CHECK-NEXT:    [[CONV2:%.*]] = zext i1 [[CMP1]] to i32
 ; CHECK-NEXT:    ret i32 [[CONV2]]


        


More information about the llvm-commits mailing list