[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