[llvm] c04c945 - [ValueTracking] Handle chain of single-pred blocks in willNotFreeBetween() (#202308)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 9 00:50:19 PDT 2026


Author: Nikita Popov
Date: 2026-06-09T07:50:14Z
New Revision: c04c945d2563297ca75baf13050594e2bd3dcec5

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

LOG: [ValueTracking] Handle chain of single-pred blocks in willNotFreeBetween() (#202308)

willNotFreeBetween() currently handles the case where both instructions
are in the same block, or one is in the single predecessor of the other.
This patch extends this to handle a chain of single predecessor blocks.

The budget now applies to all checked instructions, rather than per
block. Also increase the budget by a factor of two (which means that new
budget interpretation should never regress relative to the previous).

Added: 
    

Modified: 
    llvm/lib/Analysis/ValueTracking.cpp
    llvm/test/Transforms/LICM/hoist-deref-load.ll
    llvm/test/Transforms/SLPVectorizer/AArch64/masked-loads-side-effects-after-vec.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index e648ef5494130..04def11136d35 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -94,7 +94,7 @@ static cl::opt<unsigned> DomConditionsMaxUses("dom-conditions-max-uses",
 
 /// Maximum number of instructions to check between assume and context
 /// instruction.
-static constexpr unsigned MaxInstrsToCheckForFree = 16;
+static constexpr unsigned MaxInstrsToCheckForFree = 32;
 
 /// Returns the bitwidth of the given scalar or pointer type. For vector types,
 /// returns the element type's bitwidth.
@@ -705,9 +705,10 @@ bool llvm::isValidAssumeForContext(const Instruction *Inv,
 bool llvm::willNotFreeBetween(const Instruction *Assume,
                               const Instruction *CtxI) {
   // Helper to check if there are any calls in the range that may free memory.
-  auto hasNoFreeInRange = [](auto Range) {
-    for (const auto &[Idx, I] : enumerate(Range)) {
-      if (Idx > MaxInstrsToCheckForFree)
+  unsigned NumChecked = 0;
+  auto hasNoFreeInRange = [&NumChecked](auto Range) {
+    for (const Instruction &I : Range) {
+      if (NumChecked++ > MaxInstrsToCheckForFree)
         return false;
 
       if (auto *CB = dyn_cast<CallBase>(&I)) {
@@ -719,27 +720,32 @@ bool llvm::willNotFreeBetween(const Instruction *Assume,
     return true;
   };
 
-  // Handle cross-block case: CtxI in a successor of Assume's block.
   const BasicBlock *CtxBB = CtxI->getParent();
   const BasicBlock *AssumeBB = Assume->getParent();
   BasicBlock::const_iterator CtxIter = CtxI->getIterator();
-  if (CtxBB != AssumeBB) {
-    if (CtxBB->getSinglePredecessor() != AssumeBB)
+  if (CtxBB == AssumeBB) {
+    // Same block case: check that Assume comes before CtxI.
+    if (Assume != CtxI && !Assume->comesBefore(CtxI))
       return false;
+    return hasNoFreeInRange(make_range(Assume->getIterator(), CtxIter));
+  }
+
+  // Handle chain of single-predecessor blocks.
+  const BasicBlock *CurBB = CtxBB;
+  while (true) {
+    if (CurBB == AssumeBB)
+      return hasNoFreeInRange(
+          make_range(Assume->getIterator(), AssumeBB->end()));
 
-    if (!hasNoFreeInRange(make_range(CtxBB->begin(), CtxIter)))
+    const BasicBlock *PredBB = CurBB->getSinglePredecessor();
+    if (!PredBB)
       return false;
 
-    CtxIter = AssumeBB->end();
-  } else {
-    // Same block case: check that Assume comes before CtxI.
-    if (Assume != CtxI && !Assume->comesBefore(CtxI))
+    if (!hasNoFreeInRange(make_range(CurBB->begin(),
+                                     CurBB == CtxBB ? CtxIter : CurBB->end())))
       return false;
+    CurBB = PredBB;
   }
-
-  // Check if there are any calls between Assume and CtxIter that may free
-  // memory.
-  return hasNoFreeInRange(make_range(Assume->getIterator(), CtxIter));
 }
 
 // TODO: cmpExcludesZero misses many cases where `RHS` is non-constant but

diff  --git a/llvm/test/Transforms/LICM/hoist-deref-load.ll b/llvm/test/Transforms/LICM/hoist-deref-load.ll
index c498e85ddd6c2..4ff21a34afa3b 100644
--- a/llvm/test/Transforms/LICM/hoist-deref-load.ll
+++ b/llvm/test/Transforms/LICM/hoist-deref-load.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; RUN: opt -S -passes=licm -verify-memoryssa < %s | FileCheck %s
+; RUN: opt -S -passes=licm -verify-memoryssa -use-dereferenceable-at-point-semantics < %s | FileCheck %s
 ; RUN: opt -aa-pipeline=basic-aa -passes='require<opt-remark-emit>,loop-mssa(loop-simplifycfg,licm)' -verify-memoryssa -S < %s | FileCheck %s
 
 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"

diff  --git a/llvm/test/Transforms/SLPVectorizer/AArch64/masked-loads-side-effects-after-vec.ll b/llvm/test/Transforms/SLPVectorizer/AArch64/masked-loads-side-effects-after-vec.ll
index ca3c8bbac6366..df4c527aa216a 100644
--- a/llvm/test/Transforms/SLPVectorizer/AArch64/masked-loads-side-effects-after-vec.ll
+++ b/llvm/test/Transforms/SLPVectorizer/AArch64/masked-loads-side-effects-after-vec.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
 ; RUN: opt -S --passes=slp-vectorizer -mtriple=aarch64-unknown-linux-gnu < %s | FileCheck %s
+; RUN: opt -S --passes=slp-vectorizer -mtriple=aarch64-unknown-linux-gnu -use-dereferenceable-at-point-semantics < %s | FileCheck %s
 
 declare noalias ptr @malloc()
 


        


More information about the llvm-commits mailing list