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