-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[LICM] Sink unused l-invariant loads in preheader. #157559
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 9 commits
63d81f0
61ad654
68667db
905434c
26d7e99
7c01671
fe37acb
90404be
c0ba9e9
bd26a88
c5601ff
9a7c53b
b0a8eae
5b345e1
5f1fd21
7f8e279
43c1fc6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -213,6 +213,10 @@ static void moveInstructionBefore(Instruction &I, BasicBlock::iterator Dest, | |
| ICFLoopSafetyInfo &SafetyInfo, | ||
| MemorySSAUpdater &MSSAU, ScalarEvolution *SE); | ||
|
|
||
| static bool sinkUnusedInvariantsFromPreheaderToExit( | ||
| Loop *L, AAResults *AA, ICFLoopSafetyInfo *SafetyInfo, | ||
| MemorySSAUpdater &MSSAU, ScalarEvolution *SE); | ||
|
|
||
| static void foreachMemoryAccess(MemorySSA *MSSA, Loop *L, | ||
| function_ref<void(Instruction *)> Fn); | ||
| using PointersAndHasReadsOutsideSet = | ||
|
|
@@ -546,6 +550,12 @@ bool LoopInvariantCodeMotion::runOnLoop(Loop *L, AAResults *AA, LoopInfo *LI, | |
|
|
||
| if (Changed && SE) | ||
| SE->forgetLoopDispositions(); | ||
|
|
||
| // sink pre-header defs that are unused in-loop into the unique exit to reduce | ||
| // pressure. | ||
| Changed |= | ||
| sinkUnusedInvariantsFromPreheaderToExit(L, AA, &SafetyInfo, MSSAU, SE); | ||
|
||
|
|
||
| return Changed; | ||
| } | ||
|
|
||
|
|
@@ -1469,6 +1479,104 @@ 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) { | ||
| BasicBlock *ExitBlock = L->getExitBlock(); | ||
| if (!ExitBlock) | ||
| return false; | ||
|
|
||
| BasicBlock *Preheader = L->getLoopPreheader(); | ||
| if (!Preheader) | ||
| return false; | ||
|
|
||
| bool MadeAnyChanges = false; | ||
|
|
||
| for (Instruction &I : llvm::make_early_inc_range(llvm::reverse(*Preheader))) { | ||
VigneshwarJ marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| // Skip terminator. | ||
| if (Preheader->getTerminator() == &I) | ||
| 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; | ||
|
|
||
| // Don't sink reads unless MemorySSA says the location is not clobbered | ||
| // within the loop. | ||
| if (I.mayReadFromMemory()) { | ||
| auto *LI = dyn_cast<LoadInst>(&I); | ||
| // Only handle loads here; be conservative for other memory-reading ops. | ||
| if (!LI) | ||
| continue; | ||
| // Do not move volatile or ordered/atomic loads. | ||
| if (!LI->isUnordered() || LI->isAtomic()) | ||
| continue; | ||
|
|
||
| MemorySSA *MSSA = MSSAU.getMemorySSA(); | ||
| auto *MU = dyn_cast_or_null<MemoryUse>(MSSA->getMemoryAccess(LI)); | ||
| if (!MU) | ||
| // Conservatively skip if MSSA has no use for this load. | ||
| continue; | ||
|
|
||
| SinkAndHoistLICMFlags Flags(SetLicmMssaOptCap, | ||
| SetLicmMssaNoAccForPromotionCap, | ||
| /*IsSink=*/true, *L, *MSSA); | ||
| bool InvariantGroup = LI->hasMetadata(LLVMContext::MD_invariant_group); | ||
|
|
||
| // If the pointer could be invalidated in the loop, do not sink. | ||
| if (pointerInvalidatedByLoop(MSSA, MU, L, I, Flags, InvariantGroup)) | ||
| continue; | ||
| } | ||
|
|
||
| // Skip debug/pseudo and EH pad. | ||
| if (I.isDebugOrPseudoInst() || I.isEHPad()) | ||
| continue; | ||
|
|
||
| // Don't sink alloca: we never want to sink static alloca's out of the | ||
| // entry block, and correctly sinking dynamic alloca's requires | ||
| // checks for stacksave/stackrestore intrinsics. | ||
| // FIXME: Refactor this check somehow? | ||
| if (isa<AllocaInst>(&I)) | ||
| continue; | ||
|
|
||
| // Determine if there is a use in or before the loop (direct or | ||
| // otherwise). | ||
| bool UsedInLoopOrPreheader = false; | ||
| for (Use &U : I.uses()) { | ||
| auto *UserI = cast<Instruction>(U.getUser()); | ||
| BasicBlock *UseBB = UserI->getParent(); | ||
| if (auto *PN = dyn_cast<PHINode>(UserI)) { | ||
| unsigned OpIdx = | ||
| PHINode::getIncomingValueNumForOperand(U.getOperandNo()); | ||
| UseBB = PN->getIncomingBlock(OpIdx); | ||
|
||
| } | ||
| if (UseBB == Preheader || L->contains(UseBB)) { | ||
| UsedInLoopOrPreheader = true; | ||
| break; | ||
| } | ||
| } | ||
| if (UsedInLoopOrPreheader) | ||
| continue; | ||
|
|
||
| moveInstructionBefore(I, ExitBlock->getFirstInsertionPt(), *SafetyInfo, | ||
| MSSAU, SE); | ||
| MadeAnyChanges = true; | ||
| } | ||
|
|
||
| return MadeAnyChanges; | ||
| } | ||
|
|
||
| static Instruction *sinkThroughTriviallyReplaceablePHI( | ||
| PHINode *TPN, Instruction *I, LoopInfo *LI, | ||
| SmallDenseMap<BasicBlock *, Instruction *, 32> &SunkCopies, | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.