[llvm] [LoopSafetyInfo] Compute block colors lazily (NFC) (PR #221954)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 8 03:49:34 PDT 2026


https://github.com/nikic created https://github.com/llvm/llvm-project/pull/221954

Computing the block colors is fairly expensive, but only rarely actually needed. We can delay computation to first use.

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

>From 362379a2beb6851e7cb330f1298d9f25196fe998 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Tue, 8 Sep 2026 12:45:40 +0200
Subject: [PATCH] [LoopSafetyInfo] Compute block colors lazily (NFC)

Computing the block colors is fairly expensive, but only rarely
actually needed. We can delay computation to first use.
---
 llvm/include/llvm/Analysis/MustExecute.h |  8 ++++----
 llvm/lib/Analysis/MustExecute.cpp        | 20 +++++++++++++-------
 llvm/lib/Transforms/Scalar/LICM.cpp      |  5 +++--
 3 files changed, 20 insertions(+), 13 deletions(-)

diff --git a/llvm/include/llvm/Analysis/MustExecute.h b/llvm/include/llvm/Analysis/MustExecute.h
index 7e64d0622a62a..d22c3fc1dfb15 100644
--- a/llvm/include/llvm/Analysis/MustExecute.h
+++ b/llvm/include/llvm/Analysis/MustExecute.h
@@ -54,7 +54,7 @@ class raw_ostream;
 /// changes.
 class LoopSafetyInfo {
   // Used to update funclet bundle operands.
-  DenseMap<BasicBlock *, ColorVector> BlockColors;
+  mutable std::optional<DenseMap<BasicBlock *, ColorVector>> BlockColors;
 
   // Cache whether (the start of) this block is guaranteed to execute if the
   // loop is entered.
@@ -63,12 +63,12 @@ class LoopSafetyInfo {
   bool allLoopPathsLeadToBlockImpl(const BasicBlock *BB,
                                    const DominatorTree *DT) const;
 
+  /// Computes block colors.
+  void computeBlockColors() const;
+
 protected:
   const Loop *CurLoop;
 
-  /// Computes block colors.
-  LLVM_ABI void computeBlockColors();
-
 public:
   /// Returns block colors map that is used to update funclet operand bundles.
   LLVM_ABI const DenseMap<BasicBlock *, ColorVector> &getBlockColors() const;
diff --git a/llvm/lib/Analysis/MustExecute.cpp b/llvm/lib/Analysis/MustExecute.cpp
index 2462ef716dd52..463477ce4aef1 100644
--- a/llvm/lib/Analysis/MustExecute.cpp
+++ b/llvm/lib/Analysis/MustExecute.cpp
@@ -28,12 +28,17 @@ using namespace llvm;
 
 const DenseMap<BasicBlock *, ColorVector> &
 LoopSafetyInfo::getBlockColors() const {
-  return BlockColors;
+  computeBlockColors();
+  return *BlockColors;
 }
 
 void LoopSafetyInfo::copyColors(BasicBlock *New, BasicBlock *Old) {
-  ColorVector &ColorsForNewBlock = BlockColors[New];
-  ColorVector &ColorsForOldBlock = BlockColors[Old];
+  // Nothing to update if colors have not been computed yet.
+  if (!BlockColors)
+    return;
+
+  ColorVector &ColorsForNewBlock = (*BlockColors)[New];
+  ColorVector &ColorsForOldBlock = (*BlockColors)[Old];
   ColorsForNewBlock = ColorsForOldBlock;
 }
 
@@ -62,8 +67,6 @@ void SimpleLoopSafetyInfo::computeLoopSafetyInfo() {
     if (MayThrow)
       break;
   }
-
-  computeBlockColors();
 }
 
 bool ICFLoopSafetyInfo::blockMayThrow(const BasicBlock *BB) const {
@@ -85,7 +88,6 @@ void ICFLoopSafetyInfo::computeLoopSafetyInfo() {
       MayThrow = true;
       break;
     }
-  computeBlockColors();
 }
 
 void ICFLoopSafetyInfo::insertInstructionTo(const Instruction *Inst,
@@ -99,7 +101,11 @@ void ICFLoopSafetyInfo::removeInstruction(const Instruction *Inst) {
   MW.removeInstruction(Inst);
 }
 
-void LoopSafetyInfo::computeBlockColors() {
+void LoopSafetyInfo::computeBlockColors() const {
+  if (BlockColors)
+    return;
+  BlockColors.emplace();
+
   // Compute funclet colors if we might sink/hoist in a function with a funclet
   // personality routine.
   Function *Fn = CurLoop->getHeader()->getParent();
diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp
index bc12aca7c1086..e4bcad4ac731d 100644
--- a/llvm/lib/Transforms/Scalar/LICM.cpp
+++ b/llvm/lib/Transforms/Scalar/LICM.cpp
@@ -1427,7 +1427,6 @@ static bool isNotUsedOrFoldableInLoop(const Instruction &I, const Loop *CurLoop,
                                       const LoopSafetyInfo *SafetyInfo,
                                       TargetTransformInfo *TTI,
                                       bool &FoldableInLoop, bool LoopNestMode) {
-  const auto &BlockColors = SafetyInfo->getBlockColors();
   bool IsFoldable = isFoldableInLoop(I, CurLoop, TTI);
   for (const User *U : I.users()) {
     const Instruction *UI = cast<Instruction>(U);
@@ -1439,10 +1438,12 @@ static bool isNotUsedOrFoldableInLoop(const Instruction &I, const Loop *CurLoop,
 
       // We need to sink a callsite to a unique funclet.  Avoid sinking if the
       // phi use is too muddled.
-      if (isa<CallInst>(I))
+      if (isa<CallInst>(I)) {
+        const auto &BlockColors = SafetyInfo->getBlockColors();
         if (!BlockColors.empty() &&
             BlockColors.find(const_cast<BasicBlock *>(BB))->second.size() != 1)
           return false;
+      }
 
       if (LoopNestMode) {
         while (isa<PHINode>(UI) && UI->hasOneUser() &&



More information about the llvm-commits mailing list