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