[llvm] Reland "[LICM] Sink unused l-invariant loads in preheader #157559" (PR #170204)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 16 01:37:57 PDT 2026


================
@@ -1560,6 +1572,181 @@ static void moveInstructionBefore(Instruction &I, BasicBlock::iterator Dest,
     SE->forgetBlockAndLoopDispositions(&I);
 }
 
+// If there's a single exit block, sink any loop-invariant values that were
+// defined in the preheader but not used inside the loop into the exit block
+// to reduce register pressure in the loop.
+static bool sinkUnusedInvariantsFromPreheaderToExit(
+    Loop *L, AAResults *AA, ICFLoopSafetyInfo *SafetyInfo,
+    MemorySSAUpdater &MSSAU, ScalarEvolution *SE, DominatorTree *DT,
+    SinkAndHoistLICMFlags &SinkFlags) {
+  BasicBlock *ExitBlock = L->getExitBlock();
+  if (!ExitBlock)
+    return false;
+
+  BasicBlock *Preheader = L->getLoopPreheader();
+  if (!Preheader)
+    return false;
+
+  // Collect instructions that are safe to sink and have no in-loop users.
+  SmallPtrSet<Instruction *, 16> LegalToSink;
+  for (Instruction &I : llvm::reverse(*Preheader)) {
+    if (I.isTerminator())
+      continue;
+
+    // New instructions were inserted at the end of the preheader.
+    if (isa<PHINode>(I))
+      break;
+
+    // Don't move instructions which might have side effects, since the side
+    // effects need to complete before instructions inside the loop. Note that
+    // it's okay if the instruction might have undefined behavior: LoopSimplify
+    // guarantees that the preheader dominates the exit block.
+    if (I.mayHaveSideEffects())
+      continue;
+
+    if (!canSinkOrHoistInst(I, AA, DT, L, MSSAU, true, SinkFlags, nullptr))
+      continue;
+
+    bool UsedInLoop = llvm::any_of(I.uses(), [L](Use &U) {
+      auto *UserI = cast<Instruction>(U.getUser());
+      BasicBlock *UseBB = UserI->getParent();
+      if (auto *PN = dyn_cast<PHINode>(UserI))
+        UseBB = PN->getIncomingBlock(U);
+      return L->contains(UseBB);
+    });
+    if (UsedInLoop)
+      continue;
+
+    LegalToSink.insert(&I);
+  }
+
+  if (LegalToSink.empty())
+    return false;
+
+  // Remove candidates that have a preheader user which is not itself a
+  // candidate, since that user keeps the definition live in the preheader.
+  // Iterate until stable to handle chains.
----------------
nikic wrote:

Why does this need a separate fixpoint iteration loop? Can't this be done as part of the previous one? We already go backwards through the block and inspect all users. Why can't we add a check there that there is no preheader user (that is not part of the partially built candidate set)?

https://github.com/llvm/llvm-project/pull/170204


More information about the llvm-commits mailing list