xref: /llvm-project/bolt/lib/Passes/FrameOptimizer.cpp (revision a5f3d1a803020167bd9d494a8a3921e7dcc1550a)
12f09f445SMaksim Panchenko //===- bolt/Passes/FrameOptimizer.cpp -------------------------------------===//
2a34c753fSRafael Auler //
3a34c753fSRafael Auler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a34c753fSRafael Auler // See https://llvm.org/LICENSE.txt for license information.
5a34c753fSRafael Auler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a34c753fSRafael Auler //
7a34c753fSRafael Auler //===----------------------------------------------------------------------===//
8a34c753fSRafael Auler //
92f09f445SMaksim Panchenko // This file implements the FrameOptimizerPass class.
102f09f445SMaksim Panchenko //
11a34c753fSRafael Auler //===----------------------------------------------------------------------===//
12a34c753fSRafael Auler 
13a34c753fSRafael Auler #include "bolt/Passes/FrameOptimizer.h"
14a34c753fSRafael Auler #include "bolt/Core/ParallelUtilities.h"
15a34c753fSRafael Auler #include "bolt/Passes/BinaryFunctionCallGraph.h"
16a34c753fSRafael Auler #include "bolt/Passes/DataflowInfoManager.h"
17a34c753fSRafael Auler #include "bolt/Passes/ShrinkWrapping.h"
18a34c753fSRafael Auler #include "bolt/Passes/StackAvailableExpressions.h"
19a34c753fSRafael Auler #include "bolt/Passes/StackReachingUses.h"
203332904aSRafael Auler #include "bolt/Utils/CommandLineOpts.h"
21a34c753fSRafael Auler #include "llvm/Support/Timer.h"
22a34c753fSRafael Auler #include <deque>
23a34c753fSRafael Auler #include <unordered_map>
24a34c753fSRafael Auler 
25a34c753fSRafael Auler #define DEBUG_TYPE "fop"
26a34c753fSRafael Auler 
27a34c753fSRafael Auler using namespace llvm;
28a34c753fSRafael Auler 
29a34c753fSRafael Auler namespace opts {
30a34c753fSRafael Auler extern cl::opt<unsigned> Verbosity;
31a34c753fSRafael Auler extern cl::opt<bool> TimeOpts;
32a34c753fSRafael Auler extern cl::OptionCategory BoltOptCategory;
33a34c753fSRafael Auler 
34a34c753fSRafael Auler using namespace bolt;
35a34c753fSRafael Auler 
36a34c753fSRafael Auler cl::opt<FrameOptimizationType>
37a34c753fSRafael Auler FrameOptimization("frame-opt",
38a34c753fSRafael Auler   cl::init(FOP_NONE),
39a34c753fSRafael Auler   cl::desc("optimize stack frame accesses"),
40a34c753fSRafael Auler   cl::values(
41a34c753fSRafael Auler     clEnumValN(FOP_NONE, "none", "do not perform frame optimization"),
42a34c753fSRafael Auler     clEnumValN(FOP_HOT, "hot", "perform FOP on hot functions"),
43a34c753fSRafael Auler     clEnumValN(FOP_ALL, "all", "perform FOP on all functions")),
44a34c753fSRafael Auler   cl::ZeroOrMore,
45a34c753fSRafael Auler   cl::cat(BoltOptCategory));
46a34c753fSRafael Auler 
47b92436efSFangrui Song cl::opt<bool> RemoveStores(
48b92436efSFangrui Song     "frame-opt-rm-stores", cl::init(FOP_NONE),
49a34c753fSRafael Auler     cl::desc("apply additional analysis to remove stores (experimental)"),
50a34c753fSRafael Auler     cl::cat(BoltOptCategory));
51a34c753fSRafael Auler 
52a34c753fSRafael Auler } // namespace opts
53a34c753fSRafael Auler 
54a34c753fSRafael Auler namespace llvm {
55a34c753fSRafael Auler namespace bolt {
56a34c753fSRafael Auler 
57a34c753fSRafael Auler void FrameOptimizerPass::removeUnnecessaryLoads(const RegAnalysis &RA,
58a34c753fSRafael Auler                                                 const FrameAnalysis &FA,
59a34c753fSRafael Auler                                                 BinaryFunction &BF) {
6060b09997SMaksim Panchenko   StackAvailableExpressions SAE(RA, FA, BF);
61a34c753fSRafael Auler   SAE.run();
62a34c753fSRafael Auler 
63a34c753fSRafael Auler   LLVM_DEBUG(dbgs() << "Performing unnecessary loads removal\n");
64a34c753fSRafael Auler   std::deque<std::pair<BinaryBasicBlock *, MCInst *>> ToErase;
65a34c753fSRafael Auler   bool Changed = false;
66a34c753fSRafael Auler   const auto ExprEnd = SAE.expr_end();
6760b09997SMaksim Panchenko   MCPlusBuilder *MIB = BF.getBinaryContext().MIB.get();
68a34c753fSRafael Auler   for (BinaryBasicBlock &BB : BF) {
69a34c753fSRafael Auler     LLVM_DEBUG(dbgs() << "\tNow at BB " << BB.getName() << "\n");
70a34c753fSRafael Auler     const MCInst *Prev = nullptr;
71a34c753fSRafael Auler     for (MCInst &Inst : BB) {
72a34c753fSRafael Auler       LLVM_DEBUG({
73a34c753fSRafael Auler         dbgs() << "\t\tNow at ";
74a34c753fSRafael Auler         Inst.dump();
75a34c753fSRafael Auler         for (auto I = Prev ? SAE.expr_begin(*Prev) : SAE.expr_begin(BB);
76a34c753fSRafael Auler              I != ExprEnd; ++I) {
77a34c753fSRafael Auler           dbgs() << "\t\t\tReached by: ";
78a34c753fSRafael Auler           (*I)->dump();
79a34c753fSRafael Auler         }
80a34c753fSRafael Auler       });
81a34c753fSRafael Auler       // if Inst is a load from stack and the current available expressions show
82a34c753fSRafael Auler       // this value is available in a register or immediate, replace this load
83a34c753fSRafael Auler       // with move from register or from immediate.
84a34c753fSRafael Auler       ErrorOr<const FrameIndexEntry &> FIEX = FA.getFIEFor(Inst);
85a34c753fSRafael Auler       if (!FIEX) {
86a34c753fSRafael Auler         Prev = &Inst;
87a34c753fSRafael Auler         continue;
88a34c753fSRafael Auler       }
89a34c753fSRafael Auler       // FIXME: Change to remove IsSimple == 0. We're being conservative here,
90a34c753fSRafael Auler       // but once replaceMemOperandWithReg is ready, we should feed it with all
91a34c753fSRafael Auler       // sorts of complex instructions.
92a34c753fSRafael Auler       if (FIEX->IsLoad == false || FIEX->IsSimple == false ||
93a34c753fSRafael Auler           FIEX->StackOffset >= 0) {
94a34c753fSRafael Auler         Prev = &Inst;
95a34c753fSRafael Auler         continue;
96a34c753fSRafael Auler       }
97a34c753fSRafael Auler 
98a34c753fSRafael Auler       for (auto I = Prev ? SAE.expr_begin(*Prev) : SAE.expr_begin(BB);
99a34c753fSRafael Auler            I != ExprEnd; ++I) {
100a34c753fSRafael Auler         const MCInst *AvailableInst = *I;
101a34c753fSRafael Auler         ErrorOr<const FrameIndexEntry &> FIEY = FA.getFIEFor(*AvailableInst);
102a34c753fSRafael Auler         if (!FIEY)
103a34c753fSRafael Auler           continue;
104a34c753fSRafael Auler         assert(FIEY->IsStore && FIEY->IsSimple);
105a34c753fSRafael Auler         if (FIEX->StackOffset != FIEY->StackOffset || FIEX->Size != FIEY->Size)
106a34c753fSRafael Auler           continue;
107a34c753fSRafael Auler         // TODO: Change push/pops to stack adjustment instruction
10860b09997SMaksim Panchenko         if (MIB->isPop(Inst))
109a34c753fSRafael Auler           continue;
110a34c753fSRafael Auler 
111a34c753fSRafael Auler         ++NumRedundantLoads;
11242465efdSRafael Auler         FreqRedundantLoads += BB.getKnownExecutionCount();
113a34c753fSRafael Auler         Changed = true;
114a34c753fSRafael Auler         LLVM_DEBUG(dbgs() << "Redundant load instruction: ");
115a34c753fSRafael Auler         LLVM_DEBUG(Inst.dump());
116a34c753fSRafael Auler         LLVM_DEBUG(dbgs() << "Related store instruction: ");
117a34c753fSRafael Auler         LLVM_DEBUG(AvailableInst->dump());
118a34c753fSRafael Auler         LLVM_DEBUG(dbgs() << "@BB: " << BB.getName() << "\n");
119a34c753fSRafael Auler         // Replace load
120a34c753fSRafael Auler         if (FIEY->IsStoreFromReg) {
12160b09997SMaksim Panchenko           if (!MIB->replaceMemOperandWithReg(Inst, FIEY->RegOrImm)) {
122a34c753fSRafael Auler             LLVM_DEBUG(dbgs() << "FAILED to change operand to a reg\n");
123a34c753fSRafael Auler             break;
124a34c753fSRafael Auler           }
12542465efdSRafael Auler           FreqLoadsChangedToReg += BB.getKnownExecutionCount();
12660b09997SMaksim Panchenko           MIB->removeAnnotation(Inst, "FrameAccessEntry");
127a34c753fSRafael Auler           LLVM_DEBUG(dbgs() << "Changed operand to a reg\n");
12860b09997SMaksim Panchenko           if (MIB->isRedundantMove(Inst)) {
129a34c753fSRafael Auler             ++NumLoadsDeleted;
13042465efdSRafael Auler             FreqLoadsDeleted += BB.getKnownExecutionCount();
131a34c753fSRafael Auler             LLVM_DEBUG(dbgs() << "Created a redundant move\n");
132a34c753fSRafael Auler             // Delete it!
133a34c753fSRafael Auler             ToErase.push_front(std::make_pair(&BB, &Inst));
134a34c753fSRafael Auler           }
135a34c753fSRafael Auler         } else {
136a34c753fSRafael Auler           char Buf[8] = {0, 0, 0, 0, 0, 0, 0, 0};
137a34c753fSRafael Auler           support::ulittle64_t::ref(Buf + 0) = FIEY->RegOrImm;
138a34c753fSRafael Auler           LLVM_DEBUG(dbgs() << "Changing operand to an imm... ");
13960b09997SMaksim Panchenko           if (!MIB->replaceMemOperandWithImm(Inst, StringRef(Buf, 8), 0)) {
140a34c753fSRafael Auler             LLVM_DEBUG(dbgs() << "FAILED\n");
141a34c753fSRafael Auler           } else {
14242465efdSRafael Auler             FreqLoadsChangedToImm += BB.getKnownExecutionCount();
14360b09997SMaksim Panchenko             MIB->removeAnnotation(Inst, "FrameAccessEntry");
144a34c753fSRafael Auler             LLVM_DEBUG(dbgs() << "Ok\n");
145a34c753fSRafael Auler           }
146a34c753fSRafael Auler         }
147a34c753fSRafael Auler         LLVM_DEBUG(dbgs() << "Changed to: ");
148a34c753fSRafael Auler         LLVM_DEBUG(Inst.dump());
149a34c753fSRafael Auler         break;
150a34c753fSRafael Auler       }
151a34c753fSRafael Auler       Prev = &Inst;
152a34c753fSRafael Auler     }
153a34c753fSRafael Auler   }
154f92ab6afSAmir Ayupov   if (Changed)
155a34c753fSRafael Auler     LLVM_DEBUG(dbgs() << "FOP modified \"" << BF.getPrintName() << "\"\n");
156f92ab6afSAmir Ayupov 
157a34c753fSRafael Auler   // TODO: Implement an interface of eraseInstruction that works out the
158a34c753fSRafael Auler   // complete list of elements to remove.
159f92ab6afSAmir Ayupov   for (std::pair<BinaryBasicBlock *, MCInst *> I : ToErase)
160a34c753fSRafael Auler     I.first->eraseInstruction(I.first->findInstruction(I.second));
161a34c753fSRafael Auler }
162a34c753fSRafael Auler 
163a34c753fSRafael Auler void FrameOptimizerPass::removeUnusedStores(const FrameAnalysis &FA,
164a34c753fSRafael Auler                                             BinaryFunction &BF) {
16560b09997SMaksim Panchenko   StackReachingUses SRU(FA, BF);
166a34c753fSRafael Auler   SRU.run();
167a34c753fSRafael Auler 
168a34c753fSRafael Auler   LLVM_DEBUG(dbgs() << "Performing unused stores removal\n");
169a34c753fSRafael Auler   std::vector<std::pair<BinaryBasicBlock *, MCInst *>> ToErase;
170a34c753fSRafael Auler   bool Changed = false;
171a34c753fSRafael Auler   for (BinaryBasicBlock &BB : BF) {
172a34c753fSRafael Auler     LLVM_DEBUG(dbgs() << "\tNow at BB " << BB.getName() << "\n");
173a34c753fSRafael Auler     const MCInst *Prev = nullptr;
174f40d25ddSAmir Ayupov     for (MCInst &Inst : llvm::reverse(BB)) {
175a34c753fSRafael Auler       LLVM_DEBUG({
176a34c753fSRafael Auler         dbgs() << "\t\tNow at ";
177a34c753fSRafael Auler         Inst.dump();
178a34c753fSRafael Auler         for (auto I = Prev ? SRU.expr_begin(*Prev) : SRU.expr_begin(BB);
179a34c753fSRafael Auler              I != SRU.expr_end(); ++I) {
180a34c753fSRafael Auler           dbgs() << "\t\t\tReached by: ";
181a34c753fSRafael Auler           (*I)->dump();
182a34c753fSRafael Auler         }
183a34c753fSRafael Auler       });
184a34c753fSRafael Auler       ErrorOr<const FrameIndexEntry &> FIEX = FA.getFIEFor(Inst);
185a34c753fSRafael Auler       if (!FIEX) {
186a34c753fSRafael Auler         Prev = &Inst;
187a34c753fSRafael Auler         continue;
188a34c753fSRafael Auler       }
189a34c753fSRafael Auler       if (FIEX->IsLoad || !FIEX->IsSimple || FIEX->StackOffset >= 0) {
190a34c753fSRafael Auler         Prev = &Inst;
191a34c753fSRafael Auler         continue;
192a34c753fSRafael Auler       }
193a34c753fSRafael Auler 
194a34c753fSRafael Auler       if (SRU.isStoreUsed(*FIEX,
195a34c753fSRafael Auler                           Prev ? SRU.expr_begin(*Prev) : SRU.expr_begin(BB))) {
196a34c753fSRafael Auler         Prev = &Inst;
197a34c753fSRafael Auler         continue;
198a34c753fSRafael Auler       }
199a34c753fSRafael Auler       // TODO: Change push/pops to stack adjustment instruction
20060b09997SMaksim Panchenko       if (BF.getBinaryContext().MIB->isPush(Inst))
201a34c753fSRafael Auler         continue;
202a34c753fSRafael Auler 
203a34c753fSRafael Auler       ++NumRedundantStores;
20442465efdSRafael Auler       FreqRedundantStores += BB.getKnownExecutionCount();
205a34c753fSRafael Auler       Changed = true;
206a34c753fSRafael Auler       LLVM_DEBUG(dbgs() << "Unused store instruction: ");
207a34c753fSRafael Auler       LLVM_DEBUG(Inst.dump());
208a34c753fSRafael Auler       LLVM_DEBUG(dbgs() << "@BB: " << BB.getName() << "\n");
209a34c753fSRafael Auler       LLVM_DEBUG(dbgs() << "FIE offset = " << FIEX->StackOffset
210a34c753fSRafael Auler                         << " size = " << (int)FIEX->Size << "\n");
211a34c753fSRafael Auler       // Delete it!
212a34c753fSRafael Auler       ToErase.emplace_back(&BB, &Inst);
213a34c753fSRafael Auler       Prev = &Inst;
214a34c753fSRafael Auler     }
215a34c753fSRafael Auler   }
216a34c753fSRafael Auler 
217f92ab6afSAmir Ayupov   for (std::pair<BinaryBasicBlock *, MCInst *> I : ToErase)
218a34c753fSRafael Auler     I.first->eraseInstruction(I.first->findInstruction(I.second));
219f92ab6afSAmir Ayupov 
220f92ab6afSAmir Ayupov   if (Changed)
221a34c753fSRafael Auler     LLVM_DEBUG(dbgs() << "FOP modified \"" << BF.getPrintName() << "\"\n");
222a34c753fSRafael Auler }
223a34c753fSRafael Auler 
224*a5f3d1a8SAmir Ayupov Error FrameOptimizerPass::runOnFunctions(BinaryContext &BC) {
225a34c753fSRafael Auler   if (opts::FrameOptimization == FOP_NONE)
226*a5f3d1a8SAmir Ayupov     return Error::success();
227a34c753fSRafael Auler 
228a34c753fSRafael Auler   std::unique_ptr<BinaryFunctionCallGraph> CG;
229a34c753fSRafael Auler   std::unique_ptr<FrameAnalysis> FA;
230a34c753fSRafael Auler   std::unique_ptr<RegAnalysis> RA;
231a34c753fSRafael Auler 
232a34c753fSRafael Auler   {
233a34c753fSRafael Auler     NamedRegionTimer T1("callgraph", "create call graph", "FOP",
234a34c753fSRafael Auler                         "FOP breakdown", opts::TimeOpts);
235a34c753fSRafael Auler     CG = std::make_unique<BinaryFunctionCallGraph>(buildCallGraph(BC));
236a34c753fSRafael Auler   }
237a34c753fSRafael Auler 
238a34c753fSRafael Auler   {
239a34c753fSRafael Auler     NamedRegionTimer T1("frameanalysis", "frame analysis", "FOP",
240a34c753fSRafael Auler                         "FOP breakdown", opts::TimeOpts);
241a34c753fSRafael Auler     FA = std::make_unique<FrameAnalysis>(BC, *CG);
242a34c753fSRafael Auler   }
243a34c753fSRafael Auler 
244a34c753fSRafael Auler   {
24540c2e0faSMaksim Panchenko     NamedRegionTimer T1("reganalysis", "reg analysis", "FOP", "FOP breakdown",
24640c2e0faSMaksim Panchenko                         opts::TimeOpts);
247a34c753fSRafael Auler     RA = std::make_unique<RegAnalysis>(BC, &BC.getBinaryFunctions(), CG.get());
248a34c753fSRafael Auler   }
249a34c753fSRafael Auler 
250a34c753fSRafael Auler   // Perform caller-saved register optimizations, then callee-saved register
251a34c753fSRafael Auler   // optimizations (shrink wrapping)
252a34c753fSRafael Auler   for (auto &I : BC.getBinaryFunctions()) {
253a34c753fSRafael Auler     if (!FA->hasFrameInfo(I.second))
254a34c753fSRafael Auler       continue;
255a34c753fSRafael Auler     // Restrict pass execution if user asked to only run on hot functions
256a34c753fSRafael Auler     if (opts::FrameOptimization == FOP_HOT) {
257a34c753fSRafael Auler       if (I.second.getKnownExecutionCount() < BC.getHotThreshold())
258a34c753fSRafael Auler         continue;
259a34c753fSRafael Auler       LLVM_DEBUG(
260a34c753fSRafael Auler           dbgs() << "Considering " << I.second.getPrintName()
261a34c753fSRafael Auler                  << " for frame optimizations because its execution count ( "
262a34c753fSRafael Auler                  << I.second.getKnownExecutionCount()
263a34c753fSRafael Auler                  << " ) exceeds our hotness threshold ( "
264a34c753fSRafael Auler                  << BC.getHotThreshold() << " )\n");
265a34c753fSRafael Auler     }
266a34c753fSRafael Auler 
267a34c753fSRafael Auler     {
268a34c753fSRafael Auler       NamedRegionTimer T1("removeloads", "remove loads", "FOP", "FOP breakdown",
269a34c753fSRafael Auler                           opts::TimeOpts);
270a3cfdd74SRafael Auler       if (!FA->hasStackArithmetic(I.second))
27160b09997SMaksim Panchenko         removeUnnecessaryLoads(*RA, *FA, I.second);
272a34c753fSRafael Auler     }
273a34c753fSRafael Auler 
274a34c753fSRafael Auler     if (opts::RemoveStores) {
275a34c753fSRafael Auler       NamedRegionTimer T1("removestores", "remove stores", "FOP",
276a34c753fSRafael Auler                           "FOP breakdown", opts::TimeOpts);
277a3cfdd74SRafael Auler       if (!FA->hasStackArithmetic(I.second))
27860b09997SMaksim Panchenko         removeUnusedStores(*FA, I.second);
279a34c753fSRafael Auler     }
280a34c753fSRafael Auler     // Don't even start shrink wrapping if no profiling info is available
281a34c753fSRafael Auler     if (I.second.getKnownExecutionCount() == 0)
282a34c753fSRafael Auler       continue;
283a34c753fSRafael Auler   }
284a34c753fSRafael Auler 
285a34c753fSRafael Auler   {
286a34c753fSRafael Auler     NamedRegionTimer T1("shrinkwrapping", "shrink wrapping", "FOP",
287a34c753fSRafael Auler                         "FOP breakdown", opts::TimeOpts);
288a34c753fSRafael Auler     performShrinkWrapping(*RA, *FA, BC);
289a34c753fSRafael Auler   }
290a34c753fSRafael Auler 
291a34c753fSRafael Auler   outs() << "BOLT-INFO: FOP optimized " << NumRedundantLoads
292a34c753fSRafael Auler          << " redundant load(s) and " << NumRedundantStores
293a34c753fSRafael Auler          << " unused store(s)\n";
29442465efdSRafael Auler   outs() << "BOLT-INFO: Frequency of redundant loads is " << FreqRedundantLoads
29542465efdSRafael Auler          << " and frequency of unused stores is " << FreqRedundantStores
29642465efdSRafael Auler          << "\n";
29742465efdSRafael Auler   outs() << "BOLT-INFO: Frequency of loads changed to use a register is "
29842465efdSRafael Auler          << FreqLoadsChangedToReg
29942465efdSRafael Auler          << " and frequency of loads changed to use an immediate is "
30042465efdSRafael Auler          << FreqLoadsChangedToImm << "\n";
30142465efdSRafael Auler   outs() << "BOLT-INFO: FOP deleted " << NumLoadsDeleted
30242465efdSRafael Auler          << " load(s) (dyn count: " << FreqLoadsDeleted << ") and "
30342465efdSRafael Auler          << NumRedundantStores << " store(s)\n";
304a34c753fSRafael Auler   FA->printStats();
305a34c753fSRafael Auler   ShrinkWrapping::printStats();
306*a5f3d1a8SAmir Ayupov   return Error::success();
307a34c753fSRafael Auler }
308a34c753fSRafael Auler 
309a34c753fSRafael Auler void FrameOptimizerPass::performShrinkWrapping(const RegAnalysis &RA,
310a34c753fSRafael Auler                                                const FrameAnalysis &FA,
311a34c753fSRafael Auler                                                BinaryContext &BC) {
312a34c753fSRafael Auler   // Initialize necessary annotations to allow safe parallel accesses to
313a34c753fSRafael Auler   // annotation index in MIB
314a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex(CalleeSavedAnalysis::getSaveTagName());
315a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex(CalleeSavedAnalysis::getRestoreTagName());
316a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex(StackLayoutModifier::getTodoTagName());
317a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex(StackLayoutModifier::getSlotTagName());
318a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex(
319a34c753fSRafael Auler       StackLayoutModifier::getOffsetCFIRegTagName());
320a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("ReachingDefs");
321a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("ReachingUses");
322a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("LivenessAnalysis");
323a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("StackReachingUses");
324a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("PostDominatorAnalysis");
325a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("DominatorAnalysis");
326a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("StackPointerTracking");
327a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("StackPointerTrackingForInternalCalls");
328a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("StackAvailableExpressions");
329a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("StackAllocationAnalysis");
330a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("ShrinkWrap-Todo");
331a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("PredictiveStackPointerTracking");
332a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("ReachingInsnsBackward");
333a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("ReachingInsns");
334a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("AccessesDeletedPos");
335a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("DeleteMe");
336a34c753fSRafael Auler 
33742465efdSRafael Auler   std::vector<std::pair<uint64_t, const BinaryFunction *>> Top10Funcs;
33842465efdSRafael Auler   auto LogFunc = [&](BinaryFunction &BF) {
33989f14332SKazu Hirata     auto Lower = llvm::lower_bound(
34089f14332SKazu Hirata         Top10Funcs, BF.getKnownExecutionCount(),
34142465efdSRafael Auler         [](const std::pair<uint64_t, const BinaryFunction *> &Elmt,
34242465efdSRafael Auler            uint64_t Value) { return Elmt.first > Value; });
34342465efdSRafael Auler     if (Lower == Top10Funcs.end() && Top10Funcs.size() >= 10)
34442465efdSRafael Auler       return;
34542465efdSRafael Auler     Top10Funcs.insert(Lower,
34642465efdSRafael Auler                       std::make_pair<>(BF.getKnownExecutionCount(), &BF));
34742465efdSRafael Auler     if (Top10Funcs.size() > 10)
34842465efdSRafael Auler       Top10Funcs.resize(10);
34942465efdSRafael Auler   };
35042465efdSRafael Auler   (void)LogFunc;
35142465efdSRafael Auler 
352a34c753fSRafael Auler   ParallelUtilities::PredicateTy SkipPredicate = [&](const BinaryFunction &BF) {
35342465efdSRafael Auler     if (BF.getFunctionScore() == 0)
354a34c753fSRafael Auler       return true;
355a34c753fSRafael Auler 
356a34c753fSRafael Auler     return false;
357a34c753fSRafael Auler   };
358a34c753fSRafael Auler 
35942465efdSRafael Auler   const bool HotOnly = opts::FrameOptimization == FOP_HOT;
36042465efdSRafael Auler 
361a34c753fSRafael Auler   ParallelUtilities::WorkFuncWithAllocTy WorkFunction =
362a34c753fSRafael Auler       [&](BinaryFunction &BF, MCPlusBuilder::AllocatorIdTy AllocatorId) {
36360b09997SMaksim Panchenko         DataflowInfoManager Info(BF, &RA, &FA, AllocatorId);
36460b09997SMaksim Panchenko         ShrinkWrapping SW(FA, BF, Info, AllocatorId);
365a34c753fSRafael Auler 
36642465efdSRafael Auler         if (SW.perform(HotOnly)) {
367a34c753fSRafael Auler           std::lock_guard<std::mutex> Lock(FuncsChangedMutex);
368a34c753fSRafael Auler           FuncsChanged.insert(&BF);
36942465efdSRafael Auler           LLVM_DEBUG(LogFunc(BF));
370a34c753fSRafael Auler         }
371a34c753fSRafael Auler       };
372a34c753fSRafael Auler 
373a34c753fSRafael Auler   ParallelUtilities::runOnEachFunctionWithUniqueAllocId(
374a34c753fSRafael Auler       BC, ParallelUtilities::SchedulingPolicy::SP_INST_QUADRATIC, WorkFunction,
375a34c753fSRafael Auler       SkipPredicate, "shrink-wrapping");
37642465efdSRafael Auler 
37742465efdSRafael Auler   if (!Top10Funcs.empty()) {
37842465efdSRafael Auler     outs() << "BOLT-INFO: top 10 functions changed by shrink wrapping:\n";
37942465efdSRafael Auler     for (const auto &Elmt : Top10Funcs)
38042465efdSRafael Auler       outs() << Elmt.first << " : " << Elmt.second->getPrintName() << "\n";
38142465efdSRafael Auler   }
382a34c753fSRafael Auler }
383a34c753fSRafael Auler 
384a34c753fSRafael Auler } // namespace bolt
385a34c753fSRafael Auler } // namespace llvm
386