xref: /src/contrib/llvm-project/llvm/lib/Transforms/IPO/LoopExtractor.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1009b1c42SEd Schouten //===- LoopExtractor.cpp - Extract each loop into a new function ----------===//
2009b1c42SEd Schouten //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6009b1c42SEd Schouten //
7009b1c42SEd Schouten //===----------------------------------------------------------------------===//
8009b1c42SEd Schouten //
9009b1c42SEd Schouten // A pass wrapper around the ExtractLoop() scalar transformation to extract each
10009b1c42SEd Schouten // top-level loop into its own new function. If the loop is the ONLY loop in a
11009b1c42SEd Schouten // given function, it is not touched. This is a pass most useful for debugging
12009b1c42SEd Schouten // via bugpoint.
13009b1c42SEd Schouten //
14009b1c42SEd Schouten //===----------------------------------------------------------------------===//
15009b1c42SEd Schouten 
16b60736ecSDimitry Andric #include "llvm/Transforms/IPO/LoopExtractor.h"
174a16efa3SDimitry Andric #include "llvm/ADT/Statistic.h"
18e6d15924SDimitry Andric #include "llvm/Analysis/AssumptionCache.h"
19cfca06d7SDimitry Andric #include "llvm/Analysis/LoopInfo.h"
205ca98fd9SDimitry Andric #include "llvm/IR/Dominators.h"
214a16efa3SDimitry Andric #include "llvm/IR/Instructions.h"
224a16efa3SDimitry Andric #include "llvm/IR/Module.h"
23b60736ecSDimitry Andric #include "llvm/IR/PassManager.h"
24706b4fc4SDimitry Andric #include "llvm/InitializePasses.h"
254a16efa3SDimitry Andric #include "llvm/Pass.h"
267ab83427SDimitry Andric #include "llvm/Transforms/IPO.h"
27eb11fae6SDimitry Andric #include "llvm/Transforms/Utils.h"
2858b69754SDimitry Andric #include "llvm/Transforms/Utils/CodeExtractor.h"
29009b1c42SEd Schouten using namespace llvm;
30009b1c42SEd Schouten 
315ca98fd9SDimitry Andric #define DEBUG_TYPE "loop-extract"
325ca98fd9SDimitry Andric 
33009b1c42SEd Schouten STATISTIC(NumExtracted, "Number of loops extracted");
34009b1c42SEd Schouten 
35009b1c42SEd Schouten namespace {
36b60736ecSDimitry Andric struct LoopExtractorLegacyPass : public ModulePass {
37009b1c42SEd Schouten   static char ID; // Pass identification, replacement for typeid
38cfca06d7SDimitry Andric 
39009b1c42SEd Schouten   unsigned NumLoops;
40009b1c42SEd Schouten 
LoopExtractorLegacyPass__anona359f5b00111::LoopExtractorLegacyPass41b60736ecSDimitry Andric   explicit LoopExtractorLegacyPass(unsigned NumLoops = ~0)
42b60736ecSDimitry Andric       : ModulePass(ID), NumLoops(NumLoops) {
43b60736ecSDimitry Andric     initializeLoopExtractorLegacyPassPass(*PassRegistry::getPassRegistry());
44cf099d11SDimitry Andric   }
45009b1c42SEd Schouten 
46cfca06d7SDimitry Andric   bool runOnModule(Module &M) override;
47009b1c42SEd Schouten 
getAnalysisUsage__anona359f5b00111::LoopExtractorLegacyPass485ca98fd9SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
49009b1c42SEd Schouten     AU.addRequiredID(BreakCriticalEdgesID);
505ca98fd9SDimitry Andric     AU.addRequired<DominatorTreeWrapperPass>();
51dd58ef01SDimitry Andric     AU.addRequired<LoopInfoWrapperPass>();
52cfca06d7SDimitry Andric     AU.addPreserved<LoopInfoWrapperPass>();
53cfca06d7SDimitry Andric     AU.addRequiredID(LoopSimplifyID);
54e6d15924SDimitry Andric     AU.addUsedIfAvailable<AssumptionCacheTracker>();
55009b1c42SEd Schouten   }
56009b1c42SEd Schouten };
57009b1c42SEd Schouten 
58b60736ecSDimitry Andric struct LoopExtractor {
LoopExtractor__anona359f5b00111::LoopExtractor59b60736ecSDimitry Andric   explicit LoopExtractor(
60b60736ecSDimitry Andric       unsigned NumLoops,
61b60736ecSDimitry Andric       function_ref<DominatorTree &(Function &)> LookupDomTree,
62b60736ecSDimitry Andric       function_ref<LoopInfo &(Function &)> LookupLoopInfo,
63b60736ecSDimitry Andric       function_ref<AssumptionCache *(Function &)> LookupAssumptionCache)
64b60736ecSDimitry Andric       : NumLoops(NumLoops), LookupDomTree(LookupDomTree),
65b60736ecSDimitry Andric         LookupLoopInfo(LookupLoopInfo),
66b60736ecSDimitry Andric         LookupAssumptionCache(LookupAssumptionCache) {}
67b60736ecSDimitry Andric   bool runOnModule(Module &M);
68b60736ecSDimitry Andric 
69b60736ecSDimitry Andric private:
70b60736ecSDimitry Andric   // The number of natural loops to extract from the program into functions.
71b60736ecSDimitry Andric   unsigned NumLoops;
72b60736ecSDimitry Andric 
73b60736ecSDimitry Andric   function_ref<DominatorTree &(Function &)> LookupDomTree;
74b60736ecSDimitry Andric   function_ref<LoopInfo &(Function &)> LookupLoopInfo;
75b60736ecSDimitry Andric   function_ref<AssumptionCache *(Function &)> LookupAssumptionCache;
76b60736ecSDimitry Andric 
77b60736ecSDimitry Andric   bool runOnFunction(Function &F);
78b60736ecSDimitry Andric 
79b60736ecSDimitry Andric   bool extractLoops(Loop::iterator From, Loop::iterator To, LoopInfo &LI,
80b60736ecSDimitry Andric                     DominatorTree &DT);
81b60736ecSDimitry Andric   bool extractLoop(Loop *L, LoopInfo &LI, DominatorTree &DT);
82b60736ecSDimitry Andric };
83b60736ecSDimitry Andric } // namespace
84b60736ecSDimitry Andric 
85b60736ecSDimitry Andric char LoopExtractorLegacyPass::ID = 0;
86b60736ecSDimitry Andric INITIALIZE_PASS_BEGIN(LoopExtractorLegacyPass, "loop-extract",
87cf099d11SDimitry Andric                       "Extract loops into new functions", false, false)
88cf099d11SDimitry Andric INITIALIZE_PASS_DEPENDENCY(BreakCriticalEdges)
895ca98fd9SDimitry Andric INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
90cfca06d7SDimitry Andric INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
91cfca06d7SDimitry Andric INITIALIZE_PASS_DEPENDENCY(LoopSimplify)
92b60736ecSDimitry Andric INITIALIZE_PASS_END(LoopExtractorLegacyPass, "loop-extract",
93cf099d11SDimitry Andric                     "Extract loops into new functions", false, false)
94009b1c42SEd Schouten 
95009b1c42SEd Schouten namespace {
96009b1c42SEd Schouten   /// SingleLoopExtractor - For bugpoint.
97b60736ecSDimitry Andric struct SingleLoopExtractor : public LoopExtractorLegacyPass {
98009b1c42SEd Schouten   static char ID; // Pass identification, replacement for typeid
SingleLoopExtractor__anona359f5b00211::SingleLoopExtractor99b60736ecSDimitry Andric   SingleLoopExtractor() : LoopExtractorLegacyPass(1) {}
100009b1c42SEd Schouten };
101009b1c42SEd Schouten } // End anonymous namespace
102009b1c42SEd Schouten 
103009b1c42SEd Schouten char SingleLoopExtractor::ID = 0;
104d39c594dSDimitry Andric INITIALIZE_PASS(SingleLoopExtractor, "loop-extract-single",
105cf099d11SDimitry Andric                 "Extract at most one loop into a new function", false, false)
106009b1c42SEd Schouten 
107009b1c42SEd Schouten // createLoopExtractorPass - This pass extracts all natural loops from the
108009b1c42SEd Schouten // program into a function if it can.
109009b1c42SEd Schouten //
createLoopExtractorPass()110b60736ecSDimitry Andric Pass *llvm::createLoopExtractorPass() { return new LoopExtractorLegacyPass(); }
111009b1c42SEd Schouten 
runOnModule(Module & M)112b60736ecSDimitry Andric bool LoopExtractorLegacyPass::runOnModule(Module &M) {
113cfca06d7SDimitry Andric   if (skipModule(M))
1145ca98fd9SDimitry Andric     return false;
1155ca98fd9SDimitry Andric 
116b60736ecSDimitry Andric   bool Changed = false;
117b60736ecSDimitry Andric   auto LookupDomTree = [this](Function &F) -> DominatorTree & {
118b60736ecSDimitry Andric     return this->getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
119b60736ecSDimitry Andric   };
120b60736ecSDimitry Andric   auto LookupLoopInfo = [this, &Changed](Function &F) -> LoopInfo & {
121b60736ecSDimitry Andric     return this->getAnalysis<LoopInfoWrapperPass>(F, &Changed).getLoopInfo();
122b60736ecSDimitry Andric   };
123b60736ecSDimitry Andric   auto LookupACT = [this](Function &F) -> AssumptionCache * {
124b60736ecSDimitry Andric     if (auto *ACT = this->getAnalysisIfAvailable<AssumptionCacheTracker>())
125b60736ecSDimitry Andric       return ACT->lookupAssumptionCache(F);
126b60736ecSDimitry Andric     return nullptr;
127b60736ecSDimitry Andric   };
128b60736ecSDimitry Andric   return LoopExtractor(NumLoops, LookupDomTree, LookupLoopInfo, LookupACT)
129b60736ecSDimitry Andric              .runOnModule(M) ||
130b60736ecSDimitry Andric          Changed;
131b60736ecSDimitry Andric }
132b60736ecSDimitry Andric 
runOnModule(Module & M)133b60736ecSDimitry Andric bool LoopExtractor::runOnModule(Module &M) {
134cfca06d7SDimitry Andric   if (M.empty())
135009b1c42SEd Schouten     return false;
136009b1c42SEd Schouten 
137cfca06d7SDimitry Andric   if (!NumLoops)
138907da171SRoman Divacky     return false;
139907da171SRoman Divacky 
14059850d08SRoman Divacky   bool Changed = false;
141009b1c42SEd Schouten 
142cfca06d7SDimitry Andric   // The end of the function list may change (new functions will be added at the
143cfca06d7SDimitry Andric   // end), so we run from the first to the current last.
144cfca06d7SDimitry Andric   auto I = M.begin(), E = --M.end();
145cfca06d7SDimitry Andric   while (true) {
146cfca06d7SDimitry Andric     Function &F = *I;
147cfca06d7SDimitry Andric 
148cfca06d7SDimitry Andric     Changed |= runOnFunction(F);
149cfca06d7SDimitry Andric     if (!NumLoops)
150cfca06d7SDimitry Andric       break;
151cfca06d7SDimitry Andric 
152cfca06d7SDimitry Andric     // If this is the last function.
153cfca06d7SDimitry Andric     if (I == E)
154cfca06d7SDimitry Andric       break;
155cfca06d7SDimitry Andric 
156cfca06d7SDimitry Andric     ++I;
157cfca06d7SDimitry Andric   }
158cfca06d7SDimitry Andric   return Changed;
159cfca06d7SDimitry Andric }
160cfca06d7SDimitry Andric 
runOnFunction(Function & F)161cfca06d7SDimitry Andric bool LoopExtractor::runOnFunction(Function &F) {
162cfca06d7SDimitry Andric   // Do not modify `optnone` functions.
163cfca06d7SDimitry Andric   if (F.hasOptNone())
164cfca06d7SDimitry Andric     return false;
165cfca06d7SDimitry Andric 
166cfca06d7SDimitry Andric   if (F.empty())
167cfca06d7SDimitry Andric     return false;
168cfca06d7SDimitry Andric 
169cfca06d7SDimitry Andric   bool Changed = false;
170b60736ecSDimitry Andric   LoopInfo &LI = LookupLoopInfo(F);
171cfca06d7SDimitry Andric 
172cfca06d7SDimitry Andric   // If there are no loops in the function.
173cfca06d7SDimitry Andric   if (LI.empty())
174cfca06d7SDimitry Andric     return Changed;
175cfca06d7SDimitry Andric 
176b60736ecSDimitry Andric   DominatorTree &DT = LookupDomTree(F);
177cfca06d7SDimitry Andric 
178009b1c42SEd Schouten   // If there is more than one top-level loop in this function, extract all of
179cfca06d7SDimitry Andric   // the loops.
180cfca06d7SDimitry Andric   if (std::next(LI.begin()) != LI.end())
181cfca06d7SDimitry Andric     return Changed | extractLoops(LI.begin(), LI.end(), LI, DT);
182cfca06d7SDimitry Andric 
183cfca06d7SDimitry Andric   // Otherwise there is exactly one top-level loop.
184cfca06d7SDimitry Andric   Loop *TLL = *LI.begin();
185cfca06d7SDimitry Andric 
186cfca06d7SDimitry Andric   // If the loop is in LoopSimplify form, then extract it only if this function
187cfca06d7SDimitry Andric   // is more than a minimal wrapper around the loop.
188cfca06d7SDimitry Andric   if (TLL->isLoopSimplifyForm()) {
189009b1c42SEd Schouten     bool ShouldExtractLoop = false;
190009b1c42SEd Schouten 
191009b1c42SEd Schouten     // Extract the loop if the entry block doesn't branch to the loop header.
192cfca06d7SDimitry Andric     Instruction *EntryTI = F.getEntryBlock().getTerminator();
193009b1c42SEd Schouten     if (!isa<BranchInst>(EntryTI) ||
194009b1c42SEd Schouten         !cast<BranchInst>(EntryTI)->isUnconditional() ||
195cfca06d7SDimitry Andric         EntryTI->getSuccessor(0) != TLL->getHeader()) {
196009b1c42SEd Schouten       ShouldExtractLoop = true;
19730815c53SDimitry Andric     } else {
198009b1c42SEd Schouten       // Check to see if any exits from the loop are more than just return
199009b1c42SEd Schouten       // blocks.
200009b1c42SEd Schouten       SmallVector<BasicBlock *, 8> ExitBlocks;
201cfca06d7SDimitry Andric       TLL->getExitBlocks(ExitBlocks);
202cfca06d7SDimitry Andric       for (auto *ExitBlock : ExitBlocks)
203cfca06d7SDimitry Andric         if (!isa<ReturnInst>(ExitBlock->getTerminator())) {
204009b1c42SEd Schouten           ShouldExtractLoop = true;
205009b1c42SEd Schouten           break;
206009b1c42SEd Schouten         }
207009b1c42SEd Schouten     }
20830815c53SDimitry Andric 
209cfca06d7SDimitry Andric     if (ShouldExtractLoop)
210cfca06d7SDimitry Andric       return Changed | extractLoop(TLL, LI, DT);
21130815c53SDimitry Andric   }
21230815c53SDimitry Andric 
213cfca06d7SDimitry Andric   // Okay, this function is a minimal container around the specified loop.
214cfca06d7SDimitry Andric   // If we extract the loop, we will continue to just keep extracting it
215cfca06d7SDimitry Andric   // infinitely... so don't extract it. However, if the loop contains any
216cfca06d7SDimitry Andric   // sub-loops, extract them.
217cfca06d7SDimitry Andric   return Changed | extractLoops(TLL->begin(), TLL->end(), LI, DT);
218cfca06d7SDimitry Andric }
219cfca06d7SDimitry Andric 
extractLoops(Loop::iterator From,Loop::iterator To,LoopInfo & LI,DominatorTree & DT)220cfca06d7SDimitry Andric bool LoopExtractor::extractLoops(Loop::iterator From, Loop::iterator To,
221cfca06d7SDimitry Andric                                  LoopInfo &LI, DominatorTree &DT) {
222cfca06d7SDimitry Andric   bool Changed = false;
223cfca06d7SDimitry Andric   SmallVector<Loop *, 8> Loops;
224cfca06d7SDimitry Andric 
225cfca06d7SDimitry Andric   // Save the list of loops, as it may change.
226cfca06d7SDimitry Andric   Loops.assign(From, To);
227cfca06d7SDimitry Andric   for (Loop *L : Loops) {
228cfca06d7SDimitry Andric     // If LoopSimplify form is not available, stay out of trouble.
229cfca06d7SDimitry Andric     if (!L->isLoopSimplifyForm())
230cfca06d7SDimitry Andric       continue;
231cfca06d7SDimitry Andric 
232cfca06d7SDimitry Andric     Changed |= extractLoop(L, LI, DT);
233cfca06d7SDimitry Andric     if (!NumLoops)
234cfca06d7SDimitry Andric       break;
235cfca06d7SDimitry Andric   }
236cfca06d7SDimitry Andric   return Changed;
237cfca06d7SDimitry Andric }
238cfca06d7SDimitry Andric 
extractLoop(Loop * L,LoopInfo & LI,DominatorTree & DT)239cfca06d7SDimitry Andric bool LoopExtractor::extractLoop(Loop *L, LoopInfo &LI, DominatorTree &DT) {
240cfca06d7SDimitry Andric   assert(NumLoops != 0);
2411d5ae102SDimitry Andric   Function &Func = *L->getHeader()->getParent();
242b60736ecSDimitry Andric   AssumptionCache *AC = LookupAssumptionCache(Func);
2431d5ae102SDimitry Andric   CodeExtractorAnalysisCache CEAC(Func);
244e6d15924SDimitry Andric   CodeExtractor Extractor(DT, *L, false, nullptr, nullptr, AC);
245cfca06d7SDimitry Andric   if (Extractor.extractCodeRegion(CEAC)) {
246044eb2f6SDimitry Andric     LI.erase(L);
247cfca06d7SDimitry Andric     --NumLoops;
24859850d08SRoman Divacky     ++NumExtracted;
249cfca06d7SDimitry Andric     return true;
250009b1c42SEd Schouten   }
251cfca06d7SDimitry Andric   return false;
252009b1c42SEd Schouten }
253009b1c42SEd Schouten 
254009b1c42SEd Schouten // createSingleLoopExtractorPass - This pass extracts one natural loop from the
255009b1c42SEd Schouten // program into a function if it can.  This is used by bugpoint.
256009b1c42SEd Schouten //
createSingleLoopExtractorPass()25759850d08SRoman Divacky Pass *llvm::createSingleLoopExtractorPass() {
258009b1c42SEd Schouten   return new SingleLoopExtractor();
259009b1c42SEd Schouten }
260b60736ecSDimitry Andric 
run(Module & M,ModuleAnalysisManager & AM)261b60736ecSDimitry Andric PreservedAnalyses LoopExtractorPass::run(Module &M, ModuleAnalysisManager &AM) {
262b60736ecSDimitry Andric   auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
263b60736ecSDimitry Andric   auto LookupDomTree = [&FAM](Function &F) -> DominatorTree & {
264b60736ecSDimitry Andric     return FAM.getResult<DominatorTreeAnalysis>(F);
265b60736ecSDimitry Andric   };
266b60736ecSDimitry Andric   auto LookupLoopInfo = [&FAM](Function &F) -> LoopInfo & {
267b60736ecSDimitry Andric     return FAM.getResult<LoopAnalysis>(F);
268b60736ecSDimitry Andric   };
269b60736ecSDimitry Andric   auto LookupAssumptionCache = [&FAM](Function &F) -> AssumptionCache * {
270b60736ecSDimitry Andric     return FAM.getCachedResult<AssumptionAnalysis>(F);
271b60736ecSDimitry Andric   };
272b60736ecSDimitry Andric   if (!LoopExtractor(NumLoops, LookupDomTree, LookupLoopInfo,
273b60736ecSDimitry Andric                      LookupAssumptionCache)
274b60736ecSDimitry Andric            .runOnModule(M))
275b60736ecSDimitry Andric     return PreservedAnalyses::all();
276b60736ecSDimitry Andric 
277b60736ecSDimitry Andric   PreservedAnalyses PA;
278b60736ecSDimitry Andric   PA.preserve<LoopAnalysis>();
279b60736ecSDimitry Andric   return PA;
280b60736ecSDimitry Andric }
281c0981da4SDimitry Andric 
printPipeline(raw_ostream & OS,function_ref<StringRef (StringRef)> MapClassName2PassName)282c0981da4SDimitry Andric void LoopExtractorPass::printPipeline(
283c0981da4SDimitry Andric     raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) {
284c0981da4SDimitry Andric   static_cast<PassInfoMixin<LoopExtractorPass> *>(this)->printPipeline(
285c0981da4SDimitry Andric       OS, MapClassName2PassName);
2867fa27ce4SDimitry Andric   OS << '<';
287c0981da4SDimitry Andric   if (NumLoops == 1)
288c0981da4SDimitry Andric     OS << "single";
2897fa27ce4SDimitry Andric   OS << '>';
290c0981da4SDimitry Andric }
291