[llvm] [ValueTracking] Compute knownbits from `(icmp upred (add/sub nuw X, Y), C)` (PR #87180)
via llvm-commits
llvm-commits at lists.llvm.org
Thu May 16 10:25:58 PDT 2024
https://github.com/goldsteinn updated https://github.com/llvm/llvm-project/pull/87180
>From 1690b9ac17b0fd8e22ec520a1c28cc10246be003 Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Sat, 30 Mar 2024 21:38:23 -0500
Subject: [PATCH 1/2] [ValueTracking] Add tests for computing knownbits from
`(icmp upred (add/sub nuw X, Y), C)`; NFC
---
.../test/Transforms/InstCombine/known-bits.ll | 276 ++++++++++++++++++
1 file changed, 276 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/known-bits.ll b/llvm/test/Transforms/InstCombine/known-bits.ll
index cb404c0b7f889..c00bdb7870953 100644
--- a/llvm/test/Transforms/InstCombine/known-bits.ll
+++ b/llvm/test/Transforms/InstCombine/known-bits.ll
@@ -1698,5 +1698,281 @@ define i32 @test_none(float nofpclass(all) %x) {
ret i32 %and
}
+define i8 @test_icmp_add(i8 %n, i8 %n2, i8 %other) {
+; CHECK-LABEL: @test_icmp_add(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[N_ADD:%.*]] = add nuw i8 [[N:%.*]], [[N2:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[N_ADD]], 32
+; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[R:%.*]] = and i8 [[N]], 32
+; CHECK-NEXT: ret i8 [[R]]
+; CHECK: if.else:
+; CHECK-NEXT: ret i8 [[OTHER:%.*]]
+;
+entry:
+ %n_add = add nuw i8 %n, %n2
+ %cmp = icmp ult i8 %n_add, 32
+ br i1 %cmp, label %if.then, label %if.else
+
+if.then:
+ %r = and i8 %n, 32
+ ret i8 %r
+
+if.else:
+ ret i8 %other
+}
+
+define i8 @test_icmp_add_fail_nsw(i8 %n, i8 %n2, i8 %other) {
+; CHECK-LABEL: @test_icmp_add_fail_nsw(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[N_ADD:%.*]] = add nsw i8 [[N:%.*]], [[N2:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[N_ADD]], 32
+; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[R:%.*]] = and i8 [[N]], 32
+; CHECK-NEXT: ret i8 [[R]]
+; CHECK: if.else:
+; CHECK-NEXT: ret i8 [[OTHER:%.*]]
+;
+entry:
+ %n_add = add nsw i8 %n, %n2
+ %cmp = icmp ult i8 %n_add, 32
+ br i1 %cmp, label %if.then, label %if.else
+
+if.then:
+ %r = and i8 %n, 32
+ ret i8 %r
+
+if.else:
+ ret i8 %other
+}
+
+define i8 @test_icmp_add2(i8 %n, i8 %n2, i8 %other) {
+; CHECK-LABEL: @test_icmp_add2(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[N_ADD:%.*]] = add nuw nsw i8 [[N:%.*]], [[N2:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[N_ADD]], 14
+; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: ret i8 [[OTHER:%.*]]
+; CHECK: if.else:
+; CHECK-NEXT: [[R:%.*]] = and i8 [[N]], 32
+; CHECK-NEXT: ret i8 [[R]]
+;
+entry:
+ %n_add = add nsw nuw i8 %n, %n2
+ %cmp = icmp uge i8 %n_add, 15
+ br i1 %cmp, label %if.then, label %if.else
+
+if.then:
+ ret i8 %other
+if.else:
+ %r = and i8 %n, 32
+ ret i8 %r
+
+}
+
+define i8 @test_icmp_add_fail_bad_range(i8 %n, i8 %n2, i8 %other) {
+; CHECK-LABEL: @test_icmp_add_fail_bad_range(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[N_ADD:%.*]] = add nuw i8 [[N:%.*]], [[N2:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[N_ADD]], 33
+; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[R:%.*]] = and i8 [[N]], 32
+; CHECK-NEXT: ret i8 [[R]]
+; CHECK: if.else:
+; CHECK-NEXT: ret i8 [[OTHER:%.*]]
+;
+entry:
+ %n_add = add nuw i8 %n, %n2
+ %cmp = icmp ule i8 %n_add, 32
+ br i1 %cmp, label %if.then, label %if.else
+
+if.then:
+ %r = and i8 %n, 32
+ ret i8 %r
+
+if.else:
+ ret i8 %other
+}
+
+define i8 @test_icmp_add_fail_bad_pred(i8 %n, i8 %n2, i8 %other) {
+; CHECK-LABEL: @test_icmp_add_fail_bad_pred(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[N_ADD:%.*]] = add nuw i8 [[N:%.*]], [[N2:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[N_ADD]], 32
+; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[R:%.*]] = and i8 [[N]], 32
+; CHECK-NEXT: ret i8 [[R]]
+; CHECK: if.else:
+; CHECK-NEXT: ret i8 [[OTHER:%.*]]
+;
+entry:
+ %n_add = add nuw i8 %n, %n2
+ %cmp = icmp ugt i8 %n_add, 32
+ br i1 %cmp, label %if.then, label %if.else
+
+if.then:
+ %r = and i8 %n, 32
+ ret i8 %r
+
+if.else:
+ ret i8 %other
+}
+
+define i8 @test_icmp_sub(i8 %n, i8 %n2, i8 %other) {
+; CHECK-LABEL: @test_icmp_sub(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[N_SUB:%.*]] = sub nuw i8 [[N:%.*]], [[N2:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[N_SUB]], -33
+; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[R:%.*]] = and i8 [[N]], 32
+; CHECK-NEXT: ret i8 [[R]]
+; CHECK: if.else:
+; CHECK-NEXT: ret i8 [[OTHER:%.*]]
+;
+entry:
+ %n_sub = sub nuw i8 %n, %n2
+ %cmp = icmp ugt i8 %n_sub, 223
+ br i1 %cmp, label %if.then, label %if.else
+
+if.then:
+ %r = and i8 %n, 32
+ ret i8 %r
+
+if.else:
+ ret i8 %other
+}
+
+define i8 @test_icmp_sub_fail_wrong_arg(i8 %n, i8 %n2, i8 %other) {
+; CHECK-LABEL: @test_icmp_sub_fail_wrong_arg(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[N_SUB:%.*]] = sub nuw i8 [[N:%.*]], [[N2:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[N_SUB]], -33
+; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[R:%.*]] = and i8 [[N2]], 32
+; CHECK-NEXT: ret i8 [[R]]
+; CHECK: if.else:
+; CHECK-NEXT: ret i8 [[OTHER:%.*]]
+;
+entry:
+ %n_sub = sub nuw i8 %n, %n2
+ %cmp = icmp ugt i8 %n_sub, 223
+ br i1 %cmp, label %if.then, label %if.else
+
+if.then:
+ %r = and i8 %n2, 32
+ ret i8 %r
+
+if.else:
+ ret i8 %other
+}
+
+define i8 @test_icmp_sub2(i8 %n, i8 %n2, i8 %other) {
+; CHECK-LABEL: @test_icmp_sub2(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[N_SUB:%.*]] = sub nuw i8 [[N:%.*]], [[N2:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[N_SUB]], -31
+; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: ret i8 [[OTHER:%.*]]
+; CHECK: if.else:
+; CHECK-NEXT: [[R:%.*]] = and i8 [[N]], 32
+; CHECK-NEXT: ret i8 [[R]]
+;
+entry:
+ %n_sub = sub nuw i8 %n, %n2
+ %cmp = icmp ule i8 %n_sub, 224
+ br i1 %cmp, label %if.then, label %if.else
+
+if.then:
+ ret i8 %other
+if.else:
+ %r = and i8 %n, 32
+ ret i8 %r
+
+}
+
+define i8 @test_icmp_sub2_fail_nsw(i8 %n, i8 %n2, i8 %other) {
+; CHECK-LABEL: @test_icmp_sub2_fail_nsw(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[N_SUB:%.*]] = sub nsw i8 [[N:%.*]], [[N2:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[N_SUB]], -31
+; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: ret i8 [[OTHER:%.*]]
+; CHECK: if.else:
+; CHECK-NEXT: [[R:%.*]] = and i8 [[N]], 32
+; CHECK-NEXT: ret i8 [[R]]
+;
+entry:
+ %n_sub = sub nsw i8 %n, %n2
+ %cmp = icmp ule i8 %n_sub, 224
+ br i1 %cmp, label %if.then, label %if.else
+
+if.then:
+ ret i8 %other
+if.else:
+ %r = and i8 %n, 32
+ ret i8 %r
+
+}
+
+
+define i8 @test_icmp_sub_fail_bad_range(i8 %n, i8 %n2, i8 %other) {
+; CHECK-LABEL: @test_icmp_sub_fail_bad_range(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[N_SUB:%.*]] = sub nuw i8 [[N:%.*]], [[N2:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[N_SUB]], -34
+; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[R:%.*]] = and i8 [[N]], 32
+; CHECK-NEXT: ret i8 [[R]]
+; CHECK: if.else:
+; CHECK-NEXT: ret i8 [[OTHER:%.*]]
+;
+entry:
+ %n_sub = sub nuw i8 %n, %n2
+ %cmp = icmp uge i8 %n_sub, 223
+ br i1 %cmp, label %if.then, label %if.else
+
+if.then:
+ %r = and i8 %n, 32
+ ret i8 %r
+
+if.else:
+ ret i8 %other
+}
+
+define i8 @test_icmp_sub_fail_bad_pred(i8 %n, i8 %n2, i8 %other) {
+; CHECK-LABEL: @test_icmp_sub_fail_bad_pred(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[N_SUB:%.*]] = sub nuw i8 [[N:%.*]], [[N2:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[N_SUB]], 31
+; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[R:%.*]] = and i8 [[N]], 32
+; CHECK-NEXT: ret i8 [[R]]
+; CHECK: if.else:
+; CHECK-NEXT: ret i8 [[OTHER:%.*]]
+;
+entry:
+ %n_sub = sub nuw i8 %n, %n2
+ %cmp = icmp sge i8 %n_sub, 32
+ br i1 %cmp, label %if.then, label %if.else
+
+if.then:
+ %r = and i8 %n, 32
+ ret i8 %r
+
+if.else:
+ ret i8 %other
+}
+
declare void @use(i1)
declare void @sink(i8)
>From 1adbd1018b6e735b47deb29ac9aff553442060fc Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Sat, 30 Mar 2024 21:39:36 -0500
Subject: [PATCH 2/2] [ValueTracking] Compute knownbits from `(icmp upred
(add/sub nuw X, Y), C)`
`(icmp ule/ult (add nuw X, Y), C)` implies both `(icmp ule/ult X, C)` and
`(icmp ule/ult Y, C)`. We can use this to deduce leading zeros in `X`/`Y`.
`(icmp uge/ugt (sub nuw X, Y), C)` implies `(icmp uge/uge X, C)` . We
can use this to deduce leading ones in `X`.
Proofs: https://alive2.llvm.org/ce/z/sc5k22
---
llvm/lib/Analysis/ValueTracking.cpp | 47 ++++++++++++-------
.../test/Transforms/InstCombine/known-bits.ll | 12 ++---
2 files changed, 33 insertions(+), 26 deletions(-)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index e07d14ccbb85c..e8c5f9b3dc25d 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -706,17 +706,22 @@ static void computeKnownBitsFromCmp(const Value *V, CmpInst::Predicate Pred,
LHSRange = LHSRange.sub(*Offset);
Known = Known.unionWith(LHSRange.toKnownBits());
}
- // X & Y u> C -> X u> C && Y u> C
- if ((Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_UGE) &&
- match(LHS, m_c_And(m_V, m_Value()))) {
- Known.One.setHighBits(
- (*C + (Pred == ICmpInst::ICMP_UGT)).countLeadingOnes());
+ if (Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_UGE) {
+ // X & Y u> C -> X u> C && Y u> C
+ // X nuw- Y u> C -> X u> C
+ if (match(LHS, m_c_And(m_V, m_Value())) ||
+ match(LHS, m_NUWSub(m_V, m_Value())))
+ Known.One.setHighBits(
+ (*C + (Pred == ICmpInst::ICMP_UGT)).countLeadingOnes());
}
- // X | Y u< C -> X u< C && Y u< C
- if ((Pred == ICmpInst::ICMP_ULT || Pred == ICmpInst::ICMP_ULE) &&
- match(LHS, m_c_Or(m_V, m_Value()))) {
- Known.Zero.setHighBits(
- (*C - (Pred == ICmpInst::ICMP_ULT)).countLeadingZeros());
+ if (Pred == ICmpInst::ICMP_ULT || Pred == ICmpInst::ICMP_ULE) {
+ // X | Y u< C -> X u< C && Y u< C
+ // X nuw+ Y u< C -> X u< C && Y u< C
+ if (match(LHS, m_c_Or(m_V, m_Value())) ||
+ match(LHS, m_c_NUWAdd(m_V, m_Value()))) {
+ Known.Zero.setHighBits(
+ (*C - (Pred == ICmpInst::ICMP_ULT)).countLeadingZeros());
+ }
}
}
break;
@@ -9576,14 +9581,20 @@ void llvm::findValuesAffectedByCondition(
if (match(A, m_AddLike(m_Value(X), m_ConstantInt())))
AddAffected(X);
- Value *Y;
- // X & Y u> C -> X >u C && Y >u C
- // X | Y u< C -> X u< C && Y u< C
- if (ICmpInst::isUnsigned(Pred) &&
- (match(A, m_And(m_Value(X), m_Value(Y))) ||
- match(A, m_Or(m_Value(X), m_Value(Y))))) {
- AddAffected(X);
- AddAffected(Y);
+ if (ICmpInst::isUnsigned(Pred)) {
+ Value *Y;
+ // X & Y u> C -> X >u C && Y >u C
+ // X | Y u< C -> X u< C && Y u< C
+ // X nuw+ Y u< C -> X u< C && Y u< C
+ if (match(A, m_And(m_Value(X), m_Value(Y))) ||
+ match(A, m_Or(m_Value(X), m_Value(Y))) ||
+ match(A, m_NUWAdd(m_Value(X), m_Value(Y)))) {
+ AddAffected(X);
+ AddAffected(Y);
+ }
+ // X nuw- Y u> C -> X u> C
+ if (match(A, m_NUWSub(m_Value(X), m_Value())))
+ AddAffected(X);
}
}
diff --git a/llvm/test/Transforms/InstCombine/known-bits.ll b/llvm/test/Transforms/InstCombine/known-bits.ll
index c00bdb7870953..82cd24027e4e1 100644
--- a/llvm/test/Transforms/InstCombine/known-bits.ll
+++ b/llvm/test/Transforms/InstCombine/known-bits.ll
@@ -1705,8 +1705,7 @@ define i8 @test_icmp_add(i8 %n, i8 %n2, i8 %other) {
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[N_ADD]], 32
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
-; CHECK-NEXT: [[R:%.*]] = and i8 [[N]], 32
-; CHECK-NEXT: ret i8 [[R]]
+; CHECK-NEXT: ret i8 0
; CHECK: if.else:
; CHECK-NEXT: ret i8 [[OTHER:%.*]]
;
@@ -1757,8 +1756,7 @@ define i8 @test_icmp_add2(i8 %n, i8 %n2, i8 %other) {
; CHECK: if.then:
; CHECK-NEXT: ret i8 [[OTHER:%.*]]
; CHECK: if.else:
-; CHECK-NEXT: [[R:%.*]] = and i8 [[N]], 32
-; CHECK-NEXT: ret i8 [[R]]
+; CHECK-NEXT: ret i8 0
;
entry:
%n_add = add nsw nuw i8 %n, %n2
@@ -1830,8 +1828,7 @@ define i8 @test_icmp_sub(i8 %n, i8 %n2, i8 %other) {
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[N_SUB]], -33
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
-; CHECK-NEXT: [[R:%.*]] = and i8 [[N]], 32
-; CHECK-NEXT: ret i8 [[R]]
+; CHECK-NEXT: ret i8 32
; CHECK: if.else:
; CHECK-NEXT: ret i8 [[OTHER:%.*]]
;
@@ -1882,8 +1879,7 @@ define i8 @test_icmp_sub2(i8 %n, i8 %n2, i8 %other) {
; CHECK: if.then:
; CHECK-NEXT: ret i8 [[OTHER:%.*]]
; CHECK: if.else:
-; CHECK-NEXT: [[R:%.*]] = and i8 [[N]], 32
-; CHECK-NEXT: ret i8 [[R]]
+; CHECK-NEXT: ret i8 32
;
entry:
%n_sub = sub nuw i8 %n, %n2
More information about the llvm-commits
mailing list