[llvm] ValueTracking: generalize isNonEqualPHIs (PR #108820)

Ramkumar Ramachandra via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 25 04:28:59 PDT 2024


https://github.com/artagnon updated https://github.com/llvm/llvm-project/pull/108820

>From 9a3f743927f8fc441c456306b65d18adab78c987 Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Mon, 16 Sep 2024 13:20:19 +0100
Subject: [PATCH 1/3] ValueTracking: generalize isNonEqualPHIs

isNonEqualPHIs was originally added in 3fd64cc ([ValueTracking] Handle
two PHIs in isKnownNonEqual()), but as the new test case shows, it is
not powerful enough. Generalize it, removing the APInt-specific
comparison, and extend isKnownNonEqual to handle the case when one of
the operands is a constant.
---
 llvm/lib/Analysis/ValueTracking.cpp           | 21 +++++----------
 .../Analysis/ValueTracking/known-non-equal.ll | 26 +++++++++++++++++++
 2 files changed, 32 insertions(+), 15 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 56eb3f99b39d2c..37c30bd6dd2ce1 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -2697,11 +2697,6 @@ static bool isNonZeroSub(const APInt &DemandedElts, unsigned Depth,
   if (matchOpWithOpEqZero(X, Y))
     return true;
 
-  // TODO: Move this case into isKnownNonEqual().
-  if (auto *C = dyn_cast<Constant>(X))
-    if (C->isNullValue() && isKnownNonZero(Y, DemandedElts, Q, Depth))
-      return true;
-
   return ::isKnownNonEqual(X, Y, DemandedElts, Depth, Q);
 }
 
@@ -3537,25 +3532,15 @@ static bool isNonEqualPHIs(const PHINode *PN1, const PHINode *PN2,
     return false;
 
   SmallPtrSet<const BasicBlock *, 8> VisitedBBs;
-  bool UsedFullRecursion = false;
   for (const BasicBlock *IncomBB : PN1->blocks()) {
     if (!VisitedBBs.insert(IncomBB).second)
       continue; // Don't reprocess blocks that we have dealt with already.
     const Value *IV1 = PN1->getIncomingValueForBlock(IncomBB);
     const Value *IV2 = PN2->getIncomingValueForBlock(IncomBB);
-    const APInt *C1, *C2;
-    if (match(IV1, m_APInt(C1)) && match(IV2, m_APInt(C2)) && *C1 != *C2)
-      continue;
-
-    // Only one pair of phi operands is allowed for full recursion.
-    if (UsedFullRecursion)
-      return false;
-
     SimplifyQuery RecQ = Q.getWithoutCondContext();
     RecQ.CxtI = IncomBB->getTerminator();
     if (!isKnownNonEqual(IV1, IV2, DemandedElts, Depth + 1, RecQ))
       return false;
-    UsedFullRecursion = true;
   }
   return true;
 }
@@ -3642,6 +3627,12 @@ static bool isKnownNonEqual(const Value *V1, const Value *V2,
     // We can't look through casts yet.
     return false;
 
+  if (isa<Constant>(V2))
+    std::swap(V1, V2);
+  if (auto *C = dyn_cast<Constant>(V1))
+    if (C->isNullValue() && isKnownNonZero(V2, DemandedElts, Q, Depth))
+      return true;
+
   if (Depth >= MaxAnalysisRecursionDepth)
     return false;
 
diff --git a/llvm/test/Analysis/ValueTracking/known-non-equal.ll b/llvm/test/Analysis/ValueTracking/known-non-equal.ll
index d67f1b56621476..824a62b618d983 100644
--- a/llvm/test/Analysis/ValueTracking/known-non-equal.ll
+++ b/llvm/test/Analysis/ValueTracking/known-non-equal.ll
@@ -316,6 +316,32 @@ exit:
   ret i1 %cmp
 }
 
+define i1 @known_non_equal_phis2(i8 %p, i8 %n) {
+; CHECK-LABEL: @known_non_equal_phis2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[A:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[NEXT:%.*]], [[LOOP]] ]
+; CHECK-NEXT:    [[NEXT]] = add nsw i8 [[A]], 2
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i8 [[A]], [[N:%.*]]
+; CHECK-NEXT:    br i1 [[CMP1]], label [[EXIT:%.*]], label [[LOOP]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  %known.nonzero = add nuw i8 %p, 1
+  br label %loop
+loop:
+  %A = phi i8 [ 0, %entry ], [ %next, %loop ]
+  %B = phi i8 [ %known.nonzero, %entry ], [ %A, %loop ]
+  %next = add nsw i8 %A, 2
+  %cmp1 = icmp eq i8 %A, %n
+  br i1 %cmp1, label %exit, label %loop
+exit:
+  %cmp = icmp ne i8 %A, %B
+  ret i1 %cmp
+}
+
 define i1 @known_non_equal_phis_fail(i8 %p, ptr %pq, i8 %n, i8 %r) {
 ; CHECK-LABEL: @known_non_equal_phis_fail(
 ; CHECK-NEXT:  entry:

>From fb1933c19e530bca7b998e01ef71e67efe62b7c7 Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Mon, 16 Sep 2024 14:05:34 +0100
Subject: [PATCH 2/3] ValueTracking: avoid compile-time blowup

---
 llvm/lib/Analysis/ValueTracking.cpp | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 37c30bd6dd2ce1..9d2713d9cc3f40 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -3537,9 +3537,11 @@ static bool isNonEqualPHIs(const PHINode *PN1, const PHINode *PN2,
       continue; // Don't reprocess blocks that we have dealt with already.
     const Value *IV1 = PN1->getIncomingValueForBlock(IncomBB);
     const Value *IV2 = PN2->getIncomingValueForBlock(IncomBB);
+    const unsigned PhiRecursionLimit =
+        std::max(Depth, MaxAnalysisRecursionDepth - 2);
     SimplifyQuery RecQ = Q.getWithoutCondContext();
     RecQ.CxtI = IncomBB->getTerminator();
-    if (!isKnownNonEqual(IV1, IV2, DemandedElts, Depth + 1, RecQ))
+    if (!isKnownNonEqual(IV1, IV2, DemandedElts, PhiRecursionLimit, RecQ))
       return false;
   }
   return true;

>From 62c0f62280868f3c5cf1a4154452c1f2636fc328 Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Wed, 25 Sep 2024 11:50:49 +0100
Subject: [PATCH 3/3] ValueTracking: fix thinko, crash; add test

---
 llvm/lib/Analysis/ValueTracking.cpp           |  2 +-
 .../Analysis/ValueTracking/known-non-equal.ll | 50 +++++++++++++++++++
 2 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 9d2713d9cc3f40..39872e022f42e5 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -3538,7 +3538,7 @@ static bool isNonEqualPHIs(const PHINode *PN1, const PHINode *PN2,
     const Value *IV1 = PN1->getIncomingValueForBlock(IncomBB);
     const Value *IV2 = PN2->getIncomingValueForBlock(IncomBB);
     const unsigned PhiRecursionLimit =
-        std::max(Depth, MaxAnalysisRecursionDepth - 2);
+        std::max(Depth + 1, MaxAnalysisRecursionDepth - 2);
     SimplifyQuery RecQ = Q.getWithoutCondContext();
     RecQ.CxtI = IncomBB->getTerminator();
     if (!isKnownNonEqual(IV1, IV2, DemandedElts, PhiRecursionLimit, RecQ))
diff --git a/llvm/test/Analysis/ValueTracking/known-non-equal.ll b/llvm/test/Analysis/ValueTracking/known-non-equal.ll
index 824a62b618d983..c669613afbabf8 100644
--- a/llvm/test/Analysis/ValueTracking/known-non-equal.ll
+++ b/llvm/test/Analysis/ValueTracking/known-non-equal.ll
@@ -342,6 +342,56 @@ exit:
   ret i1 %cmp
 }
 
+define i1 @phi_max_recursion_limit(i1 %cond, i32 %switch.cond) {
+; CHECK-LABEL: @phi_max_recursion_limit(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[BB0:%.*]]
+; CHECK:       bb0:
+; CHECK-NEXT:    [[PHIA_0:%.*]] = phi i32 [ [[PHIA_1:%.*]], [[BB1:%.*]] ], [ 0, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    [[PHIB_0:%.*]] = phi i32 [ [[PHIB_1:%.*]], [[BB1]] ], [ 0, [[ENTRY]] ]
+; CHECK-NEXT:    br i1 [[COND:%.*]], label [[SWITCH_BLOCK:%.*]], label [[EXIT:%.*]]
+; CHECK:       switch.block:
+; CHECK-NEXT:    switch i32 [[SWITCH_COND:%.*]], label [[BB1]] [
+; CHECK-NEXT:      i32 0, label [[EPILOGUE:%.*]]
+; CHECK-NEXT:      i32 1, label [[EPILOGUE]]
+; CHECK-NEXT:    ]
+; CHECK:       bb1:
+; CHECK-NEXT:    [[PHIA_1]] = phi i32 [ [[PHIA_0]], [[SWITCH_BLOCK]] ], [ 0, [[EPILOGUE]] ]
+; CHECK-NEXT:    [[PHIB_1]] = phi i32 [ [[PHIB_0]], [[SWITCH_BLOCK]] ], [ 0, [[EPILOGUE]] ]
+; CHECK-NEXT:    br label [[BB0]]
+; CHECK:       epilogue:
+; CHECK-NEXT:    br label [[BB1]]
+; CHECK:       exit:
+; CHECK-NEXT:    [[RET:%.*]] = icmp eq i32 [[PHIA_0]], [[PHIB_0]]
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+entry:
+  br label %bb0
+
+bb0:
+  %phiA.0 = phi i32 [ %phiA.1, %bb1 ], [ 0, %entry ]
+  %phiB.0 = phi i32 [ %phiB.1, %bb1 ], [ 0, %entry ]
+  br i1 %cond, label %switch.block, label %exit
+
+switch.block:
+  switch i32 %switch.cond, label %bb1 [
+  i32 0, label %epilogue
+  i32 1, label %epilogue
+  ]
+
+bb1:
+  %phiA.1 = phi i32 [ %phiA.0, %switch.block ], [ 0, %epilogue ]
+  %phiB.1 = phi i32 [ %phiB.0, %switch.block ], [ 0, %epilogue ]
+  br label %bb0
+
+epilogue:
+  br label %bb1
+
+exit:
+  %ret = icmp eq i32 %phiA.0, %phiB.0
+  ret i1 %ret
+}
+
 define i1 @known_non_equal_phis_fail(i8 %p, ptr %pq, i8 %n, i8 %r) {
 ; CHECK-LABEL: @known_non_equal_phis_fail(
 ; CHECK-NEXT:  entry:



More information about the llvm-commits mailing list