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