[llvm] goldsteinn/more or and support (PR #86059)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Mar 20 19:27:30 PDT 2024
https://github.com/goldsteinn created https://github.com/llvm/llvm-project/pull/86059
- **[ValueTracking] Add basic tests tracking `or disjoint` conditions as `add`; NFC**
- **[ValueTracking] Tracking `or disjoint` conditions as `add` in Assumption/DomCondition Cache**
- **[ValueTracking] Add tests for computing knownbits from `(icmp upred X (and/or X, Y))`; NFC**
- **[ValueTracking] compute knownbits from `(icmp upred X (and/or X, Y))`; NFC**
>From 5d39baf435f4f81c49889ceaa9e81cbfb351fb38 Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Wed, 20 Mar 2024 21:01:35 -0500
Subject: [PATCH 1/4] [ValueTracking] Add basic tests tracking `or disjoint`
conditions as `add`; NFC
---
.../test/Transforms/InstCombine/known-bits.ll | 52 +++++++++++++++++++
1 file changed, 52 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/known-bits.ll b/llvm/test/Transforms/InstCombine/known-bits.ll
index 58c283815cf910..ff7b81b2f2b25d 100644
--- a/llvm/test/Transforms/InstCombine/known-bits.ll
+++ b/llvm/test/Transforms/InstCombine/known-bits.ll
@@ -483,5 +483,57 @@ if.else:
ret i64 13
}
+define i1 @test_icmp_or_distjoint(i8 %n, i1 %other) {
+; CHECK-LABEL: @test_icmp_or_distjoint(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[N_OR:%.*]] = or disjoint i8 [[N:%.*]], 16
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[N_OR]], -111
+; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[R:%.*]] = icmp slt i8 [[N]], 0
+; CHECK-NEXT: ret i1 [[R]]
+; CHECK: if.else:
+; CHECK-NEXT: ret i1 [[OTHER:%.*]]
+;
+entry:
+ %n_or = or disjoint i8 %n, 16
+ %cmp = icmp ugt i8 %n_or, 145
+ br i1 %cmp, label %if.then, label %if.else
+
+if.then:
+ %r = icmp slt i8 %n, 0
+ ret i1 %r
+
+if.else:
+ ret i1 %other
+}
+
+define i1 @test_icmp_or_fail_missing_disjoint(i8 %n, i1 %other) {
+; CHECK-LABEL: @test_icmp_or_fail_missing_disjoint(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[N_OR:%.*]] = or i8 [[N:%.*]], 16
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[N_OR]], -111
+; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[R:%.*]] = icmp slt i8 [[N]], 0
+; CHECK-NEXT: ret i1 [[R]]
+; CHECK: if.else:
+; CHECK-NEXT: ret i1 [[OTHER:%.*]]
+;
+entry:
+ %n_or = or i8 %n, 16
+ %cmp = icmp ugt i8 %n_or, 145
+ br i1 %cmp, label %if.then, label %if.else
+
+if.then:
+ %r = icmp slt i8 %n, 0
+ ret i1 %r
+
+if.else:
+ ret i1 %other
+}
+
+
+
declare void @use(i1)
declare void @sink(i8)
>From 3d409e52ea13eb9468e409ccbb4a8f127211d43a Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Wed, 20 Mar 2024 20:12:21 -0500
Subject: [PATCH 2/4] [ValueTracking] Tracking `or disjoint` conditions as
`add` in Assumption/DomCondition Cache
We can definitionally treat `or disjoint` as `add` anywhere.
---
llvm/lib/Analysis/ValueTracking.cpp | 4 ++--
llvm/test/Transforms/InstCombine/known-bits.ll | 3 +--
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 797665cf06c875..b5e8a1d22f264b 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -699,7 +699,7 @@ static void computeKnownBitsFromCmp(const Value *V, CmpInst::Predicate Pred,
}
default:
const APInt *Offset = nullptr;
- if (match(LHS, m_CombineOr(m_V, m_Add(m_V, m_APInt(Offset)))) &&
+ if (match(LHS, m_CombineOr(m_V, m_AddLike(m_V, m_APInt(Offset)))) &&
match(RHS, m_APInt(C))) {
ConstantRange LHSRange = ConstantRange::makeAllowedICmpRegion(Pred, *C);
if (Offset)
@@ -9285,7 +9285,7 @@ void llvm::findValuesAffectedByCondition(
} else {
// Handle (A + C1) u< C2, which is the canonical form of
// A > C3 && A < C4.
- if (match(A, m_Add(m_Value(X), m_ConstantInt())) &&
+ if (match(A, m_AddLike(m_Value(X), m_ConstantInt())) &&
match(B, m_ConstantInt()))
AddAffected(X);
diff --git a/llvm/test/Transforms/InstCombine/known-bits.ll b/llvm/test/Transforms/InstCombine/known-bits.ll
index ff7b81b2f2b25d..5305c78f691231 100644
--- a/llvm/test/Transforms/InstCombine/known-bits.ll
+++ b/llvm/test/Transforms/InstCombine/known-bits.ll
@@ -490,8 +490,7 @@ define i1 @test_icmp_or_distjoint(i8 %n, i1 %other) {
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[N_OR]], -111
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
-; CHECK-NEXT: [[R:%.*]] = icmp slt i8 [[N]], 0
-; CHECK-NEXT: ret i1 [[R]]
+; CHECK-NEXT: ret i1 true
; CHECK: if.else:
; CHECK-NEXT: ret i1 [[OTHER:%.*]]
;
>From b4de15c692f72568cc81d333003520f6437e69d1 Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Wed, 20 Mar 2024 21:16:59 -0500
Subject: [PATCH 3/4] [ValueTracking] Add tests for computing knownbits from
`(icmp upred X (and/or X, Y))`; NFC
---
.../test/Transforms/InstCombine/known-bits.ll | 199 ++++++++++++++++++
1 file changed, 199 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/known-bits.ll b/llvm/test/Transforms/InstCombine/known-bits.ll
index 5305c78f691231..964b1c67b6a240 100644
--- a/llvm/test/Transforms/InstCombine/known-bits.ll
+++ b/llvm/test/Transforms/InstCombine/known-bits.ll
@@ -532,6 +532,205 @@ if.else:
ret i1 %other
}
+define i8 @test_icmp_or(i8 %n, i8 %n2, i8 %other) {
+; CHECK-LABEL: @test_icmp_or(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[N_OR:%.*]] = or i8 [[N:%.*]], [[N2:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[N_OR]], 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_or = or i8 %n, %n2
+ %cmp = icmp ult i8 %n_or, 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_or2(i8 %n, i8 %n2, i8 %other) {
+; CHECK-LABEL: @test_icmp_or2(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[N_OR:%.*]] = or i8 [[N:%.*]], [[N2:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[N_OR]], 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_or = or i8 %n, %n2
+ %cmp = icmp uge i8 %n_or, 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_or_fail_bad_range(i8 %n, i8 %n2, i8 %other) {
+; CHECK-LABEL: @test_icmp_or_fail_bad_range(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[N_OR:%.*]] = or i8 [[N:%.*]], [[N2:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[N_OR]], 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_or = or i8 %n, %n2
+ %cmp = icmp ule i8 %n_or, 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_or_fail_bad_pred(i8 %n, i8 %n2, i8 %other) {
+; CHECK-LABEL: @test_icmp_or_fail_bad_pred(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[N_OR:%.*]] = or i8 [[N:%.*]], [[N2:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[N_OR]], 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_or = or i8 %n, %n2
+ %cmp = icmp ugt i8 %n_or, 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_and(i8 %n, i8 %n2, i8 %other) {
+; CHECK-LABEL: @test_icmp_and(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[N_AND:%.*]] = and i8 [[N:%.*]], [[N2:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[N_AND]], -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_and = and i8 %n, %n2
+ %cmp = icmp ugt i8 %n_and, 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_and2(i8 %n, i8 %n2, i8 %other) {
+; CHECK-LABEL: @test_icmp_and2(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[N_AND:%.*]] = and i8 [[N:%.*]], [[N2:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[N_AND]], -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_and = and i8 %n, %n2
+ %cmp = icmp ule i8 %n_and, 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_and_fail_bad_range(i8 %n, i8 %n2, i8 %other) {
+; CHECK-LABEL: @test_icmp_and_fail_bad_range(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[N_AND:%.*]] = and i8 [[N:%.*]], [[N2:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[N_AND]], -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_and = and i8 %n, %n2
+ %cmp = icmp uge i8 %n_and, 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_and_fail_bad_pred(i8 %n, i8 %n2, i8 %other) {
+; CHECK-LABEL: @test_icmp_and_fail_bad_pred(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[N_AND:%.*]] = and i8 [[N:%.*]], [[N2:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[N_AND]], 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_and = and i8 %n, %n2
+ %cmp = icmp eq i8 %n_and, 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)
>From 7da2a2f580aee5280783f31229d09cdb5976be7c Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Wed, 20 Mar 2024 20:15:47 -0500
Subject: [PATCH 4/4] [ValueTracking] compute knownbits from `(icmp upred X
(and/or X, Y))`; NFC
`(icmp uge/ugt (and X, Y), C)` implies both `(icmp uge/ugt X, C)` and
`(icmp uge/ugt Y, C)`. We can use this to deduce leading ones in `X`.
`(icmp ule/ult (or 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`.
---
llvm/lib/Analysis/ValueTracking.cpp | 48 ++++++++++++++-----
.../test/Transforms/InstCombine/known-bits.ll | 12 ++---
2 files changed, 40 insertions(+), 20 deletions(-)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index b5e8a1d22f264b..ade8fef385ec15 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -698,13 +698,26 @@ static void computeKnownBitsFromCmp(const Value *V, CmpInst::Predicate Pred,
break;
}
default:
- const APInt *Offset = nullptr;
- if (match(LHS, m_CombineOr(m_V, m_AddLike(m_V, m_APInt(Offset)))) &&
- match(RHS, m_APInt(C))) {
- ConstantRange LHSRange = ConstantRange::makeAllowedICmpRegion(Pred, *C);
- if (Offset)
- LHSRange = LHSRange.sub(*Offset);
- Known = Known.unionWith(LHSRange.toKnownBits());
+ if (match(RHS, m_APInt(C))) {
+ const APInt *Offset = nullptr;
+ if (match(LHS, m_CombineOr(m_V, m_AddLike(m_V, m_APInt(Offset))))) {
+ ConstantRange LHSRange = ConstantRange::makeAllowedICmpRegion(Pred, *C);
+ if (Offset)
+ 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());
+ }
+ // 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());
+ }
}
break;
}
@@ -9283,11 +9296,22 @@ void llvm::findValuesAffectedByCondition(
AddAffected(X);
}
} else {
- // Handle (A + C1) u< C2, which is the canonical form of
- // A > C3 && A < C4.
- if (match(A, m_AddLike(m_Value(X), m_ConstantInt())) &&
- match(B, m_ConstantInt()))
- AddAffected(X);
+ if (match(B, m_ConstantInt())) {
+ // Handle (A + C1) u< C2, which is the canonical form of
+ // A > C3 && A < C4.
+ 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);
+ }
+ }
// Handle icmp slt/sgt (bitcast X to int), 0/-1, which is supported
// by computeKnownFPClass().
diff --git a/llvm/test/Transforms/InstCombine/known-bits.ll b/llvm/test/Transforms/InstCombine/known-bits.ll
index 964b1c67b6a240..ad0c2c06eea91d 100644
--- a/llvm/test/Transforms/InstCombine/known-bits.ll
+++ b/llvm/test/Transforms/InstCombine/known-bits.ll
@@ -539,8 +539,7 @@ define i8 @test_icmp_or(i8 %n, i8 %n2, i8 %other) {
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[N_OR]], 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:%.*]]
;
@@ -566,8 +565,7 @@ define i8 @test_icmp_or2(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_or = or i8 %n, %n2
@@ -639,8 +637,7 @@ define i8 @test_icmp_and(i8 %n, i8 %n2, i8 %other) {
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[N_AND]], -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:%.*]]
;
@@ -666,8 +663,7 @@ define i8 @test_icmp_and2(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_and = and i8 %n, %n2
More information about the llvm-commits
mailing list