diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:12 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:12 +0000 |
commit | e6d1592492a3a379186bfb02bd0f4eda0669c0d5 (patch) | |
tree | 599ab169a01f1c86eda9adc774edaedde2f2db5b /lib/Transforms/Scalar/LoopSimplifyCFG.cpp | |
parent | 1a56a5ead7a2e84bee8240f5f6b033b5f1707154 (diff) |
Diffstat (limited to 'lib/Transforms/Scalar/LoopSimplifyCFG.cpp')
-rw-r--r-- | lib/Transforms/Scalar/LoopSimplifyCFG.cpp | 237 |
1 files changed, 167 insertions, 70 deletions
diff --git a/lib/Transforms/Scalar/LoopSimplifyCFG.cpp b/lib/Transforms/Scalar/LoopSimplifyCFG.cpp index 2e5927f9a068..046f4c8af492 100644 --- a/lib/Transforms/Scalar/LoopSimplifyCFG.cpp +++ b/lib/Transforms/Scalar/LoopSimplifyCFG.cpp @@ -1,9 +1,8 @@ //===--------- LoopSimplifyCFG.cpp - Loop CFG Simplification Pass ---------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -21,6 +20,7 @@ #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/BasicAliasAnalysis.h" #include "llvm/Analysis/DependenceAnalysis.h" +#include "llvm/Analysis/DomTreeUpdater.h" #include "llvm/Analysis/GlobalsModRef.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/LoopPass.h" @@ -29,7 +29,6 @@ #include "llvm/Analysis/ScalarEvolution.h" #include "llvm/Analysis/ScalarEvolutionAliasAnalysis.h" #include "llvm/Analysis/TargetTransformInfo.h" -#include "llvm/IR/DomTreeUpdater.h" #include "llvm/IR/Dominators.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Scalar/LoopPassManager.h" @@ -42,7 +41,7 @@ using namespace llvm; #define DEBUG_TYPE "loop-simplifycfg" static cl::opt<bool> EnableTermFolding("enable-loop-simplifycfg-term-folding", - cl::init(false)); + cl::init(true)); STATISTIC(NumTerminatorsFolded, "Number of terminators folded to unconditional branches"); @@ -80,6 +79,36 @@ static BasicBlock *getOnlyLiveSuccessor(BasicBlock *BB) { return nullptr; } +/// Removes \p BB from all loops from [FirstLoop, LastLoop) in parent chain. +static void removeBlockFromLoops(BasicBlock *BB, Loop *FirstLoop, + Loop *LastLoop = nullptr) { + assert((!LastLoop || LastLoop->contains(FirstLoop->getHeader())) && + "First loop is supposed to be inside of last loop!"); + assert(FirstLoop->contains(BB) && "Must be a loop block!"); + for (Loop *Current = FirstLoop; Current != LastLoop; + Current = Current->getParentLoop()) + Current->removeBlockFromLoop(BB); +} + +/// Find innermost loop that contains at least one block from \p BBs and +/// contains the header of loop \p L. +static Loop *getInnermostLoopFor(SmallPtrSetImpl<BasicBlock *> &BBs, + Loop &L, LoopInfo &LI) { + Loop *Innermost = nullptr; + for (BasicBlock *BB : BBs) { + Loop *BBL = LI.getLoopFor(BB); + while (BBL && !BBL->contains(L.getHeader())) + BBL = BBL->getParentLoop(); + if (BBL == &L) + BBL = BBL->getParentLoop(); + if (!BBL) + continue; + if (!Innermost || BBL->getLoopDepth() > Innermost->getLoopDepth()) + Innermost = BBL; + } + return Innermost; +} + namespace { /// Helper class that can turn branches and switches with constant conditions /// into unconditional branches. @@ -90,6 +119,9 @@ private: DominatorTree &DT; ScalarEvolution &SE; MemorySSAUpdater *MSSAU; + LoopBlocksDFS DFS; + DomTreeUpdater DTU; + SmallVector<DominatorTree::UpdateType, 16> DTUpdates; // Whether or not the current loop has irreducible CFG. bool HasIrreducibleCFG = false; @@ -175,7 +207,6 @@ private: /// Fill all information about status of blocks and exits of the current loop /// if constant folding of all branches will be done. void analyze() { - LoopBlocksDFS DFS(&L); DFS.perform(&LI); assert(DFS.isComplete() && "DFS is expected to be finished"); @@ -208,12 +239,13 @@ private: // folding. Only handle blocks from current loop: branches in child loops // are skipped because if they can be folded, they should be folded during // the processing of child loops. - if (TheOnlySucc && LI.getLoopFor(BB) == &L) + bool TakeFoldCandidate = TheOnlySucc && LI.getLoopFor(BB) == &L; + if (TakeFoldCandidate) FoldCandidates.push_back(BB); // Handle successors. for (BasicBlock *Succ : successors(BB)) - if (!TheOnlySucc || TheOnlySucc == Succ) { + if (!TakeFoldCandidate || TheOnlySucc == Succ) { if (L.contains(Succ)) LiveLoopBlocks.insert(Succ); else @@ -229,8 +261,10 @@ private: // Now, all exit blocks that are not marked as live are dead. SmallVector<BasicBlock *, 8> ExitBlocks; L.getExitBlocks(ExitBlocks); + SmallPtrSet<BasicBlock *, 8> UniqueDeadExits; for (auto *ExitBlock : ExitBlocks) - if (!LiveExitBlocks.count(ExitBlock)) + if (!LiveExitBlocks.count(ExitBlock) && + UniqueDeadExits.insert(ExitBlock).second) DeadExitBlocks.push_back(ExitBlock); // Whether or not the edge From->To will still be present in graph after the @@ -239,7 +273,7 @@ private: if (!LiveLoopBlocks.count(From)) return false; BasicBlock *TheOnlySucc = getOnlyLiveSuccessor(From); - return !TheOnlySucc || TheOnlySucc == To; + return !TheOnlySucc || TheOnlySucc == To || LI.getLoopFor(From) != &L; }; // The loop will not be destroyed if its latch is live. @@ -317,14 +351,10 @@ private: // Construct split preheader and the dummy switch to thread edges from it to // dead exits. - DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager); BasicBlock *Preheader = L.getLoopPreheader(); - BasicBlock *NewPreheader = Preheader->splitBasicBlock( - Preheader->getTerminator(), - Twine(Preheader->getName()).concat("-split")); - DTU.deleteEdge(Preheader, L.getHeader()); - DTU.insertEdge(NewPreheader, L.getHeader()); - DTU.insertEdge(Preheader, NewPreheader); + BasicBlock *NewPreheader = llvm::SplitBlock( + Preheader, Preheader->getTerminator(), &DT, &LI, MSSAU); + IRBuilder<> Builder(Preheader->getTerminator()); SwitchInst *DummySwitch = Builder.CreateSwitch(Builder.getInt32(0), NewPreheader); @@ -343,75 +373,106 @@ private: } assert(DummyIdx != 0 && "Too many dead exits!"); DummySwitch->addCase(Builder.getInt32(DummyIdx++), BB); - DTU.insertEdge(Preheader, BB); + DTUpdates.push_back({DominatorTree::Insert, Preheader, BB}); ++NumLoopExitsDeleted; } assert(L.getLoopPreheader() == NewPreheader && "Malformed CFG?"); if (Loop *OuterLoop = LI.getLoopFor(Preheader)) { - OuterLoop->addBasicBlockToLoop(NewPreheader, LI); - // When we break dead edges, the outer loop may become unreachable from // the current loop. We need to fix loop info accordingly. For this, we // find the most nested loop that still contains L and remove L from all // loops that are inside of it. - Loop *StillReachable = nullptr; - for (BasicBlock *BB : LiveExitBlocks) { - Loop *BBL = LI.getLoopFor(BB); - if (BBL && BBL->contains(L.getHeader())) - if (!StillReachable || - BBL->getLoopDepth() > StillReachable->getLoopDepth()) - StillReachable = BBL; - } + Loop *StillReachable = getInnermostLoopFor(LiveExitBlocks, L, LI); // Okay, our loop is no longer in the outer loop (and maybe not in some of // its parents as well). Make the fixup. if (StillReachable != OuterLoop) { LI.changeLoopFor(NewPreheader, StillReachable); - for (Loop *NotContaining = OuterLoop; NotContaining != StillReachable; - NotContaining = NotContaining->getParentLoop()) { - NotContaining->removeBlockFromLoop(NewPreheader); - for (auto *BB : L.blocks()) - NotContaining->removeBlockFromLoop(BB); - } + removeBlockFromLoops(NewPreheader, OuterLoop, StillReachable); + for (auto *BB : L.blocks()) + removeBlockFromLoops(BB, OuterLoop, StillReachable); OuterLoop->removeChildLoop(&L); if (StillReachable) StillReachable->addChildLoop(&L); else LI.addTopLevelLoop(&L); + + // Some values from loops in [OuterLoop, StillReachable) could be used + // in the current loop. Now it is not their child anymore, so such uses + // require LCSSA Phis. + Loop *FixLCSSALoop = OuterLoop; + while (FixLCSSALoop->getParentLoop() != StillReachable) + FixLCSSALoop = FixLCSSALoop->getParentLoop(); + assert(FixLCSSALoop && "Should be a loop!"); + // We need all DT updates to be done before forming LCSSA. + DTU.applyUpdates(DTUpdates); + if (MSSAU) + MSSAU->applyUpdates(DTUpdates, DT); + DTUpdates.clear(); + formLCSSARecursively(*FixLCSSALoop, DT, &LI, &SE); } } + + if (MSSAU) { + // Clear all updates now. Facilitates deletes that follow. + DTU.applyUpdates(DTUpdates); + MSSAU->applyUpdates(DTUpdates, DT); + DTUpdates.clear(); + if (VerifyMemorySSA) + MSSAU->getMemorySSA()->verifyMemorySSA(); + } } /// Delete loop blocks that have become unreachable after folding. Make all /// relevant updates to DT and LI. void deleteDeadLoopBlocks() { - DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager); if (MSSAU) { - SmallPtrSet<BasicBlock *, 8> DeadLoopBlocksSet(DeadLoopBlocks.begin(), - DeadLoopBlocks.end()); + SmallSetVector<BasicBlock *, 8> DeadLoopBlocksSet(DeadLoopBlocks.begin(), + DeadLoopBlocks.end()); MSSAU->removeBlocks(DeadLoopBlocksSet); } + + // The function LI.erase has some invariants that need to be preserved when + // it tries to remove a loop which is not the top-level loop. In particular, + // it requires loop's preheader to be strictly in loop's parent. We cannot + // just remove blocks one by one, because after removal of preheader we may + // break this invariant for the dead loop. So we detatch and erase all dead + // loops beforehand. + for (auto *BB : DeadLoopBlocks) + if (LI.isLoopHeader(BB)) { + assert(LI.getLoopFor(BB) != &L && "Attempt to remove current loop!"); + Loop *DL = LI.getLoopFor(BB); + if (DL->getParentLoop()) { + for (auto *PL = DL->getParentLoop(); PL; PL = PL->getParentLoop()) + for (auto *BB : DL->getBlocks()) + PL->removeBlockFromLoop(BB); + DL->getParentLoop()->removeChildLoop(DL); + LI.addTopLevelLoop(DL); + } + LI.erase(DL); + } + for (auto *BB : DeadLoopBlocks) { assert(BB != L.getHeader() && "Header of the current loop cannot be dead!"); LLVM_DEBUG(dbgs() << "Deleting dead loop block " << BB->getName() << "\n"); - if (LI.isLoopHeader(BB)) { - assert(LI.getLoopFor(BB) != &L && "Attempt to remove current loop!"); - LI.erase(LI.getLoopFor(BB)); - } LI.removeBlock(BB); - DeleteDeadBlock(BB, &DTU); - ++NumLoopBlocksDeleted; } + + DetatchDeadBlocks(DeadLoopBlocks, &DTUpdates, /*KeepOneInputPHIs*/true); + DTU.applyUpdates(DTUpdates); + DTUpdates.clear(); + for (auto *BB : DeadLoopBlocks) + DTU.deleteBB(BB); + + NumLoopBlocksDeleted += DeadLoopBlocks.size(); } /// Constant-fold terminators of blocks acculumated in FoldCandidates into the /// unconditional branches. void foldTerminators() { - DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager); - for (BasicBlock *BB : FoldCandidates) { assert(LI.getLoopFor(BB) == &L && "Should be a loop block!"); BasicBlock *TheOnlySucc = getOnlyLiveSuccessor(BB); @@ -453,7 +514,7 @@ private: Term->eraseFromParent(); for (auto *DeadSucc : DeadSuccessors) - DTU.deleteEdge(BB, DeadSucc); + DTUpdates.push_back({DominatorTree::Delete, BB, DeadSucc}); ++NumTerminatorsFolded; } @@ -463,15 +524,18 @@ public: ConstantTerminatorFoldingImpl(Loop &L, LoopInfo &LI, DominatorTree &DT, ScalarEvolution &SE, MemorySSAUpdater *MSSAU) - : L(L), LI(LI), DT(DT), SE(SE), MSSAU(MSSAU) {} + : L(L), LI(LI), DT(DT), SE(SE), MSSAU(MSSAU), DFS(&L), + DTU(DT, DomTreeUpdater::UpdateStrategy::Eager) {} bool run() { assert(L.getLoopLatch() && "Should be single latch!"); // Collect all available information about status of blocks after constant // folding. analyze(); + BasicBlock *Header = L.getHeader(); + (void)Header; - LLVM_DEBUG(dbgs() << "In function " << L.getHeader()->getParent()->getName() + LLVM_DEBUG(dbgs() << "In function " << Header->getParent()->getName() << ": "); if (HasIrreducibleCFG) { @@ -483,7 +547,7 @@ public: if (FoldCandidates.empty()) { LLVM_DEBUG( dbgs() << "No constant terminator folding candidates found in loop " - << L.getHeader()->getName() << "\n"); + << Header->getName() << "\n"); return false; } @@ -491,8 +555,7 @@ public: if (DeleteCurrentLoop) { LLVM_DEBUG( dbgs() - << "Give up constant terminator folding in loop " - << L.getHeader()->getName() + << "Give up constant terminator folding in loop " << Header->getName() << ": we don't currently support deletion of the current loop.\n"); return false; } @@ -503,8 +566,7 @@ public: L.getNumBlocks()) { LLVM_DEBUG( dbgs() << "Give up constant terminator folding in loop " - << L.getHeader()->getName() - << ": we don't currently" + << Header->getName() << ": we don't currently" " support blocks that are not dead, but will stop " "being a part of the loop after constant-folding.\n"); return false; @@ -515,8 +577,7 @@ public: LLVM_DEBUG(dump()); LLVM_DEBUG(dbgs() << "Constant-folding " << FoldCandidates.size() - << " terminators in loop " << L.getHeader()->getName() - << "\n"); + << " terminators in loop " << Header->getName() << "\n"); // Make the actual transforms. handleDeadExits(); @@ -524,20 +585,36 @@ public: if (!DeadLoopBlocks.empty()) { LLVM_DEBUG(dbgs() << "Deleting " << DeadLoopBlocks.size() - << " dead blocks in loop " << L.getHeader()->getName() - << "\n"); + << " dead blocks in loop " << Header->getName() << "\n"); deleteDeadLoopBlocks(); + } else { + // If we didn't do updates inside deleteDeadLoopBlocks, do them here. + DTU.applyUpdates(DTUpdates); + DTUpdates.clear(); } + if (MSSAU && VerifyMemorySSA) + MSSAU->getMemorySSA()->verifyMemorySSA(); + #ifndef NDEBUG // Make sure that we have preserved all data structures after the transform. - DT.verify(); - assert(DT.isReachableFromEntry(L.getHeader())); +#if defined(EXPENSIVE_CHECKS) + assert(DT.verify(DominatorTree::VerificationLevel::Full) && + "DT broken after transform!"); +#else + assert(DT.verify(DominatorTree::VerificationLevel::Fast) && + "DT broken after transform!"); +#endif + assert(DT.isReachableFromEntry(Header)); LI.verify(DT); #endif return true; } + + bool foldingBreaksCurrentLoop() const { + return DeleteCurrentLoop; + } }; } // namespace @@ -545,7 +622,8 @@ public: /// branches. static bool constantFoldTerminators(Loop &L, DominatorTree &DT, LoopInfo &LI, ScalarEvolution &SE, - MemorySSAUpdater *MSSAU) { + MemorySSAUpdater *MSSAU, + bool &IsLoopDeleted) { if (!EnableTermFolding) return false; @@ -555,7 +633,9 @@ static bool constantFoldTerminators(Loop &L, DominatorTree &DT, LoopInfo &LI, return false; ConstantTerminatorFoldingImpl BranchFolder(L, LI, DT, SE, MSSAU); - return BranchFolder.run(); + bool Changed = BranchFolder.run(); + IsLoopDeleted = Changed && BranchFolder.foldingBreaksCurrentLoop(); + return Changed; } static bool mergeBlocksIntoPredecessors(Loop &L, DominatorTree &DT, @@ -587,11 +667,15 @@ static bool mergeBlocksIntoPredecessors(Loop &L, DominatorTree &DT, } static bool simplifyLoopCFG(Loop &L, DominatorTree &DT, LoopInfo &LI, - ScalarEvolution &SE, MemorySSAUpdater *MSSAU) { + ScalarEvolution &SE, MemorySSAUpdater *MSSAU, + bool &isLoopDeleted) { bool Changed = false; // Constant-fold terminators with known constant conditions. - Changed |= constantFoldTerminators(L, DT, LI, SE, MSSAU); + Changed |= constantFoldTerminators(L, DT, LI, SE, MSSAU, isLoopDeleted); + + if (isLoopDeleted) + return true; // Eliminate unconditional branches by merging blocks into their predecessors. Changed |= mergeBlocksIntoPredecessors(L, DT, LI, MSSAU); @@ -604,15 +688,23 @@ static bool simplifyLoopCFG(Loop &L, DominatorTree &DT, LoopInfo &LI, PreservedAnalyses LoopSimplifyCFGPass::run(Loop &L, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR, - LPMUpdater &) { + LPMUpdater &LPMU) { Optional<MemorySSAUpdater> MSSAU; if (EnableMSSALoopDependency && AR.MSSA) MSSAU = MemorySSAUpdater(AR.MSSA); + bool DeleteCurrentLoop = false; if (!simplifyLoopCFG(L, AR.DT, AR.LI, AR.SE, - MSSAU.hasValue() ? MSSAU.getPointer() : nullptr)) + MSSAU.hasValue() ? MSSAU.getPointer() : nullptr, + DeleteCurrentLoop)) return PreservedAnalyses::all(); - return getLoopPassPreservedAnalyses(); + if (DeleteCurrentLoop) + LPMU.markLoopAsDeleted(L, "loop-simplifycfg"); + + auto PA = getLoopPassPreservedAnalyses(); + if (EnableMSSALoopDependency) + PA.preserve<MemorySSAAnalysis>(); + return PA; } namespace { @@ -623,7 +715,7 @@ public: initializeLoopSimplifyCFGLegacyPassPass(*PassRegistry::getPassRegistry()); } - bool runOnLoop(Loop *L, LPPassManager &) override { + bool runOnLoop(Loop *L, LPPassManager &LPM) override { if (skipLoop(L)) return false; @@ -637,8 +729,13 @@ public: if (VerifyMemorySSA) MSSA->verifyMemorySSA(); } - return simplifyLoopCFG(*L, DT, LI, SE, - MSSAU.hasValue() ? MSSAU.getPointer() : nullptr); + bool DeleteCurrentLoop = false; + bool Changed = simplifyLoopCFG( + *L, DT, LI, SE, MSSAU.hasValue() ? MSSAU.getPointer() : nullptr, + DeleteCurrentLoop); + if (DeleteCurrentLoop) + LPM.markLoopAsDeleted(*L); + return Changed; } void getAnalysisUsage(AnalysisUsage &AU) const override { |