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"
14*2430a354Sshaw young #include "bolt/Core/BinaryFunctionCallGraph.h"
15a34c753fSRafael Auler #include "bolt/Core/ParallelUtilities.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
24a34c753fSRafael Auler #define DEBUG_TYPE "fop"
25a34c753fSRafael Auler
26a34c753fSRafael Auler using namespace llvm;
27a34c753fSRafael Auler
28a34c753fSRafael Auler namespace opts {
29a34c753fSRafael Auler extern cl::opt<unsigned> Verbosity;
30a34c753fSRafael Auler extern cl::opt<bool> TimeOpts;
31a34c753fSRafael Auler extern cl::OptionCategory BoltOptCategory;
32a34c753fSRafael Auler
33a34c753fSRafael Auler using namespace bolt;
34a34c753fSRafael Auler
35a34c753fSRafael Auler cl::opt<FrameOptimizationType>
36a34c753fSRafael Auler FrameOptimization("frame-opt",
37a34c753fSRafael Auler cl::init(FOP_NONE),
38a34c753fSRafael Auler cl::desc("optimize stack frame accesses"),
39a34c753fSRafael Auler cl::values(
40a34c753fSRafael Auler clEnumValN(FOP_NONE, "none", "do not perform frame optimization"),
41a34c753fSRafael Auler clEnumValN(FOP_HOT, "hot", "perform FOP on hot functions"),
42a34c753fSRafael Auler clEnumValN(FOP_ALL, "all", "perform FOP on all functions")),
43a34c753fSRafael Auler cl::ZeroOrMore,
44a34c753fSRafael Auler cl::cat(BoltOptCategory));
45a34c753fSRafael Auler
46b92436efSFangrui Song cl::opt<bool> RemoveStores(
47b92436efSFangrui Song "frame-opt-rm-stores", cl::init(FOP_NONE),
48a34c753fSRafael Auler cl::desc("apply additional analysis to remove stores (experimental)"),
49a34c753fSRafael Auler cl::cat(BoltOptCategory));
50a34c753fSRafael Auler
51a34c753fSRafael Auler } // namespace opts
52a34c753fSRafael Auler
53a34c753fSRafael Auler namespace llvm {
54a34c753fSRafael Auler namespace bolt {
55a34c753fSRafael Auler
removeUnnecessaryLoads(const RegAnalysis & RA,const FrameAnalysis & FA,BinaryFunction & BF)56a34c753fSRafael Auler void FrameOptimizerPass::removeUnnecessaryLoads(const RegAnalysis &RA,
57a34c753fSRafael Auler const FrameAnalysis &FA,
58a34c753fSRafael Auler BinaryFunction &BF) {
5960b09997SMaksim Panchenko StackAvailableExpressions SAE(RA, FA, BF);
60a34c753fSRafael Auler SAE.run();
61a34c753fSRafael Auler
62a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Performing unnecessary loads removal\n");
63a34c753fSRafael Auler std::deque<std::pair<BinaryBasicBlock *, MCInst *>> ToErase;
64a34c753fSRafael Auler bool Changed = false;
65a34c753fSRafael Auler const auto ExprEnd = SAE.expr_end();
6660b09997SMaksim Panchenko MCPlusBuilder *MIB = BF.getBinaryContext().MIB.get();
67a34c753fSRafael Auler for (BinaryBasicBlock &BB : BF) {
68a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "\tNow at BB " << BB.getName() << "\n");
69a34c753fSRafael Auler const MCInst *Prev = nullptr;
70a34c753fSRafael Auler for (MCInst &Inst : BB) {
71a34c753fSRafael Auler LLVM_DEBUG({
72a34c753fSRafael Auler dbgs() << "\t\tNow at ";
73a34c753fSRafael Auler Inst.dump();
74a34c753fSRafael Auler for (auto I = Prev ? SAE.expr_begin(*Prev) : SAE.expr_begin(BB);
75a34c753fSRafael Auler I != ExprEnd; ++I) {
76a34c753fSRafael Auler dbgs() << "\t\t\tReached by: ";
77a34c753fSRafael Auler (*I)->dump();
78a34c753fSRafael Auler }
79a34c753fSRafael Auler });
80a34c753fSRafael Auler // if Inst is a load from stack and the current available expressions show
81a34c753fSRafael Auler // this value is available in a register or immediate, replace this load
82a34c753fSRafael Auler // with move from register or from immediate.
83a34c753fSRafael Auler ErrorOr<const FrameIndexEntry &> FIEX = FA.getFIEFor(Inst);
84a34c753fSRafael Auler if (!FIEX) {
85a34c753fSRafael Auler Prev = &Inst;
86a34c753fSRafael Auler continue;
87a34c753fSRafael Auler }
88a34c753fSRafael Auler // FIXME: Change to remove IsSimple == 0. We're being conservative here,
89a34c753fSRafael Auler // but once replaceMemOperandWithReg is ready, we should feed it with all
90a34c753fSRafael Auler // sorts of complex instructions.
91a34c753fSRafael Auler if (FIEX->IsLoad == false || FIEX->IsSimple == false ||
92a34c753fSRafael Auler FIEX->StackOffset >= 0) {
93a34c753fSRafael Auler Prev = &Inst;
94a34c753fSRafael Auler continue;
95a34c753fSRafael Auler }
96a34c753fSRafael Auler
97a34c753fSRafael Auler for (auto I = Prev ? SAE.expr_begin(*Prev) : SAE.expr_begin(BB);
98a34c753fSRafael Auler I != ExprEnd; ++I) {
99a34c753fSRafael Auler const MCInst *AvailableInst = *I;
100a34c753fSRafael Auler ErrorOr<const FrameIndexEntry &> FIEY = FA.getFIEFor(*AvailableInst);
101a34c753fSRafael Auler if (!FIEY)
102a34c753fSRafael Auler continue;
103a34c753fSRafael Auler assert(FIEY->IsStore && FIEY->IsSimple);
104a34c753fSRafael Auler if (FIEX->StackOffset != FIEY->StackOffset || FIEX->Size != FIEY->Size)
105a34c753fSRafael Auler continue;
106a34c753fSRafael Auler // TODO: Change push/pops to stack adjustment instruction
10760b09997SMaksim Panchenko if (MIB->isPop(Inst))
108a34c753fSRafael Auler continue;
109a34c753fSRafael Auler
110a34c753fSRafael Auler ++NumRedundantLoads;
11142465efdSRafael Auler FreqRedundantLoads += BB.getKnownExecutionCount();
112a34c753fSRafael Auler Changed = true;
113a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Redundant load instruction: ");
114a34c753fSRafael Auler LLVM_DEBUG(Inst.dump());
115a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Related store instruction: ");
116a34c753fSRafael Auler LLVM_DEBUG(AvailableInst->dump());
117a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "@BB: " << BB.getName() << "\n");
118a34c753fSRafael Auler // Replace load
119a34c753fSRafael Auler if (FIEY->IsStoreFromReg) {
12060b09997SMaksim Panchenko if (!MIB->replaceMemOperandWithReg(Inst, FIEY->RegOrImm)) {
121a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "FAILED to change operand to a reg\n");
122a34c753fSRafael Auler break;
123a34c753fSRafael Auler }
12442465efdSRafael Auler FreqLoadsChangedToReg += BB.getKnownExecutionCount();
12560b09997SMaksim Panchenko MIB->removeAnnotation(Inst, "FrameAccessEntry");
126a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Changed operand to a reg\n");
12760b09997SMaksim Panchenko if (MIB->isRedundantMove(Inst)) {
128a34c753fSRafael Auler ++NumLoadsDeleted;
12942465efdSRafael Auler FreqLoadsDeleted += BB.getKnownExecutionCount();
130a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Created a redundant move\n");
131a34c753fSRafael Auler // Delete it!
132a34c753fSRafael Auler ToErase.push_front(std::make_pair(&BB, &Inst));
133a34c753fSRafael Auler }
134a34c753fSRafael Auler } else {
135a34c753fSRafael Auler char Buf[8] = {0, 0, 0, 0, 0, 0, 0, 0};
136a34c753fSRafael Auler support::ulittle64_t::ref(Buf + 0) = FIEY->RegOrImm;
137a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Changing operand to an imm... ");
13860b09997SMaksim Panchenko if (!MIB->replaceMemOperandWithImm(Inst, StringRef(Buf, 8), 0)) {
139a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "FAILED\n");
140a34c753fSRafael Auler } else {
14142465efdSRafael Auler FreqLoadsChangedToImm += BB.getKnownExecutionCount();
14260b09997SMaksim Panchenko MIB->removeAnnotation(Inst, "FrameAccessEntry");
143a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Ok\n");
144a34c753fSRafael Auler }
145a34c753fSRafael Auler }
146a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Changed to: ");
147a34c753fSRafael Auler LLVM_DEBUG(Inst.dump());
148a34c753fSRafael Auler break;
149a34c753fSRafael Auler }
150a34c753fSRafael Auler Prev = &Inst;
151a34c753fSRafael Auler }
152a34c753fSRafael Auler }
153f92ab6afSAmir Ayupov if (Changed)
154a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "FOP modified \"" << BF.getPrintName() << "\"\n");
155f92ab6afSAmir Ayupov
156a34c753fSRafael Auler // TODO: Implement an interface of eraseInstruction that works out the
157a34c753fSRafael Auler // complete list of elements to remove.
158f92ab6afSAmir Ayupov for (std::pair<BinaryBasicBlock *, MCInst *> I : ToErase)
159a34c753fSRafael Auler I.first->eraseInstruction(I.first->findInstruction(I.second));
160a34c753fSRafael Auler }
161a34c753fSRafael Auler
removeUnusedStores(const FrameAnalysis & FA,BinaryFunction & BF)162a34c753fSRafael Auler void FrameOptimizerPass::removeUnusedStores(const FrameAnalysis &FA,
163a34c753fSRafael Auler BinaryFunction &BF) {
16460b09997SMaksim Panchenko StackReachingUses SRU(FA, BF);
165a34c753fSRafael Auler SRU.run();
166a34c753fSRafael Auler
167a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Performing unused stores removal\n");
168a34c753fSRafael Auler std::vector<std::pair<BinaryBasicBlock *, MCInst *>> ToErase;
169a34c753fSRafael Auler bool Changed = false;
170a34c753fSRafael Auler for (BinaryBasicBlock &BB : BF) {
171a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "\tNow at BB " << BB.getName() << "\n");
172a34c753fSRafael Auler const MCInst *Prev = nullptr;
173f40d25ddSAmir Ayupov for (MCInst &Inst : llvm::reverse(BB)) {
174a34c753fSRafael Auler LLVM_DEBUG({
175a34c753fSRafael Auler dbgs() << "\t\tNow at ";
176a34c753fSRafael Auler Inst.dump();
177a34c753fSRafael Auler for (auto I = Prev ? SRU.expr_begin(*Prev) : SRU.expr_begin(BB);
178a34c753fSRafael Auler I != SRU.expr_end(); ++I) {
179a34c753fSRafael Auler dbgs() << "\t\t\tReached by: ";
180a34c753fSRafael Auler (*I)->dump();
181a34c753fSRafael Auler }
182a34c753fSRafael Auler });
183a34c753fSRafael Auler ErrorOr<const FrameIndexEntry &> FIEX = FA.getFIEFor(Inst);
184a34c753fSRafael Auler if (!FIEX) {
185a34c753fSRafael Auler Prev = &Inst;
186a34c753fSRafael Auler continue;
187a34c753fSRafael Auler }
188a34c753fSRafael Auler if (FIEX->IsLoad || !FIEX->IsSimple || FIEX->StackOffset >= 0) {
189a34c753fSRafael Auler Prev = &Inst;
190a34c753fSRafael Auler continue;
191a34c753fSRafael Auler }
192a34c753fSRafael Auler
193a34c753fSRafael Auler if (SRU.isStoreUsed(*FIEX,
194a34c753fSRafael Auler Prev ? SRU.expr_begin(*Prev) : SRU.expr_begin(BB))) {
195a34c753fSRafael Auler Prev = &Inst;
196a34c753fSRafael Auler continue;
197a34c753fSRafael Auler }
198a34c753fSRafael Auler // TODO: Change push/pops to stack adjustment instruction
19960b09997SMaksim Panchenko if (BF.getBinaryContext().MIB->isPush(Inst))
200a34c753fSRafael Auler continue;
201a34c753fSRafael Auler
202a34c753fSRafael Auler ++NumRedundantStores;
20342465efdSRafael Auler FreqRedundantStores += BB.getKnownExecutionCount();
204a34c753fSRafael Auler Changed = true;
205a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Unused store instruction: ");
206a34c753fSRafael Auler LLVM_DEBUG(Inst.dump());
207a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "@BB: " << BB.getName() << "\n");
208a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "FIE offset = " << FIEX->StackOffset
209a34c753fSRafael Auler << " size = " << (int)FIEX->Size << "\n");
210a34c753fSRafael Auler // Delete it!
211a34c753fSRafael Auler ToErase.emplace_back(&BB, &Inst);
212a34c753fSRafael Auler Prev = &Inst;
213a34c753fSRafael Auler }
214a34c753fSRafael Auler }
215a34c753fSRafael Auler
216f92ab6afSAmir Ayupov for (std::pair<BinaryBasicBlock *, MCInst *> I : ToErase)
217a34c753fSRafael Auler I.first->eraseInstruction(I.first->findInstruction(I.second));
218f92ab6afSAmir Ayupov
219f92ab6afSAmir Ayupov if (Changed)
220a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "FOP modified \"" << BF.getPrintName() << "\"\n");
221a34c753fSRafael Auler }
222a34c753fSRafael Auler
runOnFunctions(BinaryContext & BC)223a5f3d1a8SAmir Ayupov Error FrameOptimizerPass::runOnFunctions(BinaryContext &BC) {
224a34c753fSRafael Auler if (opts::FrameOptimization == FOP_NONE)
225a5f3d1a8SAmir Ayupov return Error::success();
226a34c753fSRafael Auler
227a34c753fSRafael Auler std::unique_ptr<BinaryFunctionCallGraph> CG;
228a34c753fSRafael Auler std::unique_ptr<FrameAnalysis> FA;
229a34c753fSRafael Auler std::unique_ptr<RegAnalysis> RA;
230a34c753fSRafael Auler
231a34c753fSRafael Auler {
232a34c753fSRafael Auler NamedRegionTimer T1("callgraph", "create call graph", "FOP",
233a34c753fSRafael Auler "FOP breakdown", opts::TimeOpts);
234a34c753fSRafael Auler CG = std::make_unique<BinaryFunctionCallGraph>(buildCallGraph(BC));
235a34c753fSRafael Auler }
236a34c753fSRafael Auler
237a34c753fSRafael Auler {
238a34c753fSRafael Auler NamedRegionTimer T1("frameanalysis", "frame analysis", "FOP",
239a34c753fSRafael Auler "FOP breakdown", opts::TimeOpts);
240a34c753fSRafael Auler FA = std::make_unique<FrameAnalysis>(BC, *CG);
241a34c753fSRafael Auler }
242a34c753fSRafael Auler
243a34c753fSRafael Auler {
24440c2e0faSMaksim Panchenko NamedRegionTimer T1("reganalysis", "reg analysis", "FOP", "FOP breakdown",
24540c2e0faSMaksim Panchenko opts::TimeOpts);
246a34c753fSRafael Auler RA = std::make_unique<RegAnalysis>(BC, &BC.getBinaryFunctions(), CG.get());
247a34c753fSRafael Auler }
248a34c753fSRafael Auler
249a34c753fSRafael Auler // Perform caller-saved register optimizations, then callee-saved register
250a34c753fSRafael Auler // optimizations (shrink wrapping)
251a34c753fSRafael Auler for (auto &I : BC.getBinaryFunctions()) {
252a34c753fSRafael Auler if (!FA->hasFrameInfo(I.second))
253a34c753fSRafael Auler continue;
254a34c753fSRafael Auler // Restrict pass execution if user asked to only run on hot functions
255a34c753fSRafael Auler if (opts::FrameOptimization == FOP_HOT) {
256a34c753fSRafael Auler if (I.second.getKnownExecutionCount() < BC.getHotThreshold())
257a34c753fSRafael Auler continue;
258a34c753fSRafael Auler LLVM_DEBUG(
259a34c753fSRafael Auler dbgs() << "Considering " << I.second.getPrintName()
260a34c753fSRafael Auler << " for frame optimizations because its execution count ( "
261a34c753fSRafael Auler << I.second.getKnownExecutionCount()
262a34c753fSRafael Auler << " ) exceeds our hotness threshold ( "
263a34c753fSRafael Auler << BC.getHotThreshold() << " )\n");
264a34c753fSRafael Auler }
265a34c753fSRafael Auler
266a34c753fSRafael Auler {
267a34c753fSRafael Auler NamedRegionTimer T1("removeloads", "remove loads", "FOP", "FOP breakdown",
268a34c753fSRafael Auler opts::TimeOpts);
269a3cfdd74SRafael Auler if (!FA->hasStackArithmetic(I.second))
27060b09997SMaksim Panchenko removeUnnecessaryLoads(*RA, *FA, I.second);
271a34c753fSRafael Auler }
272a34c753fSRafael Auler
273a34c753fSRafael Auler if (opts::RemoveStores) {
274a34c753fSRafael Auler NamedRegionTimer T1("removestores", "remove stores", "FOP",
275a34c753fSRafael Auler "FOP breakdown", opts::TimeOpts);
276a3cfdd74SRafael Auler if (!FA->hasStackArithmetic(I.second))
27760b09997SMaksim Panchenko removeUnusedStores(*FA, I.second);
278a34c753fSRafael Auler }
279a34c753fSRafael Auler // Don't even start shrink wrapping if no profiling info is available
280a34c753fSRafael Auler if (I.second.getKnownExecutionCount() == 0)
281a34c753fSRafael Auler continue;
282a34c753fSRafael Auler }
283a34c753fSRafael Auler
284a34c753fSRafael Auler {
285a34c753fSRafael Auler NamedRegionTimer T1("shrinkwrapping", "shrink wrapping", "FOP",
286a34c753fSRafael Auler "FOP breakdown", opts::TimeOpts);
28713d60ce2SAmir Ayupov if (Error E = performShrinkWrapping(*RA, *FA, BC))
28813d60ce2SAmir Ayupov return Error(std::move(E));
289a34c753fSRafael Auler }
290a34c753fSRafael Auler
29152cf0711SAmir Ayupov BC.outs() << "BOLT-INFO: FOP optimized " << NumRedundantLoads
292a34c753fSRafael Auler << " redundant load(s) and " << NumRedundantStores
293a34c753fSRafael Auler << " unused store(s)\n";
29452cf0711SAmir Ayupov BC.outs() << "BOLT-INFO: Frequency of redundant loads is "
29552cf0711SAmir Ayupov << FreqRedundantLoads << " and frequency of unused stores is "
29652cf0711SAmir Ayupov << FreqRedundantStores << "\n";
29752cf0711SAmir Ayupov BC.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";
30152cf0711SAmir Ayupov BC.outs() << "BOLT-INFO: FOP deleted " << NumLoadsDeleted
30242465efdSRafael Auler << " load(s) (dyn count: " << FreqLoadsDeleted << ") and "
30342465efdSRafael Auler << NumRedundantStores << " store(s)\n";
304a34c753fSRafael Auler FA->printStats();
30552cf0711SAmir Ayupov ShrinkWrapping::printStats(BC);
306a5f3d1a8SAmir Ayupov return Error::success();
307a34c753fSRafael Auler }
308a34c753fSRafael Auler
performShrinkWrapping(const RegAnalysis & RA,const FrameAnalysis & FA,BinaryContext & BC)30913d60ce2SAmir Ayupov Error 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
36113d60ce2SAmir Ayupov Error SWError = Error::success();
36213d60ce2SAmir Ayupov
363a34c753fSRafael Auler ParallelUtilities::WorkFuncWithAllocTy WorkFunction =
364a34c753fSRafael Auler [&](BinaryFunction &BF, MCPlusBuilder::AllocatorIdTy AllocatorId) {
36560b09997SMaksim Panchenko DataflowInfoManager Info(BF, &RA, &FA, AllocatorId);
36660b09997SMaksim Panchenko ShrinkWrapping SW(FA, BF, Info, AllocatorId);
367a34c753fSRafael Auler
36813d60ce2SAmir Ayupov auto ChangedOrErr = SW.perform(HotOnly);
36913d60ce2SAmir Ayupov if (auto E = ChangedOrErr.takeError()) {
37013d60ce2SAmir Ayupov std::lock_guard<std::mutex> Lock(FuncsChangedMutex);
37113d60ce2SAmir Ayupov SWError = joinErrors(std::move(SWError), Error(std::move(E)));
37213d60ce2SAmir Ayupov return;
37313d60ce2SAmir Ayupov }
37413d60ce2SAmir Ayupov const bool Changed = *ChangedOrErr;
37513d60ce2SAmir Ayupov if (Changed) {
376a34c753fSRafael Auler std::lock_guard<std::mutex> Lock(FuncsChangedMutex);
377a34c753fSRafael Auler FuncsChanged.insert(&BF);
37842465efdSRafael Auler LLVM_DEBUG(LogFunc(BF));
379a34c753fSRafael Auler }
380a34c753fSRafael Auler };
381a34c753fSRafael Auler
382a34c753fSRafael Auler ParallelUtilities::runOnEachFunctionWithUniqueAllocId(
383a34c753fSRafael Auler BC, ParallelUtilities::SchedulingPolicy::SP_INST_QUADRATIC, WorkFunction,
384a34c753fSRafael Auler SkipPredicate, "shrink-wrapping");
38542465efdSRafael Auler
38642465efdSRafael Auler if (!Top10Funcs.empty()) {
38752cf0711SAmir Ayupov BC.outs() << "BOLT-INFO: top 10 functions changed by shrink wrapping:\n";
38842465efdSRafael Auler for (const auto &Elmt : Top10Funcs)
38952cf0711SAmir Ayupov BC.outs() << Elmt.first << " : " << Elmt.second->getPrintName() << "\n";
39042465efdSRafael Auler }
39113d60ce2SAmir Ayupov return SWError;
392a34c753fSRafael Auler }
393a34c753fSRafael Auler
394a34c753fSRafael Auler } // namespace bolt
395a34c753fSRafael Auler } // namespace llvm
396