xref: /llvm-project/bolt/lib/Passes/LongJmp.cpp (revision b92436efcb7813fc481b30f2593a4907568d917a)
1 //===- bolt/Passes/LongJmp.cpp --------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements the LongJmpPass class.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "bolt/Passes/LongJmp.h"
14 
15 #define DEBUG_TYPE "longjmp"
16 
17 using namespace llvm;
18 
19 namespace opts {
20 extern cl::OptionCategory BoltOptCategory;
21 extern llvm::cl::opt<unsigned> AlignText;
22 extern cl::opt<unsigned> AlignFunctions;
23 extern cl::opt<bool> UseOldText;
24 extern cl::opt<bool> HotFunctionsAtEnd;
25 
26 static cl::opt<bool> GroupStubs("group-stubs",
27                                 cl::desc("share stubs across functions"),
28                                 cl::init(true), cl::cat(BoltOptCategory));
29 }
30 
31 namespace llvm {
32 namespace bolt {
33 
34 namespace {
35 constexpr unsigned ColdFragAlign = 16;
36 
37 void relaxStubToShortJmp(BinaryBasicBlock &StubBB, const MCSymbol *Tgt) {
38   const BinaryContext &BC = StubBB.getFunction()->getBinaryContext();
39   InstructionListType Seq;
40   BC.MIB->createShortJmp(Seq, Tgt, BC.Ctx.get());
41   StubBB.clear();
42   StubBB.addInstructions(Seq.begin(), Seq.end());
43 }
44 
45 void relaxStubToLongJmp(BinaryBasicBlock &StubBB, const MCSymbol *Tgt) {
46   const BinaryContext &BC = StubBB.getFunction()->getBinaryContext();
47   InstructionListType Seq;
48   BC.MIB->createLongJmp(Seq, Tgt, BC.Ctx.get());
49   StubBB.clear();
50   StubBB.addInstructions(Seq.begin(), Seq.end());
51 }
52 
53 BinaryBasicBlock *getBBAtHotColdSplitPoint(BinaryFunction &Func) {
54   if (!Func.isSplit() || Func.empty())
55     return nullptr;
56 
57   assert(!(*Func.begin()).isCold() && "Entry cannot be cold");
58   for (auto I = Func.layout_begin(), E = Func.layout_end(); I != E; ++I) {
59     auto Next = std::next(I);
60     if (Next != E && (*Next)->isCold())
61       return *I;
62   }
63   llvm_unreachable("No hot-colt split point found");
64 }
65 
66 bool shouldInsertStub(const BinaryContext &BC, const MCInst &Inst) {
67   return (BC.MIB->isBranch(Inst) || BC.MIB->isCall(Inst)) &&
68          !BC.MIB->isIndirectBranch(Inst) && !BC.MIB->isIndirectCall(Inst);
69 }
70 
71 } // end anonymous namespace
72 
73 std::pair<std::unique_ptr<BinaryBasicBlock>, MCSymbol *>
74 LongJmpPass::createNewStub(BinaryBasicBlock &SourceBB, const MCSymbol *TgtSym,
75                            bool TgtIsFunc, uint64_t AtAddress) {
76   BinaryFunction &Func = *SourceBB.getFunction();
77   const BinaryContext &BC = Func.getBinaryContext();
78   const bool IsCold = SourceBB.isCold();
79   MCSymbol *StubSym = BC.Ctx->createNamedTempSymbol("Stub");
80   std::unique_ptr<BinaryBasicBlock> StubBB = Func.createBasicBlock(0, StubSym);
81   MCInst Inst;
82   BC.MIB->createUncondBranch(Inst, TgtSym, BC.Ctx.get());
83   if (TgtIsFunc)
84     BC.MIB->convertJmpToTailCall(Inst);
85   StubBB->addInstruction(Inst);
86   StubBB->setExecutionCount(0);
87 
88   // Register this in stubs maps
89   auto registerInMap = [&](StubGroupsTy &Map) {
90     StubGroupTy &StubGroup = Map[TgtSym];
91     StubGroup.insert(
92         std::lower_bound(
93             StubGroup.begin(), StubGroup.end(),
94             std::make_pair(AtAddress, nullptr),
95             [&](const std::pair<uint64_t, BinaryBasicBlock *> &LHS,
96                 const std::pair<uint64_t, BinaryBasicBlock *> &RHS) {
97               return LHS.first < RHS.first;
98             }),
99         std::make_pair(AtAddress, StubBB.get()));
100   };
101 
102   Stubs[&Func].insert(StubBB.get());
103   StubBits[StubBB.get()] = BC.MIB->getUncondBranchEncodingSize();
104   if (IsCold) {
105     registerInMap(ColdLocalStubs[&Func]);
106     if (opts::GroupStubs && TgtIsFunc)
107       registerInMap(ColdStubGroups);
108     ++NumColdStubs;
109   } else {
110     registerInMap(HotLocalStubs[&Func]);
111     if (opts::GroupStubs && TgtIsFunc)
112       registerInMap(HotStubGroups);
113     ++NumHotStubs;
114   }
115 
116   return std::make_pair(std::move(StubBB), StubSym);
117 }
118 
119 BinaryBasicBlock *LongJmpPass::lookupStubFromGroup(
120     const StubGroupsTy &StubGroups, const BinaryFunction &Func,
121     const MCInst &Inst, const MCSymbol *TgtSym, uint64_t DotAddress) const {
122   const BinaryContext &BC = Func.getBinaryContext();
123   auto CandidatesIter = StubGroups.find(TgtSym);
124   if (CandidatesIter == StubGroups.end())
125     return nullptr;
126   const StubGroupTy &Candidates = CandidatesIter->second;
127   if (Candidates.empty())
128     return nullptr;
129   auto Cand = std::lower_bound(
130       Candidates.begin(), Candidates.end(), std::make_pair(DotAddress, nullptr),
131       [&](const std::pair<uint64_t, BinaryBasicBlock *> &LHS,
132           const std::pair<uint64_t, BinaryBasicBlock *> &RHS) {
133         return LHS.first < RHS.first;
134       });
135   if (Cand == Candidates.end())
136     return nullptr;
137   if (Cand != Candidates.begin()) {
138     const StubTy *LeftCand = std::prev(Cand);
139     if (Cand->first - DotAddress > DotAddress - LeftCand->first)
140       Cand = LeftCand;
141   }
142   int BitsAvail = BC.MIB->getPCRelEncodingSize(Inst) - 1;
143   uint64_t Mask = ~((1ULL << BitsAvail) - 1);
144   uint64_t PCRelTgtAddress = Cand->first;
145   PCRelTgtAddress = DotAddress > PCRelTgtAddress ? DotAddress - PCRelTgtAddress
146                                                  : PCRelTgtAddress - DotAddress;
147   LLVM_DEBUG({
148     if (Candidates.size() > 1)
149       dbgs() << "Considering stub group with " << Candidates.size()
150              << " candidates. DotAddress is " << Twine::utohexstr(DotAddress)
151              << ", chosen candidate address is "
152              << Twine::utohexstr(Cand->first) << "\n";
153   });
154   return PCRelTgtAddress & Mask ? nullptr : Cand->second;
155 }
156 
157 BinaryBasicBlock *
158 LongJmpPass::lookupGlobalStub(const BinaryBasicBlock &SourceBB,
159                               const MCInst &Inst, const MCSymbol *TgtSym,
160                               uint64_t DotAddress) const {
161   const BinaryFunction &Func = *SourceBB.getFunction();
162   const StubGroupsTy &StubGroups =
163       SourceBB.isCold() ? ColdStubGroups : HotStubGroups;
164   return lookupStubFromGroup(StubGroups, Func, Inst, TgtSym, DotAddress);
165 }
166 
167 BinaryBasicBlock *LongJmpPass::lookupLocalStub(const BinaryBasicBlock &SourceBB,
168                                                const MCInst &Inst,
169                                                const MCSymbol *TgtSym,
170                                                uint64_t DotAddress) const {
171   const BinaryFunction &Func = *SourceBB.getFunction();
172   const DenseMap<const BinaryFunction *, StubGroupsTy> &StubGroups =
173       SourceBB.isCold() ? ColdLocalStubs : HotLocalStubs;
174   const auto Iter = StubGroups.find(&Func);
175   if (Iter == StubGroups.end())
176     return nullptr;
177   return lookupStubFromGroup(Iter->second, Func, Inst, TgtSym, DotAddress);
178 }
179 
180 std::unique_ptr<BinaryBasicBlock>
181 LongJmpPass::replaceTargetWithStub(BinaryBasicBlock &BB, MCInst &Inst,
182                                    uint64_t DotAddress,
183                                    uint64_t StubCreationAddress) {
184   const BinaryFunction &Func = *BB.getFunction();
185   const BinaryContext &BC = Func.getBinaryContext();
186   std::unique_ptr<BinaryBasicBlock> NewBB;
187   const MCSymbol *TgtSym = BC.MIB->getTargetSymbol(Inst);
188   assert(TgtSym && "getTargetSymbol failed");
189 
190   BinaryBasicBlock::BinaryBranchInfo BI{0, 0};
191   BinaryBasicBlock *TgtBB = BB.getSuccessor(TgtSym, BI);
192   auto LocalStubsIter = Stubs.find(&Func);
193 
194   // If already using stub and the stub is from another function, create a local
195   // stub, since the foreign stub is now out of range
196   if (!TgtBB) {
197     auto SSIter = SharedStubs.find(TgtSym);
198     if (SSIter != SharedStubs.end()) {
199       TgtSym = BC.MIB->getTargetSymbol(*SSIter->second->begin());
200       --NumSharedStubs;
201     }
202   } else if (LocalStubsIter != Stubs.end() &&
203              LocalStubsIter->second.count(TgtBB)) {
204     // If we are replacing a local stub (because it is now out of range),
205     // use its target instead of creating a stub to jump to another stub
206     TgtSym = BC.MIB->getTargetSymbol(*TgtBB->begin());
207     TgtBB = BB.getSuccessor(TgtSym, BI);
208   }
209 
210   BinaryBasicBlock *StubBB = lookupLocalStub(BB, Inst, TgtSym, DotAddress);
211   // If not found, look it up in globally shared stub maps if it is a function
212   // call (TgtBB is not set)
213   if (!StubBB && !TgtBB) {
214     StubBB = lookupGlobalStub(BB, Inst, TgtSym, DotAddress);
215     if (StubBB) {
216       SharedStubs[StubBB->getLabel()] = StubBB;
217       ++NumSharedStubs;
218     }
219   }
220   MCSymbol *StubSymbol = StubBB ? StubBB->getLabel() : nullptr;
221 
222   if (!StubBB) {
223     std::tie(NewBB, StubSymbol) =
224         createNewStub(BB, TgtSym, /*is func?*/ !TgtBB, StubCreationAddress);
225     StubBB = NewBB.get();
226   }
227 
228   // Local branch
229   if (TgtBB) {
230     uint64_t OrigCount = BI.Count;
231     uint64_t OrigMispreds = BI.MispredictedCount;
232     BB.replaceSuccessor(TgtBB, StubBB, OrigCount, OrigMispreds);
233     StubBB->setExecutionCount(StubBB->getExecutionCount() + OrigCount);
234     if (NewBB) {
235       StubBB->addSuccessor(TgtBB, OrigCount, OrigMispreds);
236       StubBB->setIsCold(BB.isCold());
237     }
238     // Call / tail call
239   } else {
240     StubBB->setExecutionCount(StubBB->getExecutionCount() +
241                               BB.getExecutionCount());
242     if (NewBB) {
243       assert(TgtBB == nullptr);
244       StubBB->setIsCold(BB.isCold());
245       // Set as entry point because this block is valid but we have no preds
246       StubBB->getFunction()->addEntryPoint(*StubBB);
247     }
248   }
249   BC.MIB->replaceBranchTarget(Inst, StubSymbol, BC.Ctx.get());
250 
251   return NewBB;
252 }
253 
254 void LongJmpPass::updateStubGroups() {
255   auto update = [&](StubGroupsTy &StubGroups) {
256     for (auto &KeyVal : StubGroups) {
257       for (StubTy &Elem : KeyVal.second)
258         Elem.first = BBAddresses[Elem.second];
259       std::sort(KeyVal.second.begin(), KeyVal.second.end(),
260                 [&](const std::pair<uint64_t, BinaryBasicBlock *> &LHS,
261                     const std::pair<uint64_t, BinaryBasicBlock *> &RHS) {
262                   return LHS.first < RHS.first;
263                 });
264     }
265   };
266 
267   for (auto &KeyVal : HotLocalStubs)
268     update(KeyVal.second);
269   for (auto &KeyVal : ColdLocalStubs)
270     update(KeyVal.second);
271   update(HotStubGroups);
272   update(ColdStubGroups);
273 }
274 
275 void LongJmpPass::tentativeBBLayout(const BinaryFunction &Func) {
276   const BinaryContext &BC = Func.getBinaryContext();
277   uint64_t HotDot = HotAddresses[&Func];
278   uint64_t ColdDot = ColdAddresses[&Func];
279   bool Cold = false;
280   for (BinaryBasicBlock *BB : Func.layout()) {
281     if (Cold || BB->isCold()) {
282       Cold = true;
283       BBAddresses[BB] = ColdDot;
284       ColdDot += BC.computeCodeSize(BB->begin(), BB->end());
285     } else {
286       BBAddresses[BB] = HotDot;
287       HotDot += BC.computeCodeSize(BB->begin(), BB->end());
288     }
289   }
290 }
291 
292 uint64_t LongJmpPass::tentativeLayoutRelocColdPart(
293     const BinaryContext &BC, std::vector<BinaryFunction *> &SortedFunctions,
294     uint64_t DotAddress) {
295   DotAddress = alignTo(DotAddress, llvm::Align(opts::AlignFunctions));
296   for (BinaryFunction *Func : SortedFunctions) {
297     if (!Func->isSplit())
298       continue;
299     DotAddress = alignTo(DotAddress, BinaryFunction::MinAlign);
300     uint64_t Pad =
301         offsetToAlignment(DotAddress, llvm::Align(Func->getAlignment()));
302     if (Pad <= Func->getMaxColdAlignmentBytes())
303       DotAddress += Pad;
304     ColdAddresses[Func] = DotAddress;
305     LLVM_DEBUG(dbgs() << Func->getPrintName() << " cold tentative: "
306                       << Twine::utohexstr(DotAddress) << "\n");
307     DotAddress += Func->estimateColdSize();
308     DotAddress = alignTo(DotAddress, Func->getConstantIslandAlignment());
309     DotAddress += Func->estimateConstantIslandSize();
310   }
311   return DotAddress;
312 }
313 
314 uint64_t LongJmpPass::tentativeLayoutRelocMode(
315     const BinaryContext &BC, std::vector<BinaryFunction *> &SortedFunctions,
316     uint64_t DotAddress) {
317 
318   // Compute hot cold frontier
319   uint32_t LastHotIndex = -1u;
320   uint32_t CurrentIndex = 0;
321   if (opts::HotFunctionsAtEnd) {
322     for (BinaryFunction *BF : SortedFunctions) {
323       if (BF->hasValidIndex()) {
324         LastHotIndex = CurrentIndex;
325         break;
326       }
327 
328       ++CurrentIndex;
329     }
330   } else {
331     for (BinaryFunction *BF : SortedFunctions) {
332       if (!BF->hasValidIndex()) {
333         LastHotIndex = CurrentIndex;
334         break;
335       }
336 
337       ++CurrentIndex;
338     }
339   }
340 
341   // Hot
342   CurrentIndex = 0;
343   bool ColdLayoutDone = false;
344   for (BinaryFunction *Func : SortedFunctions) {
345     if (!BC.shouldEmit(*Func)) {
346       HotAddresses[Func] = Func->getAddress();
347       continue;
348     }
349 
350     if (!ColdLayoutDone && CurrentIndex >= LastHotIndex) {
351       DotAddress =
352           tentativeLayoutRelocColdPart(BC, SortedFunctions, DotAddress);
353       ColdLayoutDone = true;
354       if (opts::HotFunctionsAtEnd)
355         DotAddress = alignTo(DotAddress, opts::AlignText);
356     }
357 
358     DotAddress = alignTo(DotAddress, BinaryFunction::MinAlign);
359     uint64_t Pad =
360         offsetToAlignment(DotAddress, llvm::Align(Func->getAlignment()));
361     if (Pad <= Func->getMaxAlignmentBytes())
362       DotAddress += Pad;
363     HotAddresses[Func] = DotAddress;
364     LLVM_DEBUG(dbgs() << Func->getPrintName() << " tentative: "
365                       << Twine::utohexstr(DotAddress) << "\n");
366     if (!Func->isSplit())
367       DotAddress += Func->estimateSize();
368     else
369       DotAddress += Func->estimateHotSize();
370 
371     DotAddress = alignTo(DotAddress, Func->getConstantIslandAlignment());
372     DotAddress += Func->estimateConstantIslandSize();
373     ++CurrentIndex;
374   }
375   // BBs
376   for (BinaryFunction *Func : SortedFunctions)
377     tentativeBBLayout(*Func);
378 
379   return DotAddress;
380 }
381 
382 void LongJmpPass::tentativeLayout(
383     const BinaryContext &BC, std::vector<BinaryFunction *> &SortedFunctions) {
384   uint64_t DotAddress = BC.LayoutStartAddress;
385 
386   if (!BC.HasRelocations) {
387     for (BinaryFunction *Func : SortedFunctions) {
388       HotAddresses[Func] = Func->getAddress();
389       DotAddress = alignTo(DotAddress, ColdFragAlign);
390       ColdAddresses[Func] = DotAddress;
391       if (Func->isSplit())
392         DotAddress += Func->estimateColdSize();
393       tentativeBBLayout(*Func);
394     }
395 
396     return;
397   }
398 
399   // Relocation mode
400   uint64_t EstimatedTextSize = 0;
401   if (opts::UseOldText) {
402     EstimatedTextSize = tentativeLayoutRelocMode(BC, SortedFunctions, 0);
403 
404     // Initial padding
405     if (EstimatedTextSize <= BC.OldTextSectionSize) {
406       DotAddress = BC.OldTextSectionAddress;
407       uint64_t Pad =
408           offsetToAlignment(DotAddress, llvm::Align(opts::AlignText));
409       if (Pad + EstimatedTextSize <= BC.OldTextSectionSize) {
410         DotAddress += Pad;
411       }
412     }
413   }
414 
415   if (!EstimatedTextSize || EstimatedTextSize > BC.OldTextSectionSize)
416     DotAddress = alignTo(BC.LayoutStartAddress, opts::AlignText);
417 
418   tentativeLayoutRelocMode(BC, SortedFunctions, DotAddress);
419 }
420 
421 bool LongJmpPass::usesStub(const BinaryFunction &Func,
422                            const MCInst &Inst) const {
423   const MCSymbol *TgtSym = Func.getBinaryContext().MIB->getTargetSymbol(Inst);
424   const BinaryBasicBlock *TgtBB = Func.getBasicBlockForLabel(TgtSym);
425   auto Iter = Stubs.find(&Func);
426   if (Iter != Stubs.end())
427     return Iter->second.count(TgtBB);
428   return false;
429 }
430 
431 uint64_t LongJmpPass::getSymbolAddress(const BinaryContext &BC,
432                                        const MCSymbol *Target,
433                                        const BinaryBasicBlock *TgtBB) const {
434   if (TgtBB) {
435     auto Iter = BBAddresses.find(TgtBB);
436     assert(Iter != BBAddresses.end() && "Unrecognized BB");
437     return Iter->second;
438   }
439   uint64_t EntryID = 0;
440   const BinaryFunction *TargetFunc = BC.getFunctionForSymbol(Target, &EntryID);
441   auto Iter = HotAddresses.find(TargetFunc);
442   if (Iter == HotAddresses.end() || (TargetFunc && EntryID)) {
443     // Look at BinaryContext's resolution for this symbol - this is a symbol not
444     // mapped to a BinaryFunction
445     ErrorOr<uint64_t> ValueOrError = BC.getSymbolValue(*Target);
446     assert(ValueOrError && "Unrecognized symbol");
447     return *ValueOrError;
448   }
449   return Iter->second;
450 }
451 
452 bool LongJmpPass::relaxStub(BinaryBasicBlock &StubBB) {
453   const BinaryFunction &Func = *StubBB.getFunction();
454   const BinaryContext &BC = Func.getBinaryContext();
455   const int Bits = StubBits[&StubBB];
456   // Already working with the largest range?
457   if (Bits == static_cast<int>(BC.AsmInfo->getCodePointerSize() * 8))
458     return false;
459 
460   const static int RangeShortJmp = BC.MIB->getShortJmpEncodingSize();
461   const static int RangeSingleInstr = BC.MIB->getUncondBranchEncodingSize();
462   const static uint64_t ShortJmpMask = ~((1ULL << RangeShortJmp) - 1);
463   const static uint64_t SingleInstrMask =
464       ~((1ULL << (RangeSingleInstr - 1)) - 1);
465 
466   const MCSymbol *RealTargetSym = BC.MIB->getTargetSymbol(*StubBB.begin());
467   const BinaryBasicBlock *TgtBB = Func.getBasicBlockForLabel(RealTargetSym);
468   uint64_t TgtAddress = getSymbolAddress(BC, RealTargetSym, TgtBB);
469   uint64_t DotAddress = BBAddresses[&StubBB];
470   uint64_t PCRelTgtAddress = DotAddress > TgtAddress ? DotAddress - TgtAddress
471                                                      : TgtAddress - DotAddress;
472   // If it fits in one instruction, do not relax
473   if (!(PCRelTgtAddress & SingleInstrMask))
474     return false;
475 
476   // Fits short jmp
477   if (!(PCRelTgtAddress & ShortJmpMask)) {
478     if (Bits >= RangeShortJmp)
479       return false;
480 
481     LLVM_DEBUG(dbgs() << "Relaxing stub to short jump. PCRelTgtAddress = "
482                       << Twine::utohexstr(PCRelTgtAddress)
483                       << " RealTargetSym = " << RealTargetSym->getName()
484                       << "\n");
485     relaxStubToShortJmp(StubBB, RealTargetSym);
486     StubBits[&StubBB] = RangeShortJmp;
487     return true;
488   }
489 
490   // The long jmp uses absolute address on AArch64
491   // So we could not use it for PIC binaries
492   if (BC.isAArch64() && !BC.HasFixedLoadAddress) {
493     errs() << "BOLT-ERROR: Unable to relax stub for PIC binary\n";
494     exit(1);
495   }
496 
497   LLVM_DEBUG(dbgs() << "Relaxing stub to long jump. PCRelTgtAddress = "
498                     << Twine::utohexstr(PCRelTgtAddress)
499                     << " RealTargetSym = " << RealTargetSym->getName() << "\n");
500   relaxStubToLongJmp(StubBB, RealTargetSym);
501   StubBits[&StubBB] = static_cast<int>(BC.AsmInfo->getCodePointerSize() * 8);
502   return true;
503 }
504 
505 bool LongJmpPass::needsStub(const BinaryBasicBlock &BB, const MCInst &Inst,
506                             uint64_t DotAddress) const {
507   const BinaryFunction &Func = *BB.getFunction();
508   const BinaryContext &BC = Func.getBinaryContext();
509   const MCSymbol *TgtSym = BC.MIB->getTargetSymbol(Inst);
510   assert(TgtSym && "getTargetSymbol failed");
511 
512   const BinaryBasicBlock *TgtBB = Func.getBasicBlockForLabel(TgtSym);
513   // Check for shared stubs from foreign functions
514   if (!TgtBB) {
515     auto SSIter = SharedStubs.find(TgtSym);
516     if (SSIter != SharedStubs.end())
517       TgtBB = SSIter->second;
518   }
519 
520   int BitsAvail = BC.MIB->getPCRelEncodingSize(Inst) - 1;
521   uint64_t Mask = ~((1ULL << BitsAvail) - 1);
522 
523   uint64_t PCRelTgtAddress = getSymbolAddress(BC, TgtSym, TgtBB);
524   PCRelTgtAddress = DotAddress > PCRelTgtAddress ? DotAddress - PCRelTgtAddress
525                                                  : PCRelTgtAddress - DotAddress;
526 
527   return PCRelTgtAddress & Mask;
528 }
529 
530 bool LongJmpPass::relax(BinaryFunction &Func) {
531   const BinaryContext &BC = Func.getBinaryContext();
532   bool Modified = false;
533 
534   assert(BC.isAArch64() && "Unsupported arch");
535   constexpr int InsnSize = 4; // AArch64
536   std::vector<std::pair<BinaryBasicBlock *, std::unique_ptr<BinaryBasicBlock>>>
537       Insertions;
538 
539   BinaryBasicBlock *Frontier = getBBAtHotColdSplitPoint(Func);
540   uint64_t FrontierAddress = Frontier ? BBAddresses[Frontier] : 0;
541   if (FrontierAddress)
542     FrontierAddress += Frontier->getNumNonPseudos() * InsnSize;
543 
544   // Add necessary stubs for branch targets we know we can't fit in the
545   // instruction
546   for (BinaryBasicBlock &BB : Func) {
547     uint64_t DotAddress = BBAddresses[&BB];
548     // Stubs themselves are relaxed on the next loop
549     if (Stubs[&Func].count(&BB))
550       continue;
551 
552     for (MCInst &Inst : BB) {
553       if (BC.MIB->isPseudo(Inst))
554         continue;
555 
556       if (!shouldInsertStub(BC, Inst)) {
557         DotAddress += InsnSize;
558         continue;
559       }
560 
561       // Check and relax direct branch or call
562       if (!needsStub(BB, Inst, DotAddress)) {
563         DotAddress += InsnSize;
564         continue;
565       }
566       Modified = true;
567 
568       // Insert stubs close to the patched BB if call, but far away from the
569       // hot path if a branch, since this branch target is the cold region
570       // (but first check that the far away stub will be in range).
571       BinaryBasicBlock *InsertionPoint = &BB;
572       if (Func.isSimple() && !BC.MIB->isCall(Inst) && FrontierAddress &&
573           !BB.isCold()) {
574         int BitsAvail = BC.MIB->getPCRelEncodingSize(Inst) - 1;
575         uint64_t Mask = ~((1ULL << BitsAvail) - 1);
576         assert(FrontierAddress > DotAddress &&
577                "Hot code should be before the frontier");
578         uint64_t PCRelTgt = FrontierAddress - DotAddress;
579         if (!(PCRelTgt & Mask))
580           InsertionPoint = Frontier;
581       }
582       // Always put stubs at the end of the function if non-simple. We can't
583       // change the layout of non-simple functions because it has jump tables
584       // that we do not control.
585       if (!Func.isSimple())
586         InsertionPoint = &*std::prev(Func.end());
587 
588       // Create a stub to handle a far-away target
589       Insertions.emplace_back(InsertionPoint,
590                               replaceTargetWithStub(BB, Inst, DotAddress,
591                                                     InsertionPoint == Frontier
592                                                         ? FrontierAddress
593                                                         : DotAddress));
594 
595       DotAddress += InsnSize;
596     }
597   }
598 
599   // Relax stubs if necessary
600   for (BinaryBasicBlock &BB : Func) {
601     if (!Stubs[&Func].count(&BB) || !BB.isValid())
602       continue;
603 
604     Modified |= relaxStub(BB);
605   }
606 
607   for (std::pair<BinaryBasicBlock *, std::unique_ptr<BinaryBasicBlock>> &Elmt :
608        Insertions) {
609     if (!Elmt.second)
610       continue;
611     std::vector<std::unique_ptr<BinaryBasicBlock>> NewBBs;
612     NewBBs.emplace_back(std::move(Elmt.second));
613     Func.insertBasicBlocks(Elmt.first, std::move(NewBBs), true);
614   }
615 
616   return Modified;
617 }
618 
619 void LongJmpPass::runOnFunctions(BinaryContext &BC) {
620   outs() << "BOLT-INFO: Starting stub-insertion pass\n";
621   std::vector<BinaryFunction *> Sorted = BC.getSortedFunctions();
622   bool Modified;
623   uint32_t Iterations = 0;
624   do {
625     ++Iterations;
626     Modified = false;
627     tentativeLayout(BC, Sorted);
628     updateStubGroups();
629     for (BinaryFunction *Func : Sorted) {
630       if (relax(*Func)) {
631         // Don't ruin non-simple functions, they can't afford to have the layout
632         // changed.
633         if (Func->isSimple())
634           Func->fixBranches();
635         Modified = true;
636       }
637     }
638   } while (Modified);
639   outs() << "BOLT-INFO: Inserted " << NumHotStubs
640          << " stubs in the hot area and " << NumColdStubs
641          << " stubs in the cold area. Shared " << NumSharedStubs
642          << " times, iterated " << Iterations << " times.\n";
643 }
644 } // namespace bolt
645 } // namespace llvm
646