xref: /llvm-project/bolt/lib/Passes/FrameOptimizer.cpp (revision a34c753fe709a624f5b087397fb05adeac2311e4)
1*a34c753fSRafael Auler //===--- Passes/FrameOptimizer.cpp ----------------------------------------===//
2*a34c753fSRafael Auler //
3*a34c753fSRafael Auler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*a34c753fSRafael Auler // See https://llvm.org/LICENSE.txt for license information.
5*a34c753fSRafael Auler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*a34c753fSRafael Auler //
7*a34c753fSRafael Auler //===----------------------------------------------------------------------===//
8*a34c753fSRafael Auler //
9*a34c753fSRafael Auler //===----------------------------------------------------------------------===//
10*a34c753fSRafael Auler 
11*a34c753fSRafael Auler #include "bolt/Passes/FrameOptimizer.h"
12*a34c753fSRafael Auler #include "bolt/Core/ParallelUtilities.h"
13*a34c753fSRafael Auler #include "bolt/Passes/BinaryFunctionCallGraph.h"
14*a34c753fSRafael Auler #include "bolt/Passes/DataflowInfoManager.h"
15*a34c753fSRafael Auler #include "bolt/Passes/ShrinkWrapping.h"
16*a34c753fSRafael Auler #include "bolt/Passes/StackAvailableExpressions.h"
17*a34c753fSRafael Auler #include "bolt/Passes/StackReachingUses.h"
18*a34c753fSRafael Auler #include "llvm/Support/Timer.h"
19*a34c753fSRafael Auler #include <deque>
20*a34c753fSRafael Auler #include <unordered_map>
21*a34c753fSRafael Auler 
22*a34c753fSRafael Auler #define DEBUG_TYPE "fop"
23*a34c753fSRafael Auler 
24*a34c753fSRafael Auler using namespace llvm;
25*a34c753fSRafael Auler 
26*a34c753fSRafael Auler namespace opts {
27*a34c753fSRafael Auler extern cl::opt<unsigned> Verbosity;
28*a34c753fSRafael Auler extern cl::opt<bool> TimeOpts;
29*a34c753fSRafael Auler extern cl::OptionCategory BoltOptCategory;
30*a34c753fSRafael Auler 
31*a34c753fSRafael Auler using namespace bolt;
32*a34c753fSRafael Auler 
33*a34c753fSRafael Auler cl::opt<FrameOptimizationType>
34*a34c753fSRafael Auler FrameOptimization("frame-opt",
35*a34c753fSRafael Auler   cl::init(FOP_NONE),
36*a34c753fSRafael Auler   cl::desc("optimize stack frame accesses"),
37*a34c753fSRafael Auler   cl::values(
38*a34c753fSRafael Auler     clEnumValN(FOP_NONE, "none", "do not perform frame optimization"),
39*a34c753fSRafael Auler     clEnumValN(FOP_HOT, "hot", "perform FOP on hot functions"),
40*a34c753fSRafael Auler     clEnumValN(FOP_ALL, "all", "perform FOP on all functions")),
41*a34c753fSRafael Auler   cl::ZeroOrMore,
42*a34c753fSRafael Auler   cl::cat(BoltOptCategory));
43*a34c753fSRafael Auler 
44*a34c753fSRafael Auler cl::opt<bool>
45*a34c753fSRafael Auler RemoveStores("frame-opt-rm-stores",
46*a34c753fSRafael Auler   cl::init(FOP_NONE),
47*a34c753fSRafael Auler   cl::desc("apply additional analysis to remove stores (experimental)"),
48*a34c753fSRafael Auler   cl::init(false),
49*a34c753fSRafael Auler   cl::ZeroOrMore,
50*a34c753fSRafael Auler   cl::cat(BoltOptCategory));
51*a34c753fSRafael Auler 
52*a34c753fSRafael Auler } // namespace opts
53*a34c753fSRafael Auler 
54*a34c753fSRafael Auler namespace llvm {
55*a34c753fSRafael Auler namespace bolt {
56*a34c753fSRafael Auler 
57*a34c753fSRafael Auler void FrameOptimizerPass::removeUnnecessaryLoads(const RegAnalysis &RA,
58*a34c753fSRafael Auler                                                 const FrameAnalysis &FA,
59*a34c753fSRafael Auler                                                 const BinaryContext &BC,
60*a34c753fSRafael Auler                                                 BinaryFunction &BF) {
61*a34c753fSRafael Auler   StackAvailableExpressions SAE(RA, FA, BC, BF);
62*a34c753fSRafael Auler   SAE.run();
63*a34c753fSRafael Auler 
64*a34c753fSRafael Auler   LLVM_DEBUG(dbgs() << "Performing unnecessary loads removal\n");
65*a34c753fSRafael Auler   std::deque<std::pair<BinaryBasicBlock *, MCInst *>> ToErase;
66*a34c753fSRafael Auler   bool Changed = false;
67*a34c753fSRafael Auler   const auto ExprEnd = SAE.expr_end();
68*a34c753fSRafael Auler   for (BinaryBasicBlock &BB : BF) {
69*a34c753fSRafael Auler     LLVM_DEBUG(dbgs() <<"\tNow at BB " << BB.getName() << "\n");
70*a34c753fSRafael Auler     const MCInst *Prev = nullptr;
71*a34c753fSRafael Auler     for (MCInst &Inst : BB) {
72*a34c753fSRafael Auler       LLVM_DEBUG({
73*a34c753fSRafael Auler         dbgs() << "\t\tNow at ";
74*a34c753fSRafael Auler         Inst.dump();
75*a34c753fSRafael Auler         for (auto I = Prev ? SAE.expr_begin(*Prev) : SAE.expr_begin(BB);
76*a34c753fSRafael Auler              I != ExprEnd; ++I) {
77*a34c753fSRafael Auler           dbgs() << "\t\t\tReached by: ";
78*a34c753fSRafael Auler           (*I)->dump();
79*a34c753fSRafael Auler         }
80*a34c753fSRafael Auler       });
81*a34c753fSRafael Auler       // if Inst is a load from stack and the current available expressions show
82*a34c753fSRafael Auler       // this value is available in a register or immediate, replace this load
83*a34c753fSRafael Auler       // with move from register or from immediate.
84*a34c753fSRafael Auler       ErrorOr<const FrameIndexEntry &> FIEX = FA.getFIEFor(Inst);
85*a34c753fSRafael Auler       if (!FIEX) {
86*a34c753fSRafael Auler         Prev = &Inst;
87*a34c753fSRafael Auler         continue;
88*a34c753fSRafael Auler       }
89*a34c753fSRafael Auler       // FIXME: Change to remove IsSimple == 0. We're being conservative here,
90*a34c753fSRafael Auler       // but once replaceMemOperandWithReg is ready, we should feed it with all
91*a34c753fSRafael Auler       // sorts of complex instructions.
92*a34c753fSRafael Auler       if (FIEX->IsLoad == false || FIEX->IsSimple == false ||
93*a34c753fSRafael Auler           FIEX->StackOffset >= 0) {
94*a34c753fSRafael Auler         Prev = &Inst;
95*a34c753fSRafael Auler         continue;
96*a34c753fSRafael Auler       }
97*a34c753fSRafael Auler 
98*a34c753fSRafael Auler       for (auto I = Prev ? SAE.expr_begin(*Prev) : SAE.expr_begin(BB);
99*a34c753fSRafael Auler            I != ExprEnd; ++I) {
100*a34c753fSRafael Auler         const MCInst *AvailableInst = *I;
101*a34c753fSRafael Auler         ErrorOr<const FrameIndexEntry &> FIEY = FA.getFIEFor(*AvailableInst);
102*a34c753fSRafael Auler         if (!FIEY)
103*a34c753fSRafael Auler           continue;
104*a34c753fSRafael Auler         assert(FIEY->IsStore && FIEY->IsSimple);
105*a34c753fSRafael Auler         if (FIEX->StackOffset != FIEY->StackOffset || FIEX->Size != FIEY->Size)
106*a34c753fSRafael Auler           continue;
107*a34c753fSRafael Auler         // TODO: Change push/pops to stack adjustment instruction
108*a34c753fSRafael Auler         if (BC.MIB->isPop(Inst))
109*a34c753fSRafael Auler           continue;
110*a34c753fSRafael Auler 
111*a34c753fSRafael Auler         ++NumRedundantLoads;
112*a34c753fSRafael Auler         Changed = true;
113*a34c753fSRafael Auler         LLVM_DEBUG(dbgs() << "Redundant load instruction: ");
114*a34c753fSRafael Auler         LLVM_DEBUG(Inst.dump());
115*a34c753fSRafael Auler         LLVM_DEBUG(dbgs() << "Related store instruction: ");
116*a34c753fSRafael Auler         LLVM_DEBUG(AvailableInst->dump());
117*a34c753fSRafael Auler         LLVM_DEBUG(dbgs() << "@BB: " << BB.getName() << "\n");
118*a34c753fSRafael Auler         // Replace load
119*a34c753fSRafael Auler         if (FIEY->IsStoreFromReg) {
120*a34c753fSRafael Auler           if (!BC.MIB->replaceMemOperandWithReg(Inst, FIEY->RegOrImm)) {
121*a34c753fSRafael Auler             LLVM_DEBUG(dbgs() << "FAILED to change operand to a reg\n");
122*a34c753fSRafael Auler             break;
123*a34c753fSRafael Auler           }
124*a34c753fSRafael Auler           ++NumLoadsChangedToReg;
125*a34c753fSRafael Auler           BC.MIB->removeAnnotation(Inst, "FrameAccessEntry");
126*a34c753fSRafael Auler           LLVM_DEBUG(dbgs() << "Changed operand to a reg\n");
127*a34c753fSRafael Auler           if (BC.MIB->isRedundantMove(Inst)) {
128*a34c753fSRafael Auler             ++NumLoadsDeleted;
129*a34c753fSRafael Auler             LLVM_DEBUG(dbgs() << "Created a redundant move\n");
130*a34c753fSRafael Auler             // Delete it!
131*a34c753fSRafael Auler             ToErase.push_front(std::make_pair(&BB, &Inst));
132*a34c753fSRafael Auler           }
133*a34c753fSRafael Auler         } else {
134*a34c753fSRafael Auler           char Buf[8] = {0, 0, 0, 0, 0, 0, 0, 0};
135*a34c753fSRafael Auler           support::ulittle64_t::ref(Buf + 0) = FIEY->RegOrImm;
136*a34c753fSRafael Auler           LLVM_DEBUG(dbgs() << "Changing operand to an imm... ");
137*a34c753fSRafael Auler           if (!BC.MIB->replaceMemOperandWithImm(Inst, StringRef(Buf, 8), 0)) {
138*a34c753fSRafael Auler             LLVM_DEBUG(dbgs() << "FAILED\n");
139*a34c753fSRafael Auler           } else {
140*a34c753fSRafael Auler             ++NumLoadsChangedToImm;
141*a34c753fSRafael Auler             BC.MIB->removeAnnotation(Inst, "FrameAccessEntry");
142*a34c753fSRafael Auler             LLVM_DEBUG(dbgs() << "Ok\n");
143*a34c753fSRafael Auler           }
144*a34c753fSRafael Auler         }
145*a34c753fSRafael Auler         LLVM_DEBUG(dbgs() << "Changed to: ");
146*a34c753fSRafael Auler         LLVM_DEBUG(Inst.dump());
147*a34c753fSRafael Auler         break;
148*a34c753fSRafael Auler       }
149*a34c753fSRafael Auler       Prev = &Inst;
150*a34c753fSRafael Auler     }
151*a34c753fSRafael Auler   }
152*a34c753fSRafael Auler   if (Changed) {
153*a34c753fSRafael Auler     LLVM_DEBUG(dbgs() << "FOP modified \"" << BF.getPrintName() << "\"\n");
154*a34c753fSRafael Auler   }
155*a34c753fSRafael Auler   // TODO: Implement an interface of eraseInstruction that works out the
156*a34c753fSRafael Auler   // complete list of elements to remove.
157*a34c753fSRafael Auler   for (std::pair<BinaryBasicBlock *, MCInst *> I : ToErase) {
158*a34c753fSRafael Auler     I.first->eraseInstruction(I.first->findInstruction(I.second));
159*a34c753fSRafael Auler   }
160*a34c753fSRafael Auler }
161*a34c753fSRafael Auler 
162*a34c753fSRafael Auler void FrameOptimizerPass::removeUnusedStores(const FrameAnalysis &FA,
163*a34c753fSRafael Auler                                             const BinaryContext &BC,
164*a34c753fSRafael Auler                                             BinaryFunction &BF) {
165*a34c753fSRafael Auler   StackReachingUses SRU(FA, BC, BF);
166*a34c753fSRafael Auler   SRU.run();
167*a34c753fSRafael Auler 
168*a34c753fSRafael Auler   LLVM_DEBUG(dbgs() << "Performing unused stores removal\n");
169*a34c753fSRafael Auler   std::vector<std::pair<BinaryBasicBlock *, MCInst *>> ToErase;
170*a34c753fSRafael Auler   bool Changed = false;
171*a34c753fSRafael Auler   for (BinaryBasicBlock &BB : BF) {
172*a34c753fSRafael Auler     LLVM_DEBUG(dbgs() <<"\tNow at BB " << BB.getName() << "\n");
173*a34c753fSRafael Auler     const MCInst *Prev = nullptr;
174*a34c753fSRafael Auler     for (auto I = BB.rbegin(), E = BB.rend(); I != E; ++I) {
175*a34c753fSRafael Auler       MCInst &Inst = *I;
176*a34c753fSRafael Auler       LLVM_DEBUG({
177*a34c753fSRafael Auler         dbgs() << "\t\tNow at ";
178*a34c753fSRafael Auler         Inst.dump();
179*a34c753fSRafael Auler         for (auto I = Prev ? SRU.expr_begin(*Prev) : SRU.expr_begin(BB);
180*a34c753fSRafael Auler              I != SRU.expr_end(); ++I) {
181*a34c753fSRafael Auler           dbgs() << "\t\t\tReached by: ";
182*a34c753fSRafael Auler           (*I)->dump();
183*a34c753fSRafael Auler         }
184*a34c753fSRafael Auler       });
185*a34c753fSRafael Auler       ErrorOr<const FrameIndexEntry &> FIEX = FA.getFIEFor(Inst);
186*a34c753fSRafael Auler       if (!FIEX) {
187*a34c753fSRafael Auler         Prev = &Inst;
188*a34c753fSRafael Auler         continue;
189*a34c753fSRafael Auler       }
190*a34c753fSRafael Auler       if (FIEX->IsLoad || !FIEX->IsSimple || FIEX->StackOffset >= 0) {
191*a34c753fSRafael Auler         Prev = &Inst;
192*a34c753fSRafael Auler         continue;
193*a34c753fSRafael Auler       }
194*a34c753fSRafael Auler 
195*a34c753fSRafael Auler       if (SRU.isStoreUsed(*FIEX,
196*a34c753fSRafael Auler                           Prev ? SRU.expr_begin(*Prev) : SRU.expr_begin(BB))) {
197*a34c753fSRafael Auler         Prev = &Inst;
198*a34c753fSRafael Auler         continue;
199*a34c753fSRafael Auler       }
200*a34c753fSRafael Auler       // TODO: Change push/pops to stack adjustment instruction
201*a34c753fSRafael Auler       if (BC.MIB->isPush(Inst))
202*a34c753fSRafael Auler         continue;
203*a34c753fSRafael Auler 
204*a34c753fSRafael Auler       ++NumRedundantStores;
205*a34c753fSRafael Auler       Changed = true;
206*a34c753fSRafael Auler       LLVM_DEBUG(dbgs() << "Unused store instruction: ");
207*a34c753fSRafael Auler       LLVM_DEBUG(Inst.dump());
208*a34c753fSRafael Auler       LLVM_DEBUG(dbgs() << "@BB: " << BB.getName() << "\n");
209*a34c753fSRafael Auler       LLVM_DEBUG(dbgs() << "FIE offset = " << FIEX->StackOffset
210*a34c753fSRafael Auler                    << " size = " << (int)FIEX->Size << "\n");
211*a34c753fSRafael Auler       // Delete it!
212*a34c753fSRafael Auler       ToErase.emplace_back(&BB, &Inst);
213*a34c753fSRafael Auler       Prev = &Inst;
214*a34c753fSRafael Auler     }
215*a34c753fSRafael Auler   }
216*a34c753fSRafael Auler 
217*a34c753fSRafael Auler   for (std::pair<BinaryBasicBlock *, MCInst *> I : ToErase) {
218*a34c753fSRafael Auler     I.first->eraseInstruction(I.first->findInstruction(I.second));
219*a34c753fSRafael Auler   }
220*a34c753fSRafael Auler   if (Changed) {
221*a34c753fSRafael Auler     LLVM_DEBUG(dbgs() << "FOP modified \"" << BF.getPrintName() << "\"\n");
222*a34c753fSRafael Auler   }
223*a34c753fSRafael Auler }
224*a34c753fSRafael Auler 
225*a34c753fSRafael Auler void FrameOptimizerPass::runOnFunctions(BinaryContext &BC) {
226*a34c753fSRafael Auler   if (opts::FrameOptimization == FOP_NONE)
227*a34c753fSRafael Auler     return;
228*a34c753fSRafael Auler 
229*a34c753fSRafael Auler   std::unique_ptr<BinaryFunctionCallGraph> CG;
230*a34c753fSRafael Auler   std::unique_ptr<FrameAnalysis> FA;
231*a34c753fSRafael Auler   std::unique_ptr<RegAnalysis> RA;
232*a34c753fSRafael Auler 
233*a34c753fSRafael Auler   {
234*a34c753fSRafael Auler     NamedRegionTimer T1("callgraph", "create call graph", "FOP",
235*a34c753fSRafael Auler                         "FOP breakdown", opts::TimeOpts);
236*a34c753fSRafael Auler     CG = std::make_unique<BinaryFunctionCallGraph>(buildCallGraph(BC));
237*a34c753fSRafael Auler   }
238*a34c753fSRafael Auler 
239*a34c753fSRafael Auler   {
240*a34c753fSRafael Auler     NamedRegionTimer T1("frameanalysis", "frame analysis", "FOP",
241*a34c753fSRafael Auler                         "FOP breakdown", opts::TimeOpts);
242*a34c753fSRafael Auler     FA = std::make_unique<FrameAnalysis>(BC, *CG);
243*a34c753fSRafael Auler   }
244*a34c753fSRafael Auler 
245*a34c753fSRafael Auler   {
246*a34c753fSRafael Auler     NamedRegionTimer T1("reganalysis", "reg analysis", "FOP",
247*a34c753fSRafael Auler                         "FOP breakdown", opts::TimeOpts);
248*a34c753fSRafael Auler     RA = std::make_unique<RegAnalysis>(BC, &BC.getBinaryFunctions(), CG.get());
249*a34c753fSRafael Auler   }
250*a34c753fSRafael Auler 
251*a34c753fSRafael Auler   // Perform caller-saved register optimizations, then callee-saved register
252*a34c753fSRafael Auler   // optimizations (shrink wrapping)
253*a34c753fSRafael Auler   for (auto &I : BC.getBinaryFunctions()) {
254*a34c753fSRafael Auler     if (!FA->hasFrameInfo(I.second))
255*a34c753fSRafael Auler       continue;
256*a34c753fSRafael Auler     // Restrict pass execution if user asked to only run on hot functions
257*a34c753fSRafael Auler     if (opts::FrameOptimization == FOP_HOT) {
258*a34c753fSRafael Auler       if (I.second.getKnownExecutionCount() < BC.getHotThreshold())
259*a34c753fSRafael Auler         continue;
260*a34c753fSRafael Auler       LLVM_DEBUG(
261*a34c753fSRafael Auler           dbgs() << "Considering " << I.second.getPrintName()
262*a34c753fSRafael Auler                  << " for frame optimizations because its execution count ( "
263*a34c753fSRafael Auler                  << I.second.getKnownExecutionCount()
264*a34c753fSRafael Auler                  << " ) exceeds our hotness threshold ( "
265*a34c753fSRafael Auler                  << BC.getHotThreshold() << " )\n");
266*a34c753fSRafael Auler     }
267*a34c753fSRafael Auler 
268*a34c753fSRafael Auler     {
269*a34c753fSRafael Auler       NamedRegionTimer T1("removeloads", "remove loads", "FOP", "FOP breakdown",
270*a34c753fSRafael Auler                           opts::TimeOpts);
271*a34c753fSRafael Auler       removeUnnecessaryLoads(*RA, *FA, BC, I.second);
272*a34c753fSRafael Auler     }
273*a34c753fSRafael Auler 
274*a34c753fSRafael Auler     if (opts::RemoveStores) {
275*a34c753fSRafael Auler       NamedRegionTimer T1("removestores", "remove stores", "FOP",
276*a34c753fSRafael Auler                           "FOP breakdown", opts::TimeOpts);
277*a34c753fSRafael Auler       removeUnusedStores(*FA, BC, I.second);
278*a34c753fSRafael Auler     }
279*a34c753fSRafael Auler     // Don't even start shrink wrapping if no profiling info is available
280*a34c753fSRafael Auler     if (I.second.getKnownExecutionCount() == 0)
281*a34c753fSRafael Auler       continue;
282*a34c753fSRafael Auler 
283*a34c753fSRafael Auler   }
284*a34c753fSRafael Auler 
285*a34c753fSRafael Auler   {
286*a34c753fSRafael Auler     NamedRegionTimer T1("shrinkwrapping", "shrink wrapping", "FOP",
287*a34c753fSRafael Auler                         "FOP breakdown", opts::TimeOpts);
288*a34c753fSRafael Auler     performShrinkWrapping(*RA, *FA, BC);
289*a34c753fSRafael Auler   }
290*a34c753fSRafael Auler 
291*a34c753fSRafael Auler   outs() << "BOLT-INFO: FOP optimized " << NumRedundantLoads
292*a34c753fSRafael Auler          << " redundant load(s) and " << NumRedundantStores
293*a34c753fSRafael Auler          << " unused store(s)\n";
294*a34c753fSRafael Auler   outs() << "BOLT-INFO: FOP changed " << NumLoadsChangedToReg
295*a34c753fSRafael Auler          << " load(s) to use a register instead of a stack access, and "
296*a34c753fSRafael Auler          << NumLoadsChangedToImm << " to use an immediate.\n"
297*a34c753fSRafael Auler          << "BOLT-INFO: FOP deleted " << NumLoadsDeleted << " load(s) and "
298*a34c753fSRafael Auler          << NumRedundantStores << " store(s).\n";
299*a34c753fSRafael Auler   FA->printStats();
300*a34c753fSRafael Auler   ShrinkWrapping::printStats();
301*a34c753fSRafael Auler }
302*a34c753fSRafael Auler 
303*a34c753fSRafael Auler void FrameOptimizerPass::performShrinkWrapping(const RegAnalysis &RA,
304*a34c753fSRafael Auler                                                const FrameAnalysis &FA,
305*a34c753fSRafael Auler                                                BinaryContext &BC) {
306*a34c753fSRafael Auler   // Initialize necessary annotations to allow safe parallel accesses to
307*a34c753fSRafael Auler   // annotation index in MIB
308*a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex(CalleeSavedAnalysis::getSaveTagName());
309*a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex(CalleeSavedAnalysis::getRestoreTagName());
310*a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex(StackLayoutModifier::getTodoTagName());
311*a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex(StackLayoutModifier::getSlotTagName());
312*a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex(
313*a34c753fSRafael Auler       StackLayoutModifier::getOffsetCFIRegTagName());
314*a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("ReachingDefs");
315*a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("ReachingUses");
316*a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("LivenessAnalysis");
317*a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("StackReachingUses");
318*a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("PostDominatorAnalysis");
319*a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("DominatorAnalysis");
320*a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("StackPointerTracking");
321*a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("StackPointerTrackingForInternalCalls");
322*a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("StackAvailableExpressions");
323*a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("StackAllocationAnalysis");
324*a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("ShrinkWrap-Todo");
325*a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("PredictiveStackPointerTracking");
326*a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("ReachingInsnsBackward");
327*a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("ReachingInsns");
328*a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("AccessesDeletedPos");
329*a34c753fSRafael Auler   BC.MIB->getOrCreateAnnotationIndex("DeleteMe");
330*a34c753fSRafael Auler 
331*a34c753fSRafael Auler   ParallelUtilities::PredicateTy SkipPredicate = [&](const BinaryFunction &BF) {
332*a34c753fSRafael Auler     if (!FA.hasFrameInfo(BF))
333*a34c753fSRafael Auler       return true;
334*a34c753fSRafael Auler 
335*a34c753fSRafael Auler     if (opts::FrameOptimization == FOP_HOT &&
336*a34c753fSRafael Auler         (BF.getKnownExecutionCount() < BC.getHotThreshold()))
337*a34c753fSRafael Auler       return true;
338*a34c753fSRafael Auler 
339*a34c753fSRafael Auler     if (BF.getKnownExecutionCount() == 0)
340*a34c753fSRafael Auler       return true;
341*a34c753fSRafael Auler 
342*a34c753fSRafael Auler     return false;
343*a34c753fSRafael Auler   };
344*a34c753fSRafael Auler 
345*a34c753fSRafael Auler   ParallelUtilities::WorkFuncWithAllocTy WorkFunction =
346*a34c753fSRafael Auler       [&](BinaryFunction &BF, MCPlusBuilder::AllocatorIdTy AllocatorId) {
347*a34c753fSRafael Auler         DataflowInfoManager Info(BC, BF, &RA, &FA, AllocatorId);
348*a34c753fSRafael Auler         ShrinkWrapping SW(FA, BC, BF, Info, AllocatorId);
349*a34c753fSRafael Auler 
350*a34c753fSRafael Auler         if (SW.perform()) {
351*a34c753fSRafael Auler           std::lock_guard<std::mutex> Lock(FuncsChangedMutex);
352*a34c753fSRafael Auler           FuncsChanged.insert(&BF);
353*a34c753fSRafael Auler         }
354*a34c753fSRafael Auler       };
355*a34c753fSRafael Auler 
356*a34c753fSRafael Auler   ParallelUtilities::runOnEachFunctionWithUniqueAllocId(
357*a34c753fSRafael Auler       BC, ParallelUtilities::SchedulingPolicy::SP_INST_QUADRATIC, WorkFunction,
358*a34c753fSRafael Auler       SkipPredicate, "shrink-wrapping");
359*a34c753fSRafael Auler }
360*a34c753fSRafael Auler 
361*a34c753fSRafael Auler } // namespace bolt
362*a34c753fSRafael Auler } // namespace llvm
363