12f09f445SMaksim Panchenko //===- bolt/Passes/SplitFunctions.cpp - Pass for splitting function code --===//
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 SplitFunctions pass.
102f09f445SMaksim Panchenko //
11a34c753fSRafael Auler //===----------------------------------------------------------------------===//
12a34c753fSRafael Auler 
13a34c753fSRafael Auler #include "bolt/Passes/SplitFunctions.h"
14a34c753fSRafael Auler #include "bolt/Core/BinaryFunction.h"
15a34c753fSRafael Auler #include "bolt/Core/ParallelUtilities.h"
16a34c753fSRafael Auler #include "llvm/Support/CommandLine.h"
1796f6ec50SFabian Parzefall #include "llvm/Support/FormatVariadic.h"
18e341e9f0SFabian Parzefall #include <algorithm>
19e341e9f0SFabian Parzefall #include <random>
20a34c753fSRafael Auler #include <vector>
21a34c753fSRafael Auler 
22a34c753fSRafael Auler #define DEBUG_TYPE "bolt-opts"
23a34c753fSRafael Auler 
24a34c753fSRafael Auler using namespace llvm;
25a34c753fSRafael Auler using namespace bolt;
26a34c753fSRafael Auler 
2796f6ec50SFabian Parzefall namespace {
2896f6ec50SFabian Parzefall class DeprecatedSplitFunctionOptionParser : public cl::parser<bool> {
2996f6ec50SFabian Parzefall public:
DeprecatedSplitFunctionOptionParser(cl::Option & O)3096f6ec50SFabian Parzefall   explicit DeprecatedSplitFunctionOptionParser(cl::Option &O)
3196f6ec50SFabian Parzefall       : cl::parser<bool>(O) {}
3296f6ec50SFabian Parzefall 
parse(cl::Option & O,StringRef ArgName,StringRef Arg,bool & Value)3396f6ec50SFabian Parzefall   bool parse(cl::Option &O, StringRef ArgName, StringRef Arg, bool &Value) {
3496f6ec50SFabian Parzefall     if (Arg == "2" || Arg == "3") {
3596f6ec50SFabian Parzefall       Value = true;
3696f6ec50SFabian Parzefall       errs() << formatv("BOLT-WARNING: specifying non-boolean value \"{0}\" "
3796f6ec50SFabian Parzefall                         "for option -{1} is deprecated\n",
3896f6ec50SFabian Parzefall                         Arg, ArgName);
3996f6ec50SFabian Parzefall       return false;
4096f6ec50SFabian Parzefall     }
4196f6ec50SFabian Parzefall     return cl::parser<bool>::parse(O, ArgName, Arg, Value);
4296f6ec50SFabian Parzefall   }
4396f6ec50SFabian Parzefall };
4496f6ec50SFabian Parzefall } // namespace
4596f6ec50SFabian Parzefall 
46a34c753fSRafael Auler namespace opts {
47a34c753fSRafael Auler 
48a34c753fSRafael Auler extern cl::OptionCategory BoltOptCategory;
49a34c753fSRafael Auler 
50a34c753fSRafael Auler extern cl::opt<bool> SplitEH;
51a34c753fSRafael Auler extern cl::opt<unsigned> ExecutionCountThreshold;
52e341e9f0SFabian Parzefall extern cl::opt<uint32_t> RandomSeed;
53a34c753fSRafael Auler 
54b92436efSFangrui Song static cl::opt<bool> AggressiveSplitting(
55b92436efSFangrui Song     "split-all-cold", cl::desc("outline as many cold basic blocks as possible"),
56a34c753fSRafael Auler     cl::cat(BoltOptCategory));
57a34c753fSRafael Auler 
58b92436efSFangrui Song static cl::opt<unsigned> SplitAlignThreshold(
59b92436efSFangrui Song     "split-align-threshold",
60a34c753fSRafael Auler     cl::desc("when deciding to split a function, apply this alignment "
61a34c753fSRafael Auler              "while doing the size comparison (see -split-threshold). "
62a34c753fSRafael Auler              "Default value: 2."),
63a34c753fSRafael Auler     cl::init(2),
64b92436efSFangrui Song 
65b92436efSFangrui Song     cl::Hidden, cl::cat(BoltOptCategory));
66a34c753fSRafael Auler 
6796f6ec50SFabian Parzefall static cl::opt<bool, false, DeprecatedSplitFunctionOptionParser>
68a34c753fSRafael Auler     SplitFunctions("split-functions",
69a34c753fSRafael Auler                    cl::desc("split functions into hot and cold regions"),
70a34c753fSRafael Auler                    cl::cat(BoltOptCategory));
71a34c753fSRafael Auler 
72b92436efSFangrui Song static cl::opt<unsigned> SplitThreshold(
73b92436efSFangrui Song     "split-threshold",
74a34c753fSRafael Auler     cl::desc("split function only if its main size is reduced by more than "
75a34c753fSRafael Auler              "given amount of bytes. Default value: 0, i.e. split iff the "
76a34c753fSRafael Auler              "size is reduced. Note that on some architectures the size can "
77a34c753fSRafael Auler              "increase after splitting."),
78b92436efSFangrui Song     cl::init(0), cl::Hidden, cl::cat(BoltOptCategory));
79a34c753fSRafael Auler 
80e341e9f0SFabian Parzefall static cl::opt<bool>
81e341e9f0SFabian Parzefall     RandomSplit("split-random",
82e341e9f0SFabian Parzefall                 cl::desc("split functions randomly into hot/cold regions"),
83e341e9f0SFabian Parzefall                 cl::Hidden);
84a34c753fSRafael Auler } // namespace opts
85a34c753fSRafael Auler 
86e341e9f0SFabian Parzefall namespace {
87e341e9f0SFabian Parzefall struct SplitCold {
canSplit__anonbffea4b90211::SplitCold88e341e9f0SFabian Parzefall   bool canSplit(const BinaryFunction &BF) {
89e341e9f0SFabian Parzefall     if (!BF.hasValidProfile())
90e341e9f0SFabian Parzefall       return false;
91e341e9f0SFabian Parzefall 
92e341e9f0SFabian Parzefall     bool AllCold = true;
93d55dfeafSFabian Parzefall     for (const BinaryBasicBlock &BB : BF) {
94d55dfeafSFabian Parzefall       const uint64_t ExecCount = BB.getExecutionCount();
95e341e9f0SFabian Parzefall       if (ExecCount == BinaryBasicBlock::COUNT_NO_PROFILE)
96e341e9f0SFabian Parzefall         return false;
97e341e9f0SFabian Parzefall       if (ExecCount != 0)
98e341e9f0SFabian Parzefall         AllCold = false;
99e341e9f0SFabian Parzefall     }
100e341e9f0SFabian Parzefall 
101e341e9f0SFabian Parzefall     return !AllCold;
102e341e9f0SFabian Parzefall   }
103e341e9f0SFabian Parzefall 
canOutline__anonbffea4b90211::SplitCold104e341e9f0SFabian Parzefall   bool canOutline(const BinaryBasicBlock &BB) {
105e341e9f0SFabian Parzefall     return BB.getExecutionCount() == 0;
106e341e9f0SFabian Parzefall   }
107e341e9f0SFabian Parzefall 
partition__anonbffea4b90211::SplitCold108*8477bc67SFabian Parzefall   template <typename It> void partition(const It Start, const It End) const {
109e341e9f0SFabian Parzefall     for (auto I = Start; I != End; ++I) {
110e341e9f0SFabian Parzefall       BinaryBasicBlock *BB = *I;
111e341e9f0SFabian Parzefall       if (!BB->canOutline())
112e341e9f0SFabian Parzefall         break;
113e341e9f0SFabian Parzefall       BB->setIsCold(true);
114e341e9f0SFabian Parzefall     }
115e341e9f0SFabian Parzefall   }
116e341e9f0SFabian Parzefall };
117e341e9f0SFabian Parzefall 
118e341e9f0SFabian Parzefall struct SplitRandom {
119e341e9f0SFabian Parzefall   std::minstd_rand0 *Gen;
120e341e9f0SFabian Parzefall 
SplitRandom__anonbffea4b90211::SplitRandom121e341e9f0SFabian Parzefall   explicit SplitRandom(std::minstd_rand0 &Gen) : Gen(&Gen) {}
122e341e9f0SFabian Parzefall 
canSplit__anonbffea4b90211::SplitRandom123e341e9f0SFabian Parzefall   bool canSplit(const BinaryFunction &BF) { return true; }
canOutline__anonbffea4b90211::SplitRandom124e341e9f0SFabian Parzefall   bool canOutline(const BinaryBasicBlock &BB) { return true; }
125e341e9f0SFabian Parzefall 
partition__anonbffea4b90211::SplitRandom126*8477bc67SFabian Parzefall   template <typename It> void partition(It Start, It End) const {
127*8477bc67SFabian Parzefall     using DiffT = typename It::difference_type;
128e341e9f0SFabian Parzefall 
129e341e9f0SFabian Parzefall     const It OutlineableBegin = Start;
130e341e9f0SFabian Parzefall     const It OutlineableEnd =
131*8477bc67SFabian Parzefall         std::find_if(OutlineableBegin, End, [](const BinaryBasicBlock *BB) {
132*8477bc67SFabian Parzefall           return !BB->canOutline();
133*8477bc67SFabian Parzefall         });
134*8477bc67SFabian Parzefall     const DiffT NumOutlineableBlocks = OutlineableEnd - OutlineableBegin;
135e341e9f0SFabian Parzefall 
136e341e9f0SFabian Parzefall     // We want to split at least one block unless there are not blocks that can
137e341e9f0SFabian Parzefall     // be outlined
138*8477bc67SFabian Parzefall     const auto MinimumSplit = std::min<DiffT>(NumOutlineableBlocks, 1);
139*8477bc67SFabian Parzefall     std::uniform_int_distribution<DiffT> Dist(MinimumSplit,
140*8477bc67SFabian Parzefall                                               NumOutlineableBlocks);
141*8477bc67SFabian Parzefall     const DiffT NumColdBlocks = Dist(*Gen);
142e341e9f0SFabian Parzefall     const It ColdEnd = OutlineableBegin + NumColdBlocks;
143e341e9f0SFabian Parzefall 
144e341e9f0SFabian Parzefall     LLVM_DEBUG(dbgs() << formatv("BOLT-DEBUG: randomly chose last {0} (out of "
145e341e9f0SFabian Parzefall                                  "{1} possible) blocks to split\n",
146e341e9f0SFabian Parzefall                                  ColdEnd - OutlineableBegin,
147e341e9f0SFabian Parzefall                                  OutlineableEnd - OutlineableBegin));
148e341e9f0SFabian Parzefall 
149e341e9f0SFabian Parzefall     std::for_each(OutlineableBegin, ColdEnd,
150e341e9f0SFabian Parzefall                   [](BinaryBasicBlock *BB) { BB->setIsCold(true); });
151e341e9f0SFabian Parzefall   }
152e341e9f0SFabian Parzefall };
153e341e9f0SFabian Parzefall } // namespace
154e341e9f0SFabian Parzefall 
155a34c753fSRafael Auler namespace llvm {
156a34c753fSRafael Auler namespace bolt {
157a34c753fSRafael Auler 
shouldOptimize(const BinaryFunction & BF) const158a34c753fSRafael Auler bool SplitFunctions::shouldOptimize(const BinaryFunction &BF) const {
159a34c753fSRafael Auler   // Apply execution count threshold
160a34c753fSRafael Auler   if (BF.getKnownExecutionCount() < opts::ExecutionCountThreshold)
161a34c753fSRafael Auler     return false;
162a34c753fSRafael Auler 
163a34c753fSRafael Auler   return BinaryFunctionPass::shouldOptimize(BF);
164a34c753fSRafael Auler }
165a34c753fSRafael Auler 
runOnFunctions(BinaryContext & BC)166a34c753fSRafael Auler void SplitFunctions::runOnFunctions(BinaryContext &BC) {
16796f6ec50SFabian Parzefall   if (!opts::SplitFunctions)
168a34c753fSRafael Auler     return;
169a34c753fSRafael Auler 
170e341e9f0SFabian Parzefall   ParallelUtilities::WorkFuncTy WorkFun;
171e341e9f0SFabian Parzefall   std::minstd_rand0 RandGen(opts::RandomSeed.getValue());
172e341e9f0SFabian Parzefall   if (opts::RandomSplit)
173e341e9f0SFabian Parzefall     WorkFun = [&](BinaryFunction &BF) {
174e341e9f0SFabian Parzefall       splitFunction(BF, SplitRandom(RandGen));
175a34c753fSRafael Auler     };
176e341e9f0SFabian Parzefall   else
177e341e9f0SFabian Parzefall     WorkFun = [&](BinaryFunction &BF) { splitFunction<SplitCold>(BF); };
178a34c753fSRafael Auler 
179a34c753fSRafael Auler   ParallelUtilities::PredicateTy SkipFunc = [&](const BinaryFunction &BF) {
180a34c753fSRafael Auler     return !shouldOptimize(BF);
181a34c753fSRafael Auler   };
182a34c753fSRafael Auler 
183e341e9f0SFabian Parzefall   // If we split functions randomly, we need to ensure that across runs with the
184e341e9f0SFabian Parzefall   // same input, we generate random numbers for each function in the same order.
185e341e9f0SFabian Parzefall   const bool ForceSequential = opts::RandomSplit;
186e341e9f0SFabian Parzefall 
187a34c753fSRafael Auler   ParallelUtilities::runOnEachFunction(
188a34c753fSRafael Auler       BC, ParallelUtilities::SchedulingPolicy::SP_BB_LINEAR, WorkFun, SkipFunc,
189e341e9f0SFabian Parzefall       "SplitFunctions", ForceSequential);
190a34c753fSRafael Auler 
191f92ab6afSAmir Ayupov   if (SplitBytesHot + SplitBytesCold > 0)
192a34c753fSRafael Auler     outs() << "BOLT-INFO: splitting separates " << SplitBytesHot
193a34c753fSRafael Auler            << " hot bytes from " << SplitBytesCold << " cold bytes "
194a34c753fSRafael Auler            << format("(%.2lf%% of split functions is hot).\n",
195a34c753fSRafael Auler                      100.0 * SplitBytesHot / (SplitBytesHot + SplitBytesCold));
196a34c753fSRafael Auler }
197a34c753fSRafael Auler 
198e341e9f0SFabian Parzefall template <typename SplitStrategy>
splitFunction(BinaryFunction & BF,SplitStrategy Strategy)199e341e9f0SFabian Parzefall void SplitFunctions::splitFunction(BinaryFunction &BF, SplitStrategy Strategy) {
200e341e9f0SFabian Parzefall   if (BF.empty())
201a34c753fSRafael Auler     return;
202a34c753fSRafael Auler 
203e341e9f0SFabian Parzefall   if (!Strategy.canSplit(BF))
204a34c753fSRafael Auler     return;
205a34c753fSRafael Auler 
206*8477bc67SFabian Parzefall   FunctionLayout &Layout = BF.getLayout();
207*8477bc67SFabian Parzefall   BinaryFunction::BasicBlockOrderType PreSplitLayout(Layout.block_begin(),
208*8477bc67SFabian Parzefall                                                      Layout.block_end());
209a34c753fSRafael Auler 
210a34c753fSRafael Auler   BinaryContext &BC = BF.getBinaryContext();
211a34c753fSRafael Auler   size_t OriginalHotSize;
212a34c753fSRafael Auler   size_t HotSize;
213a34c753fSRafael Auler   size_t ColdSize;
214a34c753fSRafael Auler   if (BC.isX86()) {
215a34c753fSRafael Auler     std::tie(OriginalHotSize, ColdSize) = BC.calculateEmittedSize(BF);
216a34c753fSRafael Auler     LLVM_DEBUG(dbgs() << "Estimated size for function " << BF
217a34c753fSRafael Auler                       << " pre-split is <0x"
218a34c753fSRafael Auler                       << Twine::utohexstr(OriginalHotSize) << ", 0x"
219a34c753fSRafael Auler                       << Twine::utohexstr(ColdSize) << ">\n");
220f263a66bSMaksim Panchenko   }
221a34c753fSRafael Auler 
222*8477bc67SFabian Parzefall   BinaryFunction::BasicBlockOrderType NewLayout(Layout.block_begin(),
223*8477bc67SFabian Parzefall                                                 Layout.block_end());
224a34c753fSRafael Auler   // Never outline the first basic block.
225*8477bc67SFabian Parzefall   NewLayout.front()->setCanOutline(false);
226*8477bc67SFabian Parzefall   for (BinaryBasicBlock *const BB : NewLayout) {
227a34c753fSRafael Auler     if (!BB->canOutline())
228a34c753fSRafael Auler       continue;
229e341e9f0SFabian Parzefall     if (!Strategy.canOutline(*BB)) {
230a34c753fSRafael Auler       BB->setCanOutline(false);
231a34c753fSRafael Auler       continue;
232a34c753fSRafael Auler     }
233a34c753fSRafael Auler     // Do not split extra entry points in aarch64. They can be referred by
234a34c753fSRafael Auler     // using ADRs and when this happens, these blocks cannot be placed far
235a34c753fSRafael Auler     // away due to the limited range in ADR instruction.
236a34c753fSRafael Auler     if (BC.isAArch64() && BB->isEntryPoint()) {
237a34c753fSRafael Auler       BB->setCanOutline(false);
238a34c753fSRafael Auler       continue;
239a34c753fSRafael Auler     }
240f263a66bSMaksim Panchenko 
241a34c753fSRafael Auler     if (BF.hasEHRanges() && !opts::SplitEH) {
242f263a66bSMaksim Panchenko       // We cannot move landing pads (or rather entry points for landing pads).
243a34c753fSRafael Auler       if (BB->isLandingPad()) {
244a34c753fSRafael Auler         BB->setCanOutline(false);
245a34c753fSRafael Auler         continue;
246a34c753fSRafael Auler       }
247a34c753fSRafael Auler       // We cannot move a block that can throw since exception-handling
248a34c753fSRafael Auler       // runtime cannot deal with split functions. However, if we can guarantee
249a34c753fSRafael Auler       // that the block never throws, it is safe to move the block to
250a34c753fSRafael Auler       // decrease the size of the function.
251a34c753fSRafael Auler       for (MCInst &Instr : *BB) {
252f263a66bSMaksim Panchenko         if (BC.MIB->isInvoke(Instr)) {
253a34c753fSRafael Auler           BB->setCanOutline(false);
254a34c753fSRafael Auler           break;
255a34c753fSRafael Auler         }
256a34c753fSRafael Auler       }
257a34c753fSRafael Auler     }
258a34c753fSRafael Auler   }
259a34c753fSRafael Auler 
260a34c753fSRafael Auler   if (opts::AggressiveSplitting) {
261a34c753fSRafael Auler     // All blocks with 0 count that we can move go to the end of the function.
262a34c753fSRafael Auler     // Even if they were natural to cluster formation and were seen in-between
263a34c753fSRafael Auler     // hot basic blocks.
264*8477bc67SFabian Parzefall     stable_sort(NewLayout, [&](BinaryBasicBlock *A, BinaryBasicBlock *B) {
265a34c753fSRafael Auler       return A->canOutline() < B->canOutline();
266a34c753fSRafael Auler     });
267a34c753fSRafael Auler   } else if (BF.hasEHRanges() && !opts::SplitEH) {
268a34c753fSRafael Auler     // Typically functions with exception handling have landing pads at the end.
269a34c753fSRafael Auler     // We cannot move beginning of landing pads, but we can move 0-count blocks
270a34c753fSRafael Auler     // comprising landing pads to the end and thus facilitate splitting.
271*8477bc67SFabian Parzefall     auto FirstLP = NewLayout.begin();
272a34c753fSRafael Auler     while ((*FirstLP)->isLandingPad())
273a34c753fSRafael Auler       ++FirstLP;
274a34c753fSRafael Auler 
275*8477bc67SFabian Parzefall     std::stable_sort(FirstLP, NewLayout.end(),
276a34c753fSRafael Auler                      [&](BinaryBasicBlock *A, BinaryBasicBlock *B) {
277a34c753fSRafael Auler                        return A->canOutline() < B->canOutline();
278a34c753fSRafael Auler                      });
279a34c753fSRafael Auler   }
280a34c753fSRafael Auler 
281a34c753fSRafael Auler   // Separate hot from cold starting from the bottom.
282*8477bc67SFabian Parzefall   Strategy.partition(NewLayout.rbegin(), NewLayout.rend());
283*8477bc67SFabian Parzefall   BF.getLayout().update(NewLayout);
284a34c753fSRafael Auler 
285ed743045SMaksim Panchenko   // For shared objects, invoke instructions and corresponding landing pads
286ed743045SMaksim Panchenko   // have to be placed in the same fragment. When we split them, create
287ed743045SMaksim Panchenko   // trampoline landing pads that will redirect the execution to real LPs.
288ed743045SMaksim Panchenko   TrampolineSetType Trampolines;
289f263a66bSMaksim Panchenko   if (!BC.HasFixedLoadAddress && BF.hasEHRanges() && BF.isSplit())
290ed743045SMaksim Panchenko     Trampolines = createEHTrampolines(BF);
291f263a66bSMaksim Panchenko 
292a34c753fSRafael Auler   // Check the new size to see if it's worth splitting the function.
293a34c753fSRafael Auler   if (BC.isX86() && BF.isSplit()) {
294a34c753fSRafael Auler     std::tie(HotSize, ColdSize) = BC.calculateEmittedSize(BF);
295a34c753fSRafael Auler     LLVM_DEBUG(dbgs() << "Estimated size for function " << BF
296a34c753fSRafael Auler                       << " post-split is <0x" << Twine::utohexstr(HotSize)
297a34c753fSRafael Auler                       << ", 0x" << Twine::utohexstr(ColdSize) << ">\n");
298a34c753fSRafael Auler     if (alignTo(OriginalHotSize, opts::SplitAlignThreshold) <=
299a34c753fSRafael Auler         alignTo(HotSize, opts::SplitAlignThreshold) + opts::SplitThreshold) {
300a34c753fSRafael Auler       LLVM_DEBUG(dbgs() << "Reversing splitting of function " << BF << ":\n  0x"
301a34c753fSRafael Auler                         << Twine::utohexstr(HotSize) << ", 0x"
302a34c753fSRafael Auler                         << Twine::utohexstr(ColdSize) << " -> 0x"
303a34c753fSRafael Auler                         << Twine::utohexstr(OriginalHotSize) << '\n');
304a34c753fSRafael Auler 
305ed743045SMaksim Panchenko       // Reverse the action of createEHTrampolines(). The trampolines will be
306ed743045SMaksim Panchenko       // placed immediately before the matching destination resulting in no
307ed743045SMaksim Panchenko       // extra code.
308ed743045SMaksim Panchenko       if (PreSplitLayout.size() != BF.size())
309ed743045SMaksim Panchenko         PreSplitLayout = mergeEHTrampolines(BF, PreSplitLayout, Trampolines);
310ed743045SMaksim Panchenko 
311f92ab6afSAmir Ayupov       for (BinaryBasicBlock &BB : BF)
312a34c753fSRafael Auler         BB.setIsCold(false);
313*8477bc67SFabian Parzefall       BF.getLayout().update(PreSplitLayout);
314a34c753fSRafael Auler     } else {
315a34c753fSRafael Auler       SplitBytesHot += HotSize;
316a34c753fSRafael Auler       SplitBytesCold += ColdSize;
317a34c753fSRafael Auler     }
318a34c753fSRafael Auler   }
319a34c753fSRafael Auler }
320a34c753fSRafael Auler 
321ed743045SMaksim Panchenko SplitFunctions::TrampolineSetType
createEHTrampolines(BinaryFunction & BF) const322ed743045SMaksim Panchenko SplitFunctions::createEHTrampolines(BinaryFunction &BF) const {
323f263a66bSMaksim Panchenko   const auto &MIB = BF.getBinaryContext().MIB;
324f263a66bSMaksim Panchenko 
325f263a66bSMaksim Panchenko   // Map real landing pads to the corresponding trampolines.
326ed743045SMaksim Panchenko   TrampolineSetType LPTrampolines;
327f263a66bSMaksim Panchenko 
328f263a66bSMaksim Panchenko   // Iterate over the copy of basic blocks since we are adding new blocks to the
329f263a66bSMaksim Panchenko   // function which will invalidate its iterators.
330f263a66bSMaksim Panchenko   std::vector<BinaryBasicBlock *> Blocks(BF.pbegin(), BF.pend());
331f263a66bSMaksim Panchenko   for (BinaryBasicBlock *BB : Blocks) {
332f263a66bSMaksim Panchenko     for (MCInst &Instr : *BB) {
333f263a66bSMaksim Panchenko       const Optional<MCPlus::MCLandingPad> EHInfo = MIB->getEHInfo(Instr);
334f263a66bSMaksim Panchenko       if (!EHInfo || !EHInfo->first)
335f263a66bSMaksim Panchenko         continue;
336f263a66bSMaksim Panchenko 
337f263a66bSMaksim Panchenko       const MCSymbol *LPLabel = EHInfo->first;
338f263a66bSMaksim Panchenko       BinaryBasicBlock *LPBlock = BF.getBasicBlockForLabel(LPLabel);
339f263a66bSMaksim Panchenko       if (BB->isCold() == LPBlock->isCold())
340f263a66bSMaksim Panchenko         continue;
341f263a66bSMaksim Panchenko 
342f263a66bSMaksim Panchenko       const MCSymbol *TrampolineLabel = nullptr;
343f263a66bSMaksim Panchenko       auto Iter = LPTrampolines.find(LPLabel);
344f263a66bSMaksim Panchenko       if (Iter != LPTrampolines.end()) {
345f263a66bSMaksim Panchenko         TrampolineLabel = Iter->second;
346f263a66bSMaksim Panchenko       } else {
347f263a66bSMaksim Panchenko         // Create a trampoline basic block in the same fragment as the thrower.
348f263a66bSMaksim Panchenko         // Note: there's no need to insert the jump instruction, it will be
349f263a66bSMaksim Panchenko         // added by fixBranches().
350f263a66bSMaksim Panchenko         BinaryBasicBlock *TrampolineBB = BF.addBasicBlock();
351f263a66bSMaksim Panchenko         TrampolineBB->setIsCold(BB->isCold());
352f263a66bSMaksim Panchenko         TrampolineBB->setExecutionCount(LPBlock->getExecutionCount());
353f263a66bSMaksim Panchenko         TrampolineBB->addSuccessor(LPBlock, TrampolineBB->getExecutionCount());
354f263a66bSMaksim Panchenko         TrampolineBB->setCFIState(LPBlock->getCFIState());
355f263a66bSMaksim Panchenko         TrampolineLabel = TrampolineBB->getLabel();
356ed743045SMaksim Panchenko         LPTrampolines.insert(std::make_pair(LPLabel, TrampolineLabel));
357f263a66bSMaksim Panchenko       }
358f263a66bSMaksim Panchenko 
359f263a66bSMaksim Panchenko       // Substitute the landing pad with the trampoline.
360f263a66bSMaksim Panchenko       MIB->updateEHInfo(Instr,
361f263a66bSMaksim Panchenko                         MCPlus::MCLandingPad(TrampolineLabel, EHInfo->second));
362f263a66bSMaksim Panchenko     }
363f263a66bSMaksim Panchenko   }
364f263a66bSMaksim Panchenko 
365f263a66bSMaksim Panchenko   if (LPTrampolines.empty())
366ed743045SMaksim Panchenko     return LPTrampolines;
367f263a66bSMaksim Panchenko 
368f263a66bSMaksim Panchenko   // All trampoline blocks were added to the end of the function. Place them at
369f263a66bSMaksim Panchenko   // the end of corresponding fragments.
370*8477bc67SFabian Parzefall   BinaryFunction::BasicBlockOrderType NewLayout(BF.getLayout().block_begin(),
371*8477bc67SFabian Parzefall                                                 BF.getLayout().block_end());
372*8477bc67SFabian Parzefall   stable_sort(NewLayout, [&](BinaryBasicBlock *A, BinaryBasicBlock *B) {
373f263a66bSMaksim Panchenko     return A->isCold() < B->isCold();
374f263a66bSMaksim Panchenko   });
375*8477bc67SFabian Parzefall   BF.getLayout().update(NewLayout);
376f263a66bSMaksim Panchenko 
377f263a66bSMaksim Panchenko   // Conservatively introduce branch instructions.
378f263a66bSMaksim Panchenko   BF.fixBranches();
379f263a66bSMaksim Panchenko 
380f263a66bSMaksim Panchenko   // Update exception-handling CFG for the function.
381f263a66bSMaksim Panchenko   BF.recomputeLandingPads();
382ed743045SMaksim Panchenko 
383ed743045SMaksim Panchenko   return LPTrampolines;
384ed743045SMaksim Panchenko }
385ed743045SMaksim Panchenko 
mergeEHTrampolines(BinaryFunction & BF,SplitFunctions::BasicBlockOrderType & Layout,const SplitFunctions::TrampolineSetType & Trampolines) const386ed743045SMaksim Panchenko SplitFunctions::BasicBlockOrderType SplitFunctions::mergeEHTrampolines(
387ed743045SMaksim Panchenko     BinaryFunction &BF, SplitFunctions::BasicBlockOrderType &Layout,
388ed743045SMaksim Panchenko     const SplitFunctions::TrampolineSetType &Trampolines) const {
389ed743045SMaksim Panchenko   BasicBlockOrderType MergedLayout;
390ed743045SMaksim Panchenko   for (BinaryBasicBlock *BB : Layout) {
391ed743045SMaksim Panchenko     auto Iter = Trampolines.find(BB->getLabel());
392ed743045SMaksim Panchenko     if (Iter != Trampolines.end()) {
393ed743045SMaksim Panchenko       BinaryBasicBlock *LPBlock = BF.getBasicBlockForLabel(Iter->second);
394ed743045SMaksim Panchenko       assert(LPBlock && "Could not find matching landing pad block.");
395ed743045SMaksim Panchenko       MergedLayout.push_back(LPBlock);
396ed743045SMaksim Panchenko     }
397ed743045SMaksim Panchenko     MergedLayout.push_back(BB);
398ed743045SMaksim Panchenko   }
399ed743045SMaksim Panchenko 
400ed743045SMaksim Panchenko   return MergedLayout;
401f263a66bSMaksim Panchenko }
402f263a66bSMaksim Panchenko 
403a34c753fSRafael Auler } // namespace bolt
404a34c753fSRafael Auler } // namespace llvm
405