[llvm] [LoopSafetyInfo] Store Loop and automatically compute (NFC) (PR #221238)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 7 01:38:01 PDT 2026


https://github.com/nikic updated https://github.com/llvm/llvm-project/pull/221238

>From 45f18c9d132b729e3991290b0076f1c40d7f73fb Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Fri, 4 Sep 2026 16:37:28 +0200
Subject: [PATCH 1/3] Store Loop in LoopSafetyInfo

---
 llvm/include/llvm/Analysis/MustExecute.h      | 43 +++++++++---------
 llvm/lib/Analysis/MustExecute.cpp             | 45 +++++++++----------
 llvm/lib/Transforms/Scalar/LICM.cpp           | 20 ++++-----
 .../Transforms/Scalar/LoopIdiomRecognize.cpp  |  4 +-
 .../Transforms/Scalar/SimpleLoopUnswitch.cpp  | 12 ++---
 .../lib/Transforms/Utils/LoopUnrollAndJam.cpp |  4 +-
 .../Vectorize/LoopVectorizationLegality.cpp   |  6 +--
 7 files changed, 63 insertions(+), 71 deletions(-)

diff --git a/llvm/include/llvm/Analysis/MustExecute.h b/llvm/include/llvm/Analysis/MustExecute.h
index af78d8e5e982d..deb04738bcc5d 100644
--- a/llvm/include/llvm/Analysis/MustExecute.h
+++ b/llvm/include/llvm/Analysis/MustExecute.h
@@ -66,8 +66,10 @@ class LoopSafetyInfo {
   mutable DenseMap<const BasicBlock *, bool> GuaranteedToExecute;
 
 protected:
+  const Loop *CurLoop;
+
   /// Computes block colors.
-  LLVM_ABI void computeBlockColors(const Loop *CurLoop);
+  LLVM_ABI void computeBlockColors();
 
 public:
   /// Returns block colors map that is used to update funclet operand bundles.
@@ -85,13 +87,11 @@ class LoopSafetyInfo {
   virtual bool anyBlockMayThrow() const = 0;
 
   /// Return true if we must reach the block \p BB under assumption that the
-  /// loop \p CurLoop is entered.
-  LLVM_ABI bool allLoopPathsLeadToBlock(const Loop *CurLoop,
-                                        const BasicBlock *BB,
+  /// loop is entered.
+  LLVM_ABI bool allLoopPathsLeadToBlock(const BasicBlock *BB,
                                         const DominatorTree *DT) const;
 
-  LLVM_ABI bool allLoopPathsLeadToBlockImpl(const Loop *CurLoop,
-                                            const BasicBlock *BB,
+  LLVM_ABI bool allLoopPathsLeadToBlockImpl(const BasicBlock *BB,
                                             const DominatorTree *DT) const;
 
   /// Computes safety information for a loop checks loop body & header for
@@ -99,15 +99,14 @@ class LoopSafetyInfo {
   /// as argument. Updates safety information in LoopSafetyInfo argument.
   /// Note: This is defined to clear and reinitialize an already initialized
   /// LoopSafetyInfo.  Some callers rely on this fact.
-  virtual void computeLoopSafetyInfo(const Loop *CurLoop) = 0;
+  virtual void computeLoopSafetyInfo() = 0;
 
   /// Returns true if the instruction in a loop is guaranteed to execute at
   /// least once (under the assumption that the loop is entered).
   virtual bool isGuaranteedToExecute(const Instruction &Inst,
-                                     const DominatorTree *DT,
-                                     const Loop *CurLoop) const = 0;
+                                     const DominatorTree *DT) const = 0;
 
-  LoopSafetyInfo() = default;
+  LoopSafetyInfo(const Loop *CurLoop) : CurLoop(CurLoop) {}
 
   virtual ~LoopSafetyInfo() = default;
 };
@@ -122,15 +121,16 @@ class LLVM_ABI SimpleLoopSafetyInfo : public LoopSafetyInfo {
   bool HeaderMayThrow = false; // Same as previous, but specific to loop header
 
 public:
+  SimpleLoopSafetyInfo(const Loop *L) : LoopSafetyInfo(L) {}
+
   bool blockMayThrow(const BasicBlock *BB) const override;
 
   bool anyBlockMayThrow() const override;
 
-  void computeLoopSafetyInfo(const Loop *CurLoop) override;
+  void computeLoopSafetyInfo() override;
 
   bool isGuaranteedToExecute(const Instruction &Inst,
-                             const DominatorTree *DT,
-                             const Loop *CurLoop) const override;
+                             const DominatorTree *DT) const override;
 };
 
 /// This implementation of LoopSafetyInfo use ImplicitControlFlowTracking to
@@ -147,25 +147,24 @@ class LLVM_ABI ICFLoopSafetyInfo : public LoopSafetyInfo {
   mutable MemoryWriteTracking MW;
 
 public:
+  ICFLoopSafetyInfo(const Loop *L) : LoopSafetyInfo(L) {}
+
   bool blockMayThrow(const BasicBlock *BB) const override;
 
   bool anyBlockMayThrow() const override;
 
-  void computeLoopSafetyInfo(const Loop *CurLoop) override;
+  void computeLoopSafetyInfo() override;
 
   bool isGuaranteedToExecute(const Instruction &Inst,
-                             const DominatorTree *DT,
-                             const Loop *CurLoop) const override;
+                             const DominatorTree *DT) const override;
 
   /// Returns true if we could not execute a memory-modifying instruction before
-  /// we enter \p BB under assumption that \p CurLoop is entered.
-  bool doesNotWriteMemoryBefore(const BasicBlock *BB, const Loop *CurLoop)
-      const;
+  /// we enter \p BB under assumption that the loop is entered.
+  bool doesNotWriteMemoryBefore(const BasicBlock *BB) const;
 
   /// Returns true if we could not execute a memory-modifying instruction before
-  /// we execute \p I under assumption that \p CurLoop is entered.
-  bool doesNotWriteMemoryBefore(const Instruction &I, const Loop *CurLoop)
-      const;
+  /// we execute \p I under assumption that the loopis entered.
+  bool doesNotWriteMemoryBefore(const Instruction &I) const;
 
   /// Inform the safety info that we are planning to insert a new instruction
   /// \p Inst into the basic block \p BB. It will make all cache updates to keep
diff --git a/llvm/lib/Analysis/MustExecute.cpp b/llvm/lib/Analysis/MustExecute.cpp
index cbdeaf8d990d8..5bee66b70adcf 100644
--- a/llvm/lib/Analysis/MustExecute.cpp
+++ b/llvm/lib/Analysis/MustExecute.cpp
@@ -46,7 +46,7 @@ bool SimpleLoopSafetyInfo::anyBlockMayThrow() const {
   return MayThrow;
 }
 
-void SimpleLoopSafetyInfo::computeLoopSafetyInfo(const Loop *CurLoop) {
+void SimpleLoopSafetyInfo::computeLoopSafetyInfo() {
   assert(CurLoop != nullptr && "CurLoop can't be null");
   BasicBlock *Header = CurLoop->getHeader();
   // Iterate over header and compute safety info.
@@ -63,7 +63,7 @@ void SimpleLoopSafetyInfo::computeLoopSafetyInfo(const Loop *CurLoop) {
       break;
   }
 
-  computeBlockColors(CurLoop);
+  computeBlockColors();
 }
 
 bool ICFLoopSafetyInfo::blockMayThrow(const BasicBlock *BB) const {
@@ -74,7 +74,7 @@ bool ICFLoopSafetyInfo::anyBlockMayThrow() const {
   return MayThrow;
 }
 
-void ICFLoopSafetyInfo::computeLoopSafetyInfo(const Loop *CurLoop) {
+void ICFLoopSafetyInfo::computeLoopSafetyInfo() {
   assert(CurLoop != nullptr && "CurLoop can't be null");
   ICF.clear();
   MW.clear();
@@ -85,7 +85,7 @@ void ICFLoopSafetyInfo::computeLoopSafetyInfo(const Loop *CurLoop) {
       MayThrow = true;
       break;
     }
-  computeBlockColors(CurLoop);
+  computeBlockColors();
 }
 
 void ICFLoopSafetyInfo::insertInstructionTo(const Instruction *Inst,
@@ -99,7 +99,7 @@ void ICFLoopSafetyInfo::removeInstruction(const Instruction *Inst) {
   MW.removeInstruction(Inst);
 }
 
-void LoopSafetyInfo::computeBlockColors(const Loop *CurLoop) {
+void LoopSafetyInfo::computeBlockColors() {
   // Compute funclet colors if we might sink/hoist in a function with a funclet
   // personality routine.
   Function *Fn = CurLoop->getHeader()->getParent();
@@ -195,8 +195,7 @@ static void collectTransitivePredecessors(
   }
 }
 
-bool LoopSafetyInfo::allLoopPathsLeadToBlock(const Loop *CurLoop,
-                                             const BasicBlock *BB,
+bool LoopSafetyInfo::allLoopPathsLeadToBlock(const BasicBlock *BB,
                                              const DominatorTree *DT) const {
   assert(CurLoop->contains(BB) && "Should only be called for loop blocks!");
 
@@ -206,12 +205,12 @@ bool LoopSafetyInfo::allLoopPathsLeadToBlock(const Loop *CurLoop,
 
   auto [It, Inserted] = GuaranteedToExecute.try_emplace(BB, false);
   if (Inserted)
-    It->second = allLoopPathsLeadToBlockImpl(CurLoop, BB, DT);
+    It->second = allLoopPathsLeadToBlockImpl(BB, DT);
   return It->second;
 }
 
 bool LoopSafetyInfo::allLoopPathsLeadToBlockImpl(
-    const Loop *CurLoop, const BasicBlock *BB, const DominatorTree *DT) const {
+    const BasicBlock *BB, const DominatorTree *DT) const {
   // Collect all transitive predecessors of BB in the same loop. This set will
   // be a subset of the blocks within the loop.
   SmallPtrSet<const BasicBlock *, 4> Predecessors;
@@ -271,9 +270,8 @@ bool LoopSafetyInfo::allLoopPathsLeadToBlockImpl(
 
 /// Returns true if the instruction in a loop is guaranteed to execute at least
 /// once.
-bool SimpleLoopSafetyInfo::isGuaranteedToExecute(const Instruction &Inst,
-                                                 const DominatorTree *DT,
-                                                 const Loop *CurLoop) const {
+bool SimpleLoopSafetyInfo::isGuaranteedToExecute(
+    const Instruction &Inst, const DominatorTree *DT) const {
   // If the instruction is in the header block for the loop (which is very
   // common), it is always guaranteed to dominate the exit blocks.  Since this
   // is a common case, and can save some work, check it now.
@@ -287,18 +285,16 @@ bool SimpleLoopSafetyInfo::isGuaranteedToExecute(const Instruction &Inst,
 
   // If there is a path from header to exit or latch that doesn't lead to our
   // instruction's block, return false.
-  return allLoopPathsLeadToBlock(CurLoop, Inst.getParent(), DT);
+  return allLoopPathsLeadToBlock(Inst.getParent(), DT);
 }
 
 bool ICFLoopSafetyInfo::isGuaranteedToExecute(const Instruction &Inst,
-                                              const DominatorTree *DT,
-                                              const Loop *CurLoop) const {
+                                              const DominatorTree *DT) const {
   return !ICF.isDominatedByICFIFromSameBlock(&Inst) &&
-         allLoopPathsLeadToBlock(CurLoop, Inst.getParent(), DT);
+         allLoopPathsLeadToBlock(Inst.getParent(), DT);
 }
 
-bool ICFLoopSafetyInfo::doesNotWriteMemoryBefore(const BasicBlock *BB,
-                                                 const Loop *CurLoop) const {
+bool ICFLoopSafetyInfo::doesNotWriteMemoryBefore(const BasicBlock *BB) const {
   assert(CurLoop->contains(BB) && "Should only be called for loop blocks!");
 
   // Fast path: there are no instructions before header.
@@ -317,22 +313,21 @@ bool ICFLoopSafetyInfo::doesNotWriteMemoryBefore(const BasicBlock *BB,
   return true;
 }
 
-bool ICFLoopSafetyInfo::doesNotWriteMemoryBefore(const Instruction &I,
-                                                 const Loop *CurLoop) const {
+bool ICFLoopSafetyInfo::doesNotWriteMemoryBefore(const Instruction &I) const {
   auto *BB = I.getParent();
   assert(CurLoop->contains(BB) && "Should only be called for loop blocks!");
   return !MW.isDominatedByMemoryWriteFromSameBlock(&I) &&
-         doesNotWriteMemoryBefore(BB, CurLoop);
+         doesNotWriteMemoryBefore(BB);
 }
 
 static bool isMustExecuteIn(const Instruction &I, Loop *L, DominatorTree *DT) {
   // TODO: merge these two routines.  For the moment, we display the best
   // result obtained by *either* implementation.  This is a bit unfair since no
   // caller actually gets the full power at the moment.
-  SimpleLoopSafetyInfo LSI;
-  LSI.computeLoopSafetyInfo(L);
-  return LSI.isGuaranteedToExecute(I, DT, L) ||
-    isGuaranteedToExecuteForEveryIteration(&I, L);
+  SimpleLoopSafetyInfo LSI(L);
+  LSI.computeLoopSafetyInfo();
+  return LSI.isGuaranteedToExecute(I, DT) ||
+         isGuaranteedToExecuteForEveryIteration(&I, L);
 }
 
 namespace {
diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp
index ee4c7603fdd2d..27325546d57ec 100644
--- a/llvm/lib/Transforms/Scalar/LICM.cpp
+++ b/llvm/lib/Transforms/Scalar/LICM.cpp
@@ -460,8 +460,8 @@ bool LoopInvariantCodeMotion::runOnLoop(Loop *L, AAResults *AA, LoopInfo *LI,
   BasicBlock *Preheader = L->getLoopPreheader();
 
   // Compute loop safety information.
-  ICFLoopSafetyInfo SafetyInfo;
-  SafetyInfo.computeLoopSafetyInfo(L);
+  ICFLoopSafetyInfo SafetyInfo(L);
+  SafetyInfo.computeLoopSafetyInfo();
 
   // We want to visit all of the instructions in this loop... that are not parts
   // of our subloops (they have already had their invariants hoisted out of
@@ -986,8 +986,8 @@ bool llvm::hoistRegion(DomTreeNode *N, AAResults *AA, LoopInfo *LI,
                match(&I, m_Intrinsic<Intrinsic::invariant_start>());
       };
       auto MustExecuteWithoutWritesBefore = [&](Instruction &I) {
-        return SafetyInfo->isGuaranteedToExecute(I, DT, CurLoop) &&
-               SafetyInfo->doesNotWriteMemoryBefore(I, CurLoop);
+        return SafetyInfo->isGuaranteedToExecute(I, DT) &&
+               SafetyInfo->doesNotWriteMemoryBefore(I);
       };
       if ((IsInvariantStart(I) || isGuard(&I)) &&
           CurLoop->hasLoopInvariantOperands(&I) &&
@@ -1799,7 +1799,7 @@ static void hoist(Instruction &I, const DominatorTree *DT, const Loop *CurLoop,
       // The check on hasMetadataOtherThanDebugLoc is to prevent us from burning
       // time in isGuaranteedToExecute if we don't actually have anything to
       // drop.  It is a compile time optimization, not required for correctness.
-      !SafetyInfo->isGuaranteedToExecute(I, DT, CurLoop)) {
+      !SafetyInfo->isGuaranteedToExecute(I, DT)) {
     I.dropUBImplyingAttrsAndMetadata();
   }
 
@@ -1832,8 +1832,7 @@ static bool isSafeToExecuteUnconditionally(
       isSafeToSpeculativelyExecute(&Inst, CtxI, AC, DT, TLI))
     return true;
 
-  bool GuaranteedToExecute =
-      SafetyInfo->isGuaranteedToExecute(Inst, DT, CurLoop);
+  bool GuaranteedToExecute = SafetyInfo->isGuaranteedToExecute(Inst, DT);
 
   if (!GuaranteedToExecute) {
     auto *LI = dyn_cast<LoadInst>(&Inst);
@@ -2132,7 +2131,7 @@ bool llvm::promoteLoopAccessesToScalars(
 
         if (!LoadIsGuaranteedToExecute)
           LoadIsGuaranteedToExecute =
-              SafetyInfo->isGuaranteedToExecute(*UI, DT, CurLoop);
+              SafetyInfo->isGuaranteedToExecute(*UI, DT);
 
         // Note that proving a load safe to speculate requires proving
         // sufficient alignment at the target location.  Proving it guaranteed
@@ -2162,8 +2161,7 @@ bool llvm::promoteLoopAccessesToScalars(
         // alignment than any other guaranteed stores, in which case we can
         // raise the alignment on the promoted store.
         Align InstAlignment = Store->getAlign();
-        bool GuaranteedToExecute =
-            SafetyInfo->isGuaranteedToExecute(*UI, DT, CurLoop);
+        bool GuaranteedToExecute = SafetyInfo->isGuaranteedToExecute(*UI, DT);
         StoreIsGuaranteedToExecute |= GuaranteedToExecute;
         if (GuaranteedToExecute) {
           DereferenceableInPH = true;
@@ -2365,7 +2363,7 @@ collectPromotionCandidates(MemorySSA *MSSA, AliasAnalysis *AA,
     if (IsPotentiallyPromotable(I)) {
       AttemptingPromotion.insert(I);
       if (StoreInst *SI = dyn_cast<StoreInst>(I);
-          SI && !SafetyInfo->isGuaranteedToExecute(*SI, DT, L)) {
+          SI && !SafetyInfo->isGuaranteedToExecute(*SI, DT)) {
         // Promotion requires inserting a new store at the loop exits; we need
         // to prove that store doesn't alias anything, in addition to proving
         // aliasing for the stores we're removing. The new store is executed
diff --git a/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp b/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp
index 4e5cd8462cc4d..ea82c3ca0ce1f 100644
--- a/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp
@@ -403,8 +403,8 @@ bool LoopIdiomRecognize::runOnCountableLoop() {
 
   // The following transforms hoist stores/memsets into the loop pre-header.
   // Give up if the loop has instructions that may throw.
-  SimpleLoopSafetyInfo SafetyInfo;
-  SafetyInfo.computeLoopSafetyInfo(CurLoop);
+  SimpleLoopSafetyInfo SafetyInfo(CurLoop);
+  SafetyInfo.computeLoopSafetyInfo();
   if (SafetyInfo.anyBlockMayThrow())
     return false;
 
diff --git a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
index ee7998f5bdcc8..561ddb26b928d 100644
--- a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
+++ b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
@@ -2396,9 +2396,9 @@ static void unswitchNontrivialInvariants(
     else {
       // It is only legal to preserve make.implicit metadata if we are
       // guaranteed no reach implicit null check after following this branch.
-      ICFLoopSafetyInfo SafetyInfo;
-      SafetyInfo.computeLoopSafetyInfo(&L);
-      if (!SafetyInfo.isGuaranteedToExecute(TI, &DT, &L))
+      ICFLoopSafetyInfo SafetyInfo(&L);
+      SafetyInfo.computeLoopSafetyInfo();
+      if (!SafetyInfo.isGuaranteedToExecute(TI, &DT))
         TI.setMetadata(LLVMContext::MD_make_implicit, nullptr);
     }
   }
@@ -3555,9 +3555,9 @@ static bool shouldInsertFreeze(Loop &L, Instruction &TI, DominatorTree &DT,
   if (!FreezeLoopUnswitchCond)
     return false;
 
-  ICFLoopSafetyInfo SafetyInfo;
-  SafetyInfo.computeLoopSafetyInfo(&L);
-  if (SafetyInfo.isGuaranteedToExecute(TI, &DT, &L))
+  ICFLoopSafetyInfo SafetyInfo(&L);
+  SafetyInfo.computeLoopSafetyInfo();
+  if (SafetyInfo.isGuaranteedToExecute(TI, &DT))
     return false;
 
   Value *Cond;
diff --git a/llvm/lib/Transforms/Utils/LoopUnrollAndJam.cpp b/llvm/lib/Transforms/Utils/LoopUnrollAndJam.cpp
index b04cfd1a33b7c..5814399f79076 100644
--- a/llvm/lib/Transforms/Utils/LoopUnrollAndJam.cpp
+++ b/llvm/lib/Transforms/Utils/LoopUnrollAndJam.cpp
@@ -948,8 +948,8 @@ bool llvm::isSafeToUnrollAndJam(Loop *L, ScalarEvolution &SE, DominatorTree &DT,
   }
 
   // Check the loop safety info for exceptions.
-  SimpleLoopSafetyInfo LSI;
-  LSI.computeLoopSafetyInfo(L);
+  SimpleLoopSafetyInfo LSI(L);
+  LSI.computeLoopSafetyInfo();
   if (LSI.anyBlockMayThrow()) {
     LLVM_DEBUG(dbgs() << "Won't unroll-and-jam; Something may throw\n");
     return false;
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
index e05147ab7a3e5..cab3eded3e78a 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
@@ -1844,12 +1844,12 @@ bool LoopVectorizationLegality::canUncountableExitConditionLoadBeMoved(
     return false;
   }
 
-  ICFLoopSafetyInfo SafetyInfo;
-  SafetyInfo.computeLoopSafetyInfo(TheLoop);
+  ICFLoopSafetyInfo SafetyInfo(TheLoop);
+  SafetyInfo.computeLoopSafetyInfo();
   LoadInst *Load = cast<LoadInst>(L);
   // We need to know that load will be executed before we can hoist a
   // copy out to run just before the first iteration.
-  if (!SafetyInfo.isGuaranteedToExecute(*Load, DT, TheLoop)) {
+  if (!SafetyInfo.isGuaranteedToExecute(*Load, DT)) {
     reportVectorizationFailure(
         "Load for uncountable exit not guaranteed to execute",
         "ConditionalUncountableExitLoad", ORE, TheLoop);

>From 6162a4df359dc569bc05de7efea8c1927d598217 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Fri, 4 Sep 2026 16:47:24 +0200
Subject: [PATCH 2/3] Call computeLoopSafetyInfo() in the ctor

---
 llvm/include/llvm/Analysis/MustExecute.h      | 32 +++++++------------
 llvm/lib/Analysis/MustExecute.cpp             |  1 -
 llvm/lib/Transforms/Scalar/LICM.cpp           |  1 -
 .../Transforms/Scalar/LoopIdiomRecognize.cpp  |  1 -
 .../Transforms/Scalar/SimpleLoopUnswitch.cpp  |  2 --
 .../lib/Transforms/Utils/LoopUnrollAndJam.cpp |  1 -
 .../Vectorize/LoopVectorizationLegality.cpp   |  1 -
 7 files changed, 12 insertions(+), 27 deletions(-)

diff --git a/llvm/include/llvm/Analysis/MustExecute.h b/llvm/include/llvm/Analysis/MustExecute.h
index deb04738bcc5d..282e73778da3c 100644
--- a/llvm/include/llvm/Analysis/MustExecute.h
+++ b/llvm/include/llvm/Analysis/MustExecute.h
@@ -50,13 +50,8 @@ class raw_ostream;
 /// isGuaranteedToExecute below, but some callers bailout or fallback to
 /// alternate reasoning if a loop contains any implicit control flow.
 /// NOTE: LoopSafetyInfo contains cached information regarding loops and their
-/// particular blocks. This information is only dropped on invocation of
-/// computeLoopSafetyInfo. If the loop or any of its block is deleted, or if
-/// any thrower instructions have been added or removed from them, or if the
-/// control flow has changed, or in case of other meaningful modifications, the
-/// LoopSafetyInfo needs to be recomputed. If a meaningful modifications to the
-/// loop were made and the info wasn't recomputed properly, the behavior of all
-/// methods except for computeLoopSafetyInfo is undefined.
+/// particular blocks. Cached information may not be valid after control flow
+/// changes.
 class LoopSafetyInfo {
   // Used to update funclet bundle operands.
   DenseMap<BasicBlock *, ColorVector> BlockColors;
@@ -94,13 +89,6 @@ class LoopSafetyInfo {
   LLVM_ABI bool allLoopPathsLeadToBlockImpl(const BasicBlock *BB,
                                             const DominatorTree *DT) const;
 
-  /// Computes safety information for a loop checks loop body & header for
-  /// the possibility of may throw exception, it takes LoopSafetyInfo and loop
-  /// as argument. Updates safety information in LoopSafetyInfo argument.
-  /// Note: This is defined to clear and reinitialize an already initialized
-  /// LoopSafetyInfo.  Some callers rely on this fact.
-  virtual void computeLoopSafetyInfo() = 0;
-
   /// Returns true if the instruction in a loop is guaranteed to execute at
   /// least once (under the assumption that the loop is entered).
   virtual bool isGuaranteedToExecute(const Instruction &Inst,
@@ -120,15 +108,17 @@ class LLVM_ABI SimpleLoopSafetyInfo : public LoopSafetyInfo {
                                // may throw.
   bool HeaderMayThrow = false; // Same as previous, but specific to loop header
 
+  void computeLoopSafetyInfo();
+
 public:
-  SimpleLoopSafetyInfo(const Loop *L) : LoopSafetyInfo(L) {}
+  SimpleLoopSafetyInfo(const Loop *L) : LoopSafetyInfo(L) {
+    computeLoopSafetyInfo();
+  }
 
   bool blockMayThrow(const BasicBlock *BB) const override;
 
   bool anyBlockMayThrow() const override;
 
-  void computeLoopSafetyInfo() override;
-
   bool isGuaranteedToExecute(const Instruction &Inst,
                              const DominatorTree *DT) const override;
 };
@@ -146,15 +136,17 @@ class LLVM_ABI ICFLoopSafetyInfo : public LoopSafetyInfo {
   // Contains information about instruction that may possibly write memory.
   mutable MemoryWriteTracking MW;
 
+  void computeLoopSafetyInfo();
+
 public:
-  ICFLoopSafetyInfo(const Loop *L) : LoopSafetyInfo(L) {}
+  ICFLoopSafetyInfo(const Loop *L) : LoopSafetyInfo(L) {
+    computeLoopSafetyInfo();
+  }
 
   bool blockMayThrow(const BasicBlock *BB) const override;
 
   bool anyBlockMayThrow() const override;
 
-  void computeLoopSafetyInfo() override;
-
   bool isGuaranteedToExecute(const Instruction &Inst,
                              const DominatorTree *DT) const override;
 
diff --git a/llvm/lib/Analysis/MustExecute.cpp b/llvm/lib/Analysis/MustExecute.cpp
index 5bee66b70adcf..2462ef716dd52 100644
--- a/llvm/lib/Analysis/MustExecute.cpp
+++ b/llvm/lib/Analysis/MustExecute.cpp
@@ -325,7 +325,6 @@ static bool isMustExecuteIn(const Instruction &I, Loop *L, DominatorTree *DT) {
   // result obtained by *either* implementation.  This is a bit unfair since no
   // caller actually gets the full power at the moment.
   SimpleLoopSafetyInfo LSI(L);
-  LSI.computeLoopSafetyInfo();
   return LSI.isGuaranteedToExecute(I, DT) ||
          isGuaranteedToExecuteForEveryIteration(&I, L);
 }
diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp
index 27325546d57ec..bc12aca7c1086 100644
--- a/llvm/lib/Transforms/Scalar/LICM.cpp
+++ b/llvm/lib/Transforms/Scalar/LICM.cpp
@@ -461,7 +461,6 @@ bool LoopInvariantCodeMotion::runOnLoop(Loop *L, AAResults *AA, LoopInfo *LI,
 
   // Compute loop safety information.
   ICFLoopSafetyInfo SafetyInfo(L);
-  SafetyInfo.computeLoopSafetyInfo();
 
   // We want to visit all of the instructions in this loop... that are not parts
   // of our subloops (they have already had their invariants hoisted out of
diff --git a/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp b/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp
index ea82c3ca0ce1f..dbe114f7c220a 100644
--- a/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp
@@ -404,7 +404,6 @@ bool LoopIdiomRecognize::runOnCountableLoop() {
   // The following transforms hoist stores/memsets into the loop pre-header.
   // Give up if the loop has instructions that may throw.
   SimpleLoopSafetyInfo SafetyInfo(CurLoop);
-  SafetyInfo.computeLoopSafetyInfo();
   if (SafetyInfo.anyBlockMayThrow())
     return false;
 
diff --git a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
index 561ddb26b928d..f3cc417ee442e 100644
--- a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
+++ b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
@@ -2397,7 +2397,6 @@ static void unswitchNontrivialInvariants(
       // It is only legal to preserve make.implicit metadata if we are
       // guaranteed no reach implicit null check after following this branch.
       ICFLoopSafetyInfo SafetyInfo(&L);
-      SafetyInfo.computeLoopSafetyInfo();
       if (!SafetyInfo.isGuaranteedToExecute(TI, &DT))
         TI.setMetadata(LLVMContext::MD_make_implicit, nullptr);
     }
@@ -3556,7 +3555,6 @@ static bool shouldInsertFreeze(Loop &L, Instruction &TI, DominatorTree &DT,
     return false;
 
   ICFLoopSafetyInfo SafetyInfo(&L);
-  SafetyInfo.computeLoopSafetyInfo();
   if (SafetyInfo.isGuaranteedToExecute(TI, &DT))
     return false;
 
diff --git a/llvm/lib/Transforms/Utils/LoopUnrollAndJam.cpp b/llvm/lib/Transforms/Utils/LoopUnrollAndJam.cpp
index 5814399f79076..fe34d3ea58e6a 100644
--- a/llvm/lib/Transforms/Utils/LoopUnrollAndJam.cpp
+++ b/llvm/lib/Transforms/Utils/LoopUnrollAndJam.cpp
@@ -949,7 +949,6 @@ bool llvm::isSafeToUnrollAndJam(Loop *L, ScalarEvolution &SE, DominatorTree &DT,
 
   // Check the loop safety info for exceptions.
   SimpleLoopSafetyInfo LSI(L);
-  LSI.computeLoopSafetyInfo();
   if (LSI.anyBlockMayThrow()) {
     LLVM_DEBUG(dbgs() << "Won't unroll-and-jam; Something may throw\n");
     return false;
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
index cab3eded3e78a..0c080d9434ea8 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
@@ -1845,7 +1845,6 @@ bool LoopVectorizationLegality::canUncountableExitConditionLoadBeMoved(
   }
 
   ICFLoopSafetyInfo SafetyInfo(TheLoop);
-  SafetyInfo.computeLoopSafetyInfo();
   LoadInst *Load = cast<LoadInst>(L);
   // We need to know that load will be executed before we can hoist a
   // copy out to run just before the first iteration.

>From 4e10ba92ddbc89d9966e414788a2edf4a2af1abf Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Mon, 7 Sep 2026 10:36:04 +0200
Subject: [PATCH 3/3] review

---
 llvm/include/llvm/Analysis/MustExecute.h | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/llvm/include/llvm/Analysis/MustExecute.h b/llvm/include/llvm/Analysis/MustExecute.h
index 282e73778da3c..7e64d0622a62a 100644
--- a/llvm/include/llvm/Analysis/MustExecute.h
+++ b/llvm/include/llvm/Analysis/MustExecute.h
@@ -60,6 +60,9 @@ class LoopSafetyInfo {
   // loop is entered.
   mutable DenseMap<const BasicBlock *, bool> GuaranteedToExecute;
 
+  bool allLoopPathsLeadToBlockImpl(const BasicBlock *BB,
+                                   const DominatorTree *DT) const;
+
 protected:
   const Loop *CurLoop;
 
@@ -86,9 +89,6 @@ class LoopSafetyInfo {
   LLVM_ABI bool allLoopPathsLeadToBlock(const BasicBlock *BB,
                                         const DominatorTree *DT) const;
 
-  LLVM_ABI bool allLoopPathsLeadToBlockImpl(const BasicBlock *BB,
-                                            const DominatorTree *DT) const;
-
   /// Returns true if the instruction in a loop is guaranteed to execute at
   /// least once (under the assumption that the loop is entered).
   virtual bool isGuaranteedToExecute(const Instruction &Inst,
@@ -111,7 +111,7 @@ class LLVM_ABI SimpleLoopSafetyInfo : public LoopSafetyInfo {
   void computeLoopSafetyInfo();
 
 public:
-  SimpleLoopSafetyInfo(const Loop *L) : LoopSafetyInfo(L) {
+  explicit SimpleLoopSafetyInfo(const Loop *L) : LoopSafetyInfo(L) {
     computeLoopSafetyInfo();
   }
 
@@ -139,7 +139,7 @@ class LLVM_ABI ICFLoopSafetyInfo : public LoopSafetyInfo {
   void computeLoopSafetyInfo();
 
 public:
-  ICFLoopSafetyInfo(const Loop *L) : LoopSafetyInfo(L) {
+  explicit ICFLoopSafetyInfo(const Loop *L) : LoopSafetyInfo(L) {
     computeLoopSafetyInfo();
   }
 
@@ -155,7 +155,7 @@ class LLVM_ABI ICFLoopSafetyInfo : public LoopSafetyInfo {
   bool doesNotWriteMemoryBefore(const BasicBlock *BB) const;
 
   /// Returns true if we could not execute a memory-modifying instruction before
-  /// we execute \p I under assumption that the loopis entered.
+  /// we execute \p I under assumption that the loop is entered.
   bool doesNotWriteMemoryBefore(const Instruction &I) const;
 
   /// Inform the safety info that we are planning to insert a new instruction



More information about the llvm-commits mailing list