[llvm] 5502053 - [MemoryDependenceAnalysis] Disambiguate visited state in non-local pointer dep tracking (#193220)

via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 23 02:24:49 PDT 2026


Author: Nathiyaa Sengodan
Date: 2026-04-23T11:24:43+02:00
New Revision: 5502053d578657d2ec6f69b06aa4e0de3e64fc10

URL: https://github.com/llvm/llvm-project/commit/5502053d578657d2ec6f69b06aa4e0de3e64fc10
DIFF: https://github.com/llvm/llvm-project/commit/5502053d578657d2ec6f69b06aa4e0de3e64fc10.diff

LOG: [MemoryDependenceAnalysis] Disambiguate visited state in non-local pointer dep tracking (#193220)

NonLocalPointerDepVisited used nullptr for both "not visited basic block
in current epoch" and "visited, but PHI translation failed". This
ambiguity could cause incorrect predecessor-state handling in non-local
dependency queries and trigger a GVN LoadPRE assertion crash.

Use NonLocalPointerDepEpoch to explicitly check visited state instead of
inferring from the stored pointer value

Fixes https://github.com/llvm/llvm-project/issues/190585

Added: 
    llvm/test/Transforms/GVN/PRE/load-pre-num-unavailable-preds-crash.ll

Modified: 
    llvm/include/llvm/Analysis/MemoryDependenceAnalysis.h
    llvm/lib/Analysis/MemoryDependenceAnalysis.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Analysis/MemoryDependenceAnalysis.h b/llvm/include/llvm/Analysis/MemoryDependenceAnalysis.h
index d4c8a784304c4..1d96ffb6a38ee 100644
--- a/llvm/include/llvm/Analysis/MemoryDependenceAnalysis.h
+++ b/llvm/include/llvm/Analysis/MemoryDependenceAnalysis.h
@@ -494,6 +494,7 @@ class MemoryDependenceResults {
                                      BasicBlock::iterator ScanIt,
                                      BasicBlock *BB);
   void setNonLocalPointerDepVisited(BasicBlock *BB, Value *V);
+  bool isNonLocalPointerDepVisited(BasicBlock *BB) const;
   Value *lookupNonLocalPointerDepVisited(BasicBlock *BB) const;
   bool getNonLocalPointerDepFromBB(Instruction *QueryInst,
                                    const PHITransAddr &Pointer,

diff  --git a/llvm/lib/Analysis/MemoryDependenceAnalysis.cpp b/llvm/lib/Analysis/MemoryDependenceAnalysis.cpp
index 4431ed2357571..1ef762bcf7007 100644
--- a/llvm/lib/Analysis/MemoryDependenceAnalysis.cpp
+++ b/llvm/lib/Analysis/MemoryDependenceAnalysis.cpp
@@ -1029,10 +1029,17 @@ void MemoryDependenceResults::setNonLocalPointerDepVisited(BasicBlock *BB,
   NonLocalPointerDepVisited[BB->getNumber()] = {V, NonLocalPointerDepEpoch};
 }
 
+bool MemoryDependenceResults::isNonLocalPointerDepVisited(
+    BasicBlock *BB) const {
+  return NonLocalPointerDepVisited[BB->getNumber()].second ==
+         NonLocalPointerDepEpoch;
+}
+
 Value *
 MemoryDependenceResults::lookupNonLocalPointerDepVisited(BasicBlock *BB) const {
-  auto &Entry = NonLocalPointerDepVisited[BB->getNumber()];
-  return Entry.second == NonLocalPointerDepEpoch ? Entry.first : nullptr;
+  assert(isNonLocalPointerDepVisited(BB) &&
+         "Visited value requested for unseen block");
+  return NonLocalPointerDepVisited[BB->getNumber()].first;
 }
 
 /// Perform a dependency query based on pointer/pointeesize starting at the end
@@ -1130,8 +1137,10 @@ bool MemoryDependenceResults::getNonLocalPointerDepFromBB(
     // to ensure that if a block in the results set is in the visited set that
     // it was for the same pointer query.
     for (auto &Entry : *Cache) {
+      if (!isNonLocalPointerDepVisited(Entry.getBB()))
+        continue;
       Value *Prev = lookupNonLocalPointerDepVisited(Entry.getBB());
-      if (!Prev || Prev == Pointer.getAddr())
+      if (Prev == Pointer.getAddr())
         continue;
 
       // We have a pointer mismatch in a block.  Just return false, saying
@@ -1215,7 +1224,7 @@ bool MemoryDependenceResults::getNonLocalPointerDepFromBB(
     if (!SkipFirstBlock) {
       // Analyze the dependency of *Pointer in FromBB.  See if we already have
       // been here.
-      assert(lookupNonLocalPointerDepVisited(BB) &&
+      assert(isNonLocalPointerDepVisited(BB) &&
              "Should check 'visited' before adding to WL");
 
       // Get the dependency info for Pointer in BB.  If we have cached
@@ -1242,14 +1251,13 @@ bool MemoryDependenceResults::getNonLocalPointerDepFromBB(
       SmallVector<BasicBlock *, 16> NewBlocks;
       for (BasicBlock *Pred : PredCache.get(BB)) {
         // Verify that we haven't looked at this block yet.
-        Value *Prev = lookupNonLocalPointerDepVisited(Pred);
-        if (!Prev) {
+        if (!isNonLocalPointerDepVisited(Pred)) {
           setNonLocalPointerDepVisited(Pred, Pointer.getAddr());
           // First time we've looked at *PI.
           NewBlocks.push_back(Pred);
           continue;
         }
-
+        Value *Prev = lookupNonLocalPointerDepVisited(Pred);
         // If we have seen this block before, but it was with a 
diff erent
         // pointer then we have a phi translation failure and we have to treat
         // this as a clobber.
@@ -1305,11 +1313,11 @@ bool MemoryDependenceResults::getNonLocalPointerDepFromBB(
       // with PHI translation when a critical edge exists and the PHI node in
       // the successor translates to a pointer value 
diff erent than the
       // pointer the block was first analyzed with.
-      Value *PrevVal = lookupNonLocalPointerDepVisited(Pred);
-      if (!PrevVal) {
+      if (!isNonLocalPointerDepVisited(Pred)) {
         setNonLocalPointerDepVisited(Pred, PredPtrVal);
         continue;
       }
+      Value *PrevVal = lookupNonLocalPointerDepVisited(Pred);
 
       // We found the pred; take it off the list of preds to visit.
       PredList.pop_back();

diff  --git a/llvm/test/Transforms/GVN/PRE/load-pre-num-unavailable-preds-crash.ll b/llvm/test/Transforms/GVN/PRE/load-pre-num-unavailable-preds-crash.ll
new file mode 100644
index 0000000000000..769f3db85f979
--- /dev/null
+++ b/llvm/test/Transforms/GVN/PRE/load-pre-num-unavailable-preds-crash.ll
@@ -0,0 +1,60 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -S -passes=gvn < %s | FileCheck %s
+
+; Regression test for a GVN PRE assertion crash in PerformLoadPRE.
+
+ at b = external global [1 x i32]
+
+define void @e() {
+; CHECK-LABEL: define void @e() {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    br i1 true, label %[[FOR_END4:.*]], label %[[ENTRY_C_CRIT_EDGE:.*]]
+; CHECK:       [[ENTRY_C_CRIT_EDGE]]:
+; CHECK-NEXT:    [[DOTPRE1:%.*]] = load i32, ptr null, align 4
+; CHECK-NEXT:    br label %[[C:.*]]
+; CHECK:       [[FOR_END4]]:
+; CHECK-NEXT:    store i32 0, ptr getelementptr inbounds nuw (i8, ptr @b, i64 4), align 4
+; CHECK-NEXT:    [[DOTPRE:%.*]] = load i32, ptr null, align 4
+; CHECK-NEXT:    br label %[[FOR_COND5:.*]]
+; CHECK:       [[FOR_COND5]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = phi i32 [ [[TMP1:%.*]], %[[C]] ], [ [[DOTPRE]], %[[FOR_END4]] ]
+; CHECK-NEXT:    [[CMP6:%.*]] = icmp eq i32 [[TMP0]], 0
+; CHECK-NEXT:    br i1 [[CMP6]], label %[[FOR_COND5_C_CRIT_EDGE:.*]], label %[[FOR_END8:.*]]
+; CHECK:       [[FOR_COND5_C_CRIT_EDGE]]:
+; CHECK-NEXT:    [[DOTPRE2:%.*]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @b, i64 4), align 4
+; CHECK-NEXT:    br label %[[C]]
+; CHECK:       [[C]]:
+; CHECK-NEXT:    [[TMP1]] = phi i32 [ poison, %[[ENTRY_C_CRIT_EDGE]] ], [ [[DOTPRE2]], %[[FOR_COND5_C_CRIT_EDGE]] ]
+; CHECK-NEXT:    [[TMP2:%.*]] = phi i32 [ [[DOTPRE1]], %[[ENTRY_C_CRIT_EDGE]] ], [ 0, %[[FOR_COND5_C_CRIT_EDGE]] ]
+; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[TMP2]], 1
+; CHECK-NEXT:    [[IDXPROM:%.*]] = zext i32 [[ADD]] to i64
+; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr [4 x i8], ptr @b, i64 [[IDXPROM]]
+; CHECK-NEXT:    store i32 [[TMP1]], ptr null, align 4
+; CHECK-NEXT:    br label %[[FOR_COND5]]
+; CHECK:       [[FOR_END8]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br i1 true, label %for.end4, label %c
+
+for.end4:                                         ; preds = %entry
+  store i32 0, ptr getelementptr inbounds nuw (i8, ptr @b, i64 4), align 4
+  br label %for.cond5
+
+for.cond5:                                        ; preds = %c, %for.end4
+  %0 = load i32, ptr null, align 4
+  %cmp6 = icmp eq i32 %0, 0
+  br i1 %cmp6, label %c, label %for.end8
+
+c:                                                ; preds = %for.cond5, %entry
+  %1 = load i32, ptr null, align 4
+  %add = add i32 %1, 1
+  %idxprom = zext i32 %add to i64
+  %arrayidx = getelementptr [4 x i8], ptr @b, i64 %idxprom
+  %2 = load i32, ptr %arrayidx, align 4
+  store i32 %2, ptr null, align 4
+  br label %for.cond5
+
+for.end8:                                         ; preds = %for.cond5
+  ret void
+}


        


More information about the llvm-commits mailing list