[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