xref: /llvm-project/bolt/lib/Passes/LongJmp.cpp (revision c4302e4fc2017f293323f436c20bcab31e469d57)
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, llvm::less_first());
259     }
260   };
261 
262   for (auto &KeyVal : HotLocalStubs)
263     update(KeyVal.second);
264   for (auto &KeyVal : ColdLocalStubs)
265     update(KeyVal.second);
266   update(HotStubGroups);
267   update(ColdStubGroups);
268 }
269 
270 void LongJmpPass::tentativeBBLayout(const BinaryFunction &Func) {
271   const BinaryContext &BC = Func.getBinaryContext();
272   uint64_t HotDot = HotAddresses[&Func];
273   uint64_t ColdDot = ColdAddresses[&Func];
274   bool Cold = false;
275   for (BinaryBasicBlock *BB : Func.layout()) {
276     if (Cold || BB->isCold()) {
277       Cold = true;
278       BBAddresses[BB] = ColdDot;
279       ColdDot += BC.computeCodeSize(BB->begin(), BB->end());
280     } else {
281       BBAddresses[BB] = HotDot;
282       HotDot += BC.computeCodeSize(BB->begin(), BB->end());
283     }
284   }
285 }
286 
287 uint64_t LongJmpPass::tentativeLayoutRelocColdPart(
288     const BinaryContext &BC, std::vector<BinaryFunction *> &SortedFunctions,
289     uint64_t DotAddress) {
290   DotAddress = alignTo(DotAddress, llvm::Align(opts::AlignFunctions));
291   for (BinaryFunction *Func : SortedFunctions) {
292     if (!Func->isSplit())
293       continue;
294     DotAddress = alignTo(DotAddress, BinaryFunction::MinAlign);
295     uint64_t Pad =
296         offsetToAlignment(DotAddress, llvm::Align(Func->getAlignment()));
297     if (Pad <= Func->getMaxColdAlignmentBytes())
298       DotAddress += Pad;
299     ColdAddresses[Func] = DotAddress;
300     LLVM_DEBUG(dbgs() << Func->getPrintName() << " cold tentative: "
301                       << Twine::utohexstr(DotAddress) << "\n");
302     DotAddress += Func->estimateColdSize();
303     DotAddress = alignTo(DotAddress, Func->getConstantIslandAlignment());
304     DotAddress += Func->estimateConstantIslandSize();
305   }
306   return DotAddress;
307 }
308 
309 uint64_t LongJmpPass::tentativeLayoutRelocMode(
310     const BinaryContext &BC, std::vector<BinaryFunction *> &SortedFunctions,
311     uint64_t DotAddress) {
312 
313   // Compute hot cold frontier
314   uint32_t LastHotIndex = -1u;
315   uint32_t CurrentIndex = 0;
316   if (opts::HotFunctionsAtEnd) {
317     for (BinaryFunction *BF : SortedFunctions) {
318       if (BF->hasValidIndex()) {
319         LastHotIndex = CurrentIndex;
320         break;
321       }
322 
323       ++CurrentIndex;
324     }
325   } else {
326     for (BinaryFunction *BF : SortedFunctions) {
327       if (!BF->hasValidIndex()) {
328         LastHotIndex = CurrentIndex;
329         break;
330       }
331 
332       ++CurrentIndex;
333     }
334   }
335 
336   // Hot
337   CurrentIndex = 0;
338   bool ColdLayoutDone = false;
339   for (BinaryFunction *Func : SortedFunctions) {
340     if (!BC.shouldEmit(*Func)) {
341       HotAddresses[Func] = Func->getAddress();
342       continue;
343     }
344 
345     if (!ColdLayoutDone && CurrentIndex >= LastHotIndex) {
346       DotAddress =
347           tentativeLayoutRelocColdPart(BC, SortedFunctions, DotAddress);
348       ColdLayoutDone = true;
349       if (opts::HotFunctionsAtEnd)
350         DotAddress = alignTo(DotAddress, opts::AlignText);
351     }
352 
353     DotAddress = alignTo(DotAddress, BinaryFunction::MinAlign);
354     uint64_t Pad =
355         offsetToAlignment(DotAddress, llvm::Align(Func->getAlignment()));
356     if (Pad <= Func->getMaxAlignmentBytes())
357       DotAddress += Pad;
358     HotAddresses[Func] = DotAddress;
359     LLVM_DEBUG(dbgs() << Func->getPrintName() << " tentative: "
360                       << Twine::utohexstr(DotAddress) << "\n");
361     if (!Func->isSplit())
362       DotAddress += Func->estimateSize();
363     else
364       DotAddress += Func->estimateHotSize();
365 
366     DotAddress = alignTo(DotAddress, Func->getConstantIslandAlignment());
367     DotAddress += Func->estimateConstantIslandSize();
368     ++CurrentIndex;
369   }
370   // BBs
371   for (BinaryFunction *Func : SortedFunctions)
372     tentativeBBLayout(*Func);
373 
374   return DotAddress;
375 }
376 
377 void LongJmpPass::tentativeLayout(
378     const BinaryContext &BC, std::vector<BinaryFunction *> &SortedFunctions) {
379   uint64_t DotAddress = BC.LayoutStartAddress;
380 
381   if (!BC.HasRelocations) {
382     for (BinaryFunction *Func : SortedFunctions) {
383       HotAddresses[Func] = Func->getAddress();
384       DotAddress = alignTo(DotAddress, ColdFragAlign);
385       ColdAddresses[Func] = DotAddress;
386       if (Func->isSplit())
387         DotAddress += Func->estimateColdSize();
388       tentativeBBLayout(*Func);
389     }
390 
391     return;
392   }
393 
394   // Relocation mode
395   uint64_t EstimatedTextSize = 0;
396   if (opts::UseOldText) {
397     EstimatedTextSize = tentativeLayoutRelocMode(BC, SortedFunctions, 0);
398 
399     // Initial padding
400     if (EstimatedTextSize <= BC.OldTextSectionSize) {
401       DotAddress = BC.OldTextSectionAddress;
402       uint64_t Pad =
403           offsetToAlignment(DotAddress, llvm::Align(opts::AlignText));
404       if (Pad + EstimatedTextSize <= BC.OldTextSectionSize) {
405         DotAddress += Pad;
406       }
407     }
408   }
409 
410   if (!EstimatedTextSize || EstimatedTextSize > BC.OldTextSectionSize)
411     DotAddress = alignTo(BC.LayoutStartAddress, opts::AlignText);
412 
413   tentativeLayoutRelocMode(BC, SortedFunctions, DotAddress);
414 }
415 
416 bool LongJmpPass::usesStub(const BinaryFunction &Func,
417                            const MCInst &Inst) const {
418   const MCSymbol *TgtSym = Func.getBinaryContext().MIB->getTargetSymbol(Inst);
419   const BinaryBasicBlock *TgtBB = Func.getBasicBlockForLabel(TgtSym);
420   auto Iter = Stubs.find(&Func);
421   if (Iter != Stubs.end())
422     return Iter->second.count(TgtBB);
423   return false;
424 }
425 
426 uint64_t LongJmpPass::getSymbolAddress(const BinaryContext &BC,
427                                        const MCSymbol *Target,
428                                        const BinaryBasicBlock *TgtBB) const {
429   if (TgtBB) {
430     auto Iter = BBAddresses.find(TgtBB);
431     assert(Iter != BBAddresses.end() && "Unrecognized BB");
432     return Iter->second;
433   }
434   uint64_t EntryID = 0;
435   const BinaryFunction *TargetFunc = BC.getFunctionForSymbol(Target, &EntryID);
436   auto Iter = HotAddresses.find(TargetFunc);
437   if (Iter == HotAddresses.end() || (TargetFunc && EntryID)) {
438     // Look at BinaryContext's resolution for this symbol - this is a symbol not
439     // mapped to a BinaryFunction
440     ErrorOr<uint64_t> ValueOrError = BC.getSymbolValue(*Target);
441     assert(ValueOrError && "Unrecognized symbol");
442     return *ValueOrError;
443   }
444   return Iter->second;
445 }
446 
447 bool LongJmpPass::relaxStub(BinaryBasicBlock &StubBB) {
448   const BinaryFunction &Func = *StubBB.getFunction();
449   const BinaryContext &BC = Func.getBinaryContext();
450   const int Bits = StubBits[&StubBB];
451   // Already working with the largest range?
452   if (Bits == static_cast<int>(BC.AsmInfo->getCodePointerSize() * 8))
453     return false;
454 
455   const static int RangeShortJmp = BC.MIB->getShortJmpEncodingSize();
456   const static int RangeSingleInstr = BC.MIB->getUncondBranchEncodingSize();
457   const static uint64_t ShortJmpMask = ~((1ULL << RangeShortJmp) - 1);
458   const static uint64_t SingleInstrMask =
459       ~((1ULL << (RangeSingleInstr - 1)) - 1);
460 
461   const MCSymbol *RealTargetSym = BC.MIB->getTargetSymbol(*StubBB.begin());
462   const BinaryBasicBlock *TgtBB = Func.getBasicBlockForLabel(RealTargetSym);
463   uint64_t TgtAddress = getSymbolAddress(BC, RealTargetSym, TgtBB);
464   uint64_t DotAddress = BBAddresses[&StubBB];
465   uint64_t PCRelTgtAddress = DotAddress > TgtAddress ? DotAddress - TgtAddress
466                                                      : TgtAddress - DotAddress;
467   // If it fits in one instruction, do not relax
468   if (!(PCRelTgtAddress & SingleInstrMask))
469     return false;
470 
471   // Fits short jmp
472   if (!(PCRelTgtAddress & ShortJmpMask)) {
473     if (Bits >= RangeShortJmp)
474       return false;
475 
476     LLVM_DEBUG(dbgs() << "Relaxing stub to short jump. PCRelTgtAddress = "
477                       << Twine::utohexstr(PCRelTgtAddress)
478                       << " RealTargetSym = " << RealTargetSym->getName()
479                       << "\n");
480     relaxStubToShortJmp(StubBB, RealTargetSym);
481     StubBits[&StubBB] = RangeShortJmp;
482     return true;
483   }
484 
485   // The long jmp uses absolute address on AArch64
486   // So we could not use it for PIC binaries
487   if (BC.isAArch64() && !BC.HasFixedLoadAddress) {
488     errs() << "BOLT-ERROR: Unable to relax stub for PIC binary\n";
489     exit(1);
490   }
491 
492   LLVM_DEBUG(dbgs() << "Relaxing stub to long jump. PCRelTgtAddress = "
493                     << Twine::utohexstr(PCRelTgtAddress)
494                     << " RealTargetSym = " << RealTargetSym->getName() << "\n");
495   relaxStubToLongJmp(StubBB, RealTargetSym);
496   StubBits[&StubBB] = static_cast<int>(BC.AsmInfo->getCodePointerSize() * 8);
497   return true;
498 }
499 
500 bool LongJmpPass::needsStub(const BinaryBasicBlock &BB, const MCInst &Inst,
501                             uint64_t DotAddress) const {
502   const BinaryFunction &Func = *BB.getFunction();
503   const BinaryContext &BC = Func.getBinaryContext();
504   const MCSymbol *TgtSym = BC.MIB->getTargetSymbol(Inst);
505   assert(TgtSym && "getTargetSymbol failed");
506 
507   const BinaryBasicBlock *TgtBB = Func.getBasicBlockForLabel(TgtSym);
508   // Check for shared stubs from foreign functions
509   if (!TgtBB) {
510     auto SSIter = SharedStubs.find(TgtSym);
511     if (SSIter != SharedStubs.end())
512       TgtBB = SSIter->second;
513   }
514 
515   int BitsAvail = BC.MIB->getPCRelEncodingSize(Inst) - 1;
516   uint64_t Mask = ~((1ULL << BitsAvail) - 1);
517 
518   uint64_t PCRelTgtAddress = getSymbolAddress(BC, TgtSym, TgtBB);
519   PCRelTgtAddress = DotAddress > PCRelTgtAddress ? DotAddress - PCRelTgtAddress
520                                                  : PCRelTgtAddress - DotAddress;
521 
522   return PCRelTgtAddress & Mask;
523 }
524 
525 bool LongJmpPass::relax(BinaryFunction &Func) {
526   const BinaryContext &BC = Func.getBinaryContext();
527   bool Modified = false;
528 
529   assert(BC.isAArch64() && "Unsupported arch");
530   constexpr int InsnSize = 4; // AArch64
531   std::vector<std::pair<BinaryBasicBlock *, std::unique_ptr<BinaryBasicBlock>>>
532       Insertions;
533 
534   BinaryBasicBlock *Frontier = getBBAtHotColdSplitPoint(Func);
535   uint64_t FrontierAddress = Frontier ? BBAddresses[Frontier] : 0;
536   if (FrontierAddress)
537     FrontierAddress += Frontier->getNumNonPseudos() * InsnSize;
538 
539   // Add necessary stubs for branch targets we know we can't fit in the
540   // instruction
541   for (BinaryBasicBlock &BB : Func) {
542     uint64_t DotAddress = BBAddresses[&BB];
543     // Stubs themselves are relaxed on the next loop
544     if (Stubs[&Func].count(&BB))
545       continue;
546 
547     for (MCInst &Inst : BB) {
548       if (BC.MIB->isPseudo(Inst))
549         continue;
550 
551       if (!shouldInsertStub(BC, Inst)) {
552         DotAddress += InsnSize;
553         continue;
554       }
555 
556       // Check and relax direct branch or call
557       if (!needsStub(BB, Inst, DotAddress)) {
558         DotAddress += InsnSize;
559         continue;
560       }
561       Modified = true;
562 
563       // Insert stubs close to the patched BB if call, but far away from the
564       // hot path if a branch, since this branch target is the cold region
565       // (but first check that the far away stub will be in range).
566       BinaryBasicBlock *InsertionPoint = &BB;
567       if (Func.isSimple() && !BC.MIB->isCall(Inst) && FrontierAddress &&
568           !BB.isCold()) {
569         int BitsAvail = BC.MIB->getPCRelEncodingSize(Inst) - 1;
570         uint64_t Mask = ~((1ULL << BitsAvail) - 1);
571         assert(FrontierAddress > DotAddress &&
572                "Hot code should be before the frontier");
573         uint64_t PCRelTgt = FrontierAddress - DotAddress;
574         if (!(PCRelTgt & Mask))
575           InsertionPoint = Frontier;
576       }
577       // Always put stubs at the end of the function if non-simple. We can't
578       // change the layout of non-simple functions because it has jump tables
579       // that we do not control.
580       if (!Func.isSimple())
581         InsertionPoint = &*std::prev(Func.end());
582 
583       // Create a stub to handle a far-away target
584       Insertions.emplace_back(InsertionPoint,
585                               replaceTargetWithStub(BB, Inst, DotAddress,
586                                                     InsertionPoint == Frontier
587                                                         ? FrontierAddress
588                                                         : DotAddress));
589 
590       DotAddress += InsnSize;
591     }
592   }
593 
594   // Relax stubs if necessary
595   for (BinaryBasicBlock &BB : Func) {
596     if (!Stubs[&Func].count(&BB) || !BB.isValid())
597       continue;
598 
599     Modified |= relaxStub(BB);
600   }
601 
602   for (std::pair<BinaryBasicBlock *, std::unique_ptr<BinaryBasicBlock>> &Elmt :
603        Insertions) {
604     if (!Elmt.second)
605       continue;
606     std::vector<std::unique_ptr<BinaryBasicBlock>> NewBBs;
607     NewBBs.emplace_back(std::move(Elmt.second));
608     Func.insertBasicBlocks(Elmt.first, std::move(NewBBs), true);
609   }
610 
611   return Modified;
612 }
613 
614 void LongJmpPass::runOnFunctions(BinaryContext &BC) {
615   outs() << "BOLT-INFO: Starting stub-insertion pass\n";
616   std::vector<BinaryFunction *> Sorted = BC.getSortedFunctions();
617   bool Modified;
618   uint32_t Iterations = 0;
619   do {
620     ++Iterations;
621     Modified = false;
622     tentativeLayout(BC, Sorted);
623     updateStubGroups();
624     for (BinaryFunction *Func : Sorted) {
625       if (relax(*Func)) {
626         // Don't ruin non-simple functions, they can't afford to have the layout
627         // changed.
628         if (Func->isSimple())
629           Func->fixBranches();
630         Modified = true;
631       }
632     }
633   } while (Modified);
634   outs() << "BOLT-INFO: Inserted " << NumHotStubs
635          << " stubs in the hot area and " << NumColdStubs
636          << " stubs in the cold area. Shared " << NumSharedStubs
637          << " times, iterated " << Iterations << " times.\n";
638 }
639 } // namespace bolt
640 } // namespace llvm
641