[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