[llvm] [ValueTracking] Infer NonEqual from dominating conditions/assumptions (PR #117442)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Wed Feb 12 02:21:15 PST 2025
https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/117442
>From 53a3d1ebf543fd3379c5d6ed5d7103974fd09f35 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 24 Nov 2024 00:09:52 +0800
Subject: [PATCH 1/4] [InstCombine] Add pre-commit tests. NFC.
---
llvm/test/Transforms/InstCombine/icmp-dom.ll | 212 +++++++++++++++++++
1 file changed, 212 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/icmp-dom.ll b/llvm/test/Transforms/InstCombine/icmp-dom.ll
index 3cf3a7af77041..ab3bf511ab290 100644
--- a/llvm/test/Transforms/InstCombine/icmp-dom.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-dom.ll
@@ -534,3 +534,215 @@ else:
%cmp1 = icmp eq i32 %and1, 0
ret i1 %cmp1
}
+
+; TODO: X != Y implies X | Y != 0
+define i1 @or_nonzero_from_nonequal(i8 %x, i8 %y) {
+; CHECK-LABEL: @or_nonzero_from_nonequal(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[COND:%.*]] = icmp eq i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: br i1 [[COND]], label [[IF_ELSE:%.*]], label [[IF_THEN:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[X]], [[Y]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[OR]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK: if.else:
+; CHECK-NEXT: ret i1 false
+;
+entry:
+ %cond = icmp eq i8 %x, %y
+ br i1 %cond, label %if.else, label %if.then
+
+if.then:
+ %or = or i8 %x, %y
+ %cmp = icmp eq i8 %or, 0
+ ret i1 %cmp
+
+if.else:
+ ret i1 false
+}
+
+define i1 @test_nonequal_domcond1(i64 %x, i64 %y, i64 %z, i64 %w) {
+; CHECK-LABEL: @test_nonequal_domcond1(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[COND1:%.*]] = icmp eq i64 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[COND2:%.*]] = icmp eq i64 [[W:%.*]], [[Z:%.*]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[COND1]], i1 true, i1 [[COND2]]
+; CHECK-NEXT: br i1 [[OR_COND]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[SUB1:%.*]] = sub i64 [[W]], [[Z]]
+; CHECK-NEXT: [[SUB2:%.*]] = sub i64 [[Y]], [[X]]
+; CHECK-NEXT: [[UMIN:%.*]] = call i64 @llvm.umin.i64(i64 [[SUB1]], i64 [[SUB2]])
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[UMIN]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK: if.end:
+; CHECK-NEXT: ret i1 false
+;
+entry:
+ %cond1 = icmp eq i64 %y, %x
+ %cond2 = icmp eq i64 %w, %z
+ %or.cond = select i1 %cond1, i1 true, i1 %cond2
+ br i1 %or.cond, label %if.end, label %if.then
+
+if.then:
+ %sub1 = sub i64 %w, %z
+ %sub2 = sub i64 %y, %x
+ %umin = call i64 @llvm.umin.i64(i64 %sub1, i64 %sub2)
+ %cmp = icmp eq i64 %umin, 0
+ ret i1 %cmp
+
+if.end:
+ ret i1 false
+}
+
+define i1 @test_nonequal_domcond2(i64 %x, i64 %y, i64 %z, i64 %w) {
+; CHECK-LABEL: @test_nonequal_domcond2(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[COND1:%.*]] = icmp ne i64 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[COND2:%.*]] = icmp ne i64 [[W:%.*]], [[Z:%.*]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[COND1]], i1 [[COND2]], i1 false
+; CHECK-NEXT: br i1 [[OR_COND]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[SUB1:%.*]] = sub i64 [[W]], [[Z]]
+; CHECK-NEXT: [[SUB2:%.*]] = sub i64 [[Y]], [[X]]
+; CHECK-NEXT: [[UMIN:%.*]] = call i64 @llvm.umin.i64(i64 [[SUB1]], i64 [[SUB2]])
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[UMIN]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK: if.end:
+; CHECK-NEXT: ret i1 false
+;
+entry:
+ %cond1 = icmp ne i64 %y, %x
+ %cond2 = icmp ne i64 %w, %z
+ %or.cond = select i1 %cond1, i1 %cond2, i1 false
+ br i1 %or.cond, label %if.then, label %if.end
+
+if.then:
+ %sub1 = sub i64 %w, %z
+ %sub2 = sub i64 %y, %x
+ %umin = call i64 @llvm.umin.i64(i64 %sub1, i64 %sub2)
+ %cmp = icmp eq i64 %umin, 0
+ ret i1 %cmp
+
+if.end:
+ ret i1 false
+}
+
+define i1 @test_nonequal_assume(i64 %x, i64 %y, i64 %z, i64 %w) {
+; CHECK-LABEL: @test_nonequal_assume(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[COND1:%.*]] = icmp ne i64 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[COND1]])
+; CHECK-NEXT: [[COND2:%.*]] = icmp ne i64 [[W:%.*]], [[Z:%.*]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[COND2]])
+; CHECK-NEXT: [[SUB1:%.*]] = sub i64 [[W]], [[Z]]
+; CHECK-NEXT: [[SUB2:%.*]] = sub i64 [[Y]], [[X]]
+; CHECK-NEXT: [[UMIN:%.*]] = call i64 @llvm.umin.i64(i64 [[SUB1]], i64 [[SUB2]])
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[UMIN]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+entry:
+ %cond1 = icmp ne i64 %y, %x
+ call void @llvm.assume(i1 %cond1)
+ %cond2 = icmp ne i64 %w, %z
+ call void @llvm.assume(i1 %cond2)
+
+ %sub1 = sub i64 %w, %z
+ %sub2 = sub i64 %y, %x
+ %umin = call i64 @llvm.umin.i64(i64 %sub1, i64 %sub2)
+ %cmp = icmp eq i64 %umin, 0
+ ret i1 %cmp
+}
+
+; Negative tests
+
+define i1 @test_nonequal_invalid_domcond1(i64 %x, i64 %y, i64 %z, i64 %w) {
+; CHECK-LABEL: @test_nonequal_invalid_domcond1(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[COND1:%.*]] = icmp ne i64 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[COND2:%.*]] = icmp eq i64 [[W:%.*]], [[Z:%.*]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[COND1]], i1 true, i1 [[COND2]]
+; CHECK-NEXT: br i1 [[OR_COND]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: ret i1 true
+; CHECK: if.end:
+; CHECK-NEXT: ret i1 false
+;
+entry:
+ %cond1 = icmp ne i64 %y, %x
+ %cond2 = icmp eq i64 %w, %z
+ %or.cond = select i1 %cond1, i1 true, i1 %cond2
+ br i1 %or.cond, label %if.end, label %if.then
+
+if.then:
+ %sub1 = sub i64 %w, %z
+ %sub2 = sub i64 %y, %x
+ %umin = call i64 @llvm.umin.i64(i64 %sub1, i64 %sub2)
+ %cmp = icmp eq i64 %umin, 0
+ ret i1 %cmp
+
+if.end:
+ ret i1 false
+}
+
+define i1 @test_nonequal_invalid_domcond2(i64 %x, i64 %y, i64 %z, i64 %w) {
+; CHECK-LABEL: @test_nonequal_invalid_domcond2(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[COND1:%.*]] = icmp eq i64 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[COND2:%.*]] = icmp eq i64 [[W:%.*]], [[Z:%.*]]
+; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[COND1]], i1 true, i1 [[COND2]]
+; CHECK-NEXT: br i1 [[OR_COND]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: br label [[IF_END]]
+; CHECK: if.end:
+; CHECK-NEXT: [[SUB1:%.*]] = sub i64 [[W]], [[Z]]
+; CHECK-NEXT: [[SUB2:%.*]] = sub i64 [[Y]], [[X]]
+; CHECK-NEXT: [[UMIN:%.*]] = call i64 @llvm.umin.i64(i64 [[SUB1]], i64 [[SUB2]])
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[UMIN]], 0
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+entry:
+ %cond1 = icmp eq i64 %y, %x
+ %cond2 = icmp eq i64 %w, %z
+ %or.cond = select i1 %cond1, i1 true, i1 %cond2
+ br i1 %or.cond, label %if.then, label %if.end
+
+if.then:
+ br label %if.end
+
+if.end:
+ %sub1 = sub i64 %w, %z
+ %sub2 = sub i64 %y, %x
+ %umin = call i64 @llvm.umin.i64(i64 %sub1, i64 %sub2)
+ %cmp = icmp eq i64 %umin, 0
+ ret i1 %cmp
+}
+
+define i1 @test_nonequal_invalid_assume(i64 %x, i64 %y, i64 %z, i64 %w) {
+; CHECK-LABEL: @test_nonequal_invalid_assume(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[SUB1:%.*]] = sub i64 [[W:%.*]], [[Z:%.*]]
+; CHECK-NEXT: [[SUB2:%.*]] = sub i64 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[UMIN:%.*]] = call i64 @llvm.umin.i64(i64 [[SUB1]], i64 [[SUB2]])
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[UMIN]], 0
+; CHECK-NEXT: call void @side_effect()
+; CHECK-NEXT: [[COND1:%.*]] = icmp ne i64 [[Y]], [[X]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[COND1]])
+; CHECK-NEXT: [[COND2:%.*]] = icmp ne i64 [[W]], [[Z]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[COND2]])
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+entry:
+ %sub1 = sub i64 %w, %z
+ %sub2 = sub i64 %y, %x
+ %umin = call i64 @llvm.umin.i64(i64 %sub1, i64 %sub2)
+ %cmp = icmp eq i64 %umin, 0
+
+ call void @side_effect()
+ %cond1 = icmp ne i64 %y, %x
+ call void @llvm.assume(i1 %cond1)
+ %cond2 = icmp ne i64 %w, %z
+ call void @llvm.assume(i1 %cond2)
+ ret i1 %cmp
+}
+
+declare void @side_effect()
>From d938637f27c55032c5efcd8dcf603a849b68231d Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 24 Nov 2024 00:26:40 +0800
Subject: [PATCH 2/4] [ValueTracking] Infer NonEqual from dominating
conditions/assumptions
---
llvm/lib/Analysis/ValueTracking.cpp | 49 +++++++++++++++++++-
llvm/test/Transforms/InstCombine/icmp-dom.ll | 18 ++-----
2 files changed, 50 insertions(+), 17 deletions(-)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 28d7e1ce401e4..8d28bd235281b 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -3857,6 +3857,50 @@ static bool isKnownNonEqual(const Value *V1, const Value *V2,
match(V2, m_PtrToIntSameSize(Q.DL, m_Value(B))))
return isKnownNonEqual(A, B, DemandedElts, Depth + 1, Q);
+ if (!Q.CxtI)
+ return false;
+
+ // Try to infer NonEqual based on information from dominating conditions.
+ if (Q.DC && Q.DT) {
+ for (BranchInst *BI : Q.DC->conditionsFor(V1)) {
+ Value *Cond = BI->getCondition();
+ BasicBlockEdge Edge0(BI->getParent(), BI->getSuccessor(0));
+ if (isImpliedCondition(Cond, ICmpInst::ICMP_NE, V1, V2, Q.DL,
+ /*LHSIsTrue=*/true, Depth)
+ .value_or(false) &&
+ Q.DT->dominates(Edge0, Q.CxtI->getParent()))
+ return true;
+
+ BasicBlockEdge Edge1(BI->getParent(), BI->getSuccessor(1));
+ if (isImpliedCondition(Cond, ICmpInst::ICMP_NE, V1, V2, Q.DL,
+ /*LHSIsTrue=*/false, Depth)
+ .value_or(false) &&
+ Q.DT->dominates(Edge1, Q.CxtI->getParent()))
+ return true;
+ }
+ }
+
+ if (!Q.AC)
+ return false;
+
+ // Try to infer NonEqual based on information from assumptions.
+ for (auto &AssumeVH : Q.AC->assumptionsFor(V1)) {
+ if (!AssumeVH)
+ continue;
+ CallInst *I = cast<CallInst>(AssumeVH);
+
+ assert(I->getFunction() == Q.CxtI->getFunction() &&
+ "Got assumption for the wrong function!");
+ assert(I->getIntrinsicID() == Intrinsic::assume &&
+ "must be an assume intrinsic");
+
+ if (isImpliedCondition(I->getArgOperand(0), ICmpInst::ICMP_NE, V1, V2, Q.DL,
+ /*LHSIsTrue=*/true, Depth)
+ .value_or(false) &&
+ isValidAssumeForContext(I, Q.CxtI, Q.DT))
+ return true;
+ }
+
return false;
}
@@ -10231,10 +10275,10 @@ void llvm::findValuesAffectedByCondition(
Worklist.push_back(B);
}
} else if (match(V, m_ICmp(Pred, m_Value(A), m_Value(B)))) {
- AddCmpOperands(A, B);
-
bool HasRHSC = match(B, m_ConstantInt());
if (ICmpInst::isEquality(Pred)) {
+ AddAffected(A);
+ AddAffected(B);
if (HasRHSC) {
Value *Y;
// (X & C) or (X | C).
@@ -10248,6 +10292,7 @@ void llvm::findValuesAffectedByCondition(
}
}
} else {
+ AddCmpOperands(A, B);
if (HasRHSC) {
// Handle (A + C1) u< C2, which is the canonical form of
// A > C3 && A < C4.
diff --git a/llvm/test/Transforms/InstCombine/icmp-dom.ll b/llvm/test/Transforms/InstCombine/icmp-dom.ll
index ab3bf511ab290..07793e8951de5 100644
--- a/llvm/test/Transforms/InstCombine/icmp-dom.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-dom.ll
@@ -569,11 +569,7 @@ define i1 @test_nonequal_domcond1(i64 %x, i64 %y, i64 %z, i64 %w) {
; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[COND1]], i1 true, i1 [[COND2]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
; CHECK: if.then:
-; CHECK-NEXT: [[SUB1:%.*]] = sub i64 [[W]], [[Z]]
-; CHECK-NEXT: [[SUB2:%.*]] = sub i64 [[Y]], [[X]]
-; CHECK-NEXT: [[UMIN:%.*]] = call i64 @llvm.umin.i64(i64 [[SUB1]], i64 [[SUB2]])
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[UMIN]], 0
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 false
; CHECK: if.end:
; CHECK-NEXT: ret i1 false
;
@@ -602,11 +598,7 @@ define i1 @test_nonequal_domcond2(i64 %x, i64 %y, i64 %z, i64 %w) {
; CHECK-NEXT: [[OR_COND:%.*]] = select i1 [[COND1]], i1 [[COND2]], i1 false
; CHECK-NEXT: br i1 [[OR_COND]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
; CHECK: if.then:
-; CHECK-NEXT: [[SUB1:%.*]] = sub i64 [[W]], [[Z]]
-; CHECK-NEXT: [[SUB2:%.*]] = sub i64 [[Y]], [[X]]
-; CHECK-NEXT: [[UMIN:%.*]] = call i64 @llvm.umin.i64(i64 [[SUB1]], i64 [[SUB2]])
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[UMIN]], 0
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 false
; CHECK: if.end:
; CHECK-NEXT: ret i1 false
;
@@ -634,11 +626,7 @@ define i1 @test_nonequal_assume(i64 %x, i64 %y, i64 %z, i64 %w) {
; CHECK-NEXT: call void @llvm.assume(i1 [[COND1]])
; CHECK-NEXT: [[COND2:%.*]] = icmp ne i64 [[W:%.*]], [[Z:%.*]]
; CHECK-NEXT: call void @llvm.assume(i1 [[COND2]])
-; CHECK-NEXT: [[SUB1:%.*]] = sub i64 [[W]], [[Z]]
-; CHECK-NEXT: [[SUB2:%.*]] = sub i64 [[Y]], [[X]]
-; CHECK-NEXT: [[UMIN:%.*]] = call i64 @llvm.umin.i64(i64 [[SUB1]], i64 [[SUB2]])
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[UMIN]], 0
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 false
;
entry:
%cond1 = icmp ne i64 %y, %x
>From a8d36839a5c49d636a0dc706531b40a82ac6f297 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 24 Nov 2024 00:27:53 +0800
Subject: [PATCH 3/4] [ValueTracking] Adjust evaluation order
---
llvm/lib/Analysis/ValueTracking.cpp | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 8d28bd235281b..2a49a10447e0b 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -3865,17 +3865,17 @@ static bool isKnownNonEqual(const Value *V1, const Value *V2,
for (BranchInst *BI : Q.DC->conditionsFor(V1)) {
Value *Cond = BI->getCondition();
BasicBlockEdge Edge0(BI->getParent(), BI->getSuccessor(0));
- if (isImpliedCondition(Cond, ICmpInst::ICMP_NE, V1, V2, Q.DL,
+ if (Q.DT->dominates(Edge0, Q.CxtI->getParent()) &&
+ isImpliedCondition(Cond, ICmpInst::ICMP_NE, V1, V2, Q.DL,
/*LHSIsTrue=*/true, Depth)
- .value_or(false) &&
- Q.DT->dominates(Edge0, Q.CxtI->getParent()))
+ .value_or(false))
return true;
BasicBlockEdge Edge1(BI->getParent(), BI->getSuccessor(1));
- if (isImpliedCondition(Cond, ICmpInst::ICMP_NE, V1, V2, Q.DL,
+ if (Q.DT->dominates(Edge1, Q.CxtI->getParent()) &&
+ isImpliedCondition(Cond, ICmpInst::ICMP_NE, V1, V2, Q.DL,
/*LHSIsTrue=*/false, Depth)
- .value_or(false) &&
- Q.DT->dominates(Edge1, Q.CxtI->getParent()))
+ .value_or(false))
return true;
}
}
>From 8b5145c718a41f1cbfe463def3ad88a89afb17e8 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Thu, 6 Feb 2025 11:18:07 +0800
Subject: [PATCH 4/4] [BasicAA] Update tests. NFC.
---
llvm/test/Analysis/BasicAA/fallback-mayalias.ll | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/test/Analysis/BasicAA/fallback-mayalias.ll b/llvm/test/Analysis/BasicAA/fallback-mayalias.ll
index 861351871f818..52eb494c8d75e 100644
--- a/llvm/test/Analysis/BasicAA/fallback-mayalias.ll
+++ b/llvm/test/Analysis/BasicAA/fallback-mayalias.ll
@@ -3,7 +3,7 @@
; Check that BasicAA falls back to MayAlias (instead of PartialAlias) when none
; of its little tricks are applicable.
-; CHECK: MayAlias: float* %arrayidxA, float* %arrayidxB
+; CHECK: NoAlias: float* %arrayidxA, float* %arrayidxB
define void @fallback_mayalias(ptr noalias nocapture %C, i64 %i, i64 %j) local_unnamed_addr {
entry:
More information about the llvm-commits
mailing list