[CodeGenPrepare] Drop nsw flags in `optimizeLoadExt` (#118180)
[llvm-project.git] / bolt / lib / Passes / Instrumentation.cpp
blob76766b05b9176071fcbaf77931fd39d8a42d3942
1 //===- bolt/Passes/Instrumentation.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 Instrumentation class.
11 //===----------------------------------------------------------------------===//
13 #include "bolt/Passes/Instrumentation.h"
14 #include "bolt/Core/ParallelUtilities.h"
15 #include "bolt/RuntimeLibs/InstrumentationRuntimeLibrary.h"
16 #include "bolt/Utils/CommandLineOpts.h"
17 #include "bolt/Utils/Utils.h"
18 #include "llvm/Support/CommandLine.h"
19 #include "llvm/Support/RWMutex.h"
20 #include <queue>
21 #include <stack>
22 #include <unordered_set>
24 #define DEBUG_TYPE "bolt-instrumentation"
26 using namespace llvm;
28 namespace opts {
29 extern cl::OptionCategory BoltInstrCategory;
31 cl::opt<std::string> InstrumentationFilename(
32 "instrumentation-file",
33 cl::desc("file name where instrumented profile will be saved (default: "
34 "/tmp/prof.fdata)"),
35 cl::init("/tmp/prof.fdata"), cl::Optional, cl::cat(BoltInstrCategory));
37 cl::opt<std::string> InstrumentationBinpath(
38 "instrumentation-binpath",
39 cl::desc("path to instrumented binary in case if /proc/self/map_files "
40 "is not accessible due to access restriction issues"),
41 cl::Optional, cl::cat(BoltInstrCategory));
43 cl::opt<bool> InstrumentationFileAppendPID(
44 "instrumentation-file-append-pid",
45 cl::desc("append PID to saved profile file name (default: false)"),
46 cl::init(false), cl::Optional, cl::cat(BoltInstrCategory));
48 cl::opt<bool> ConservativeInstrumentation(
49 "conservative-instrumentation",
50 cl::desc("disable instrumentation optimizations that sacrifice profile "
51 "accuracy (for debugging, default: false)"),
52 cl::init(false), cl::Optional, cl::cat(BoltInstrCategory));
54 cl::opt<uint32_t> InstrumentationSleepTime(
55 "instrumentation-sleep-time",
56 cl::desc("interval between profile writes (default: 0 = write only at "
57 "program end). This is useful for service workloads when you "
58 "want to dump profile every X minutes or if you are killing the "
59 "program and the profile is not being dumped at the end."),
60 cl::init(0), cl::Optional, cl::cat(BoltInstrCategory));
62 cl::opt<bool> InstrumentationNoCountersClear(
63 "instrumentation-no-counters-clear",
64 cl::desc("Don't clear counters across dumps "
65 "(use with instrumentation-sleep-time option)"),
66 cl::init(false), cl::Optional, cl::cat(BoltInstrCategory));
68 cl::opt<bool> InstrumentationWaitForks(
69 "instrumentation-wait-forks",
70 cl::desc("Wait until all forks of instrumented process will finish "
71 "(use with instrumentation-sleep-time option)"),
72 cl::init(false), cl::Optional, cl::cat(BoltInstrCategory));
74 cl::opt<bool>
75 InstrumentHotOnly("instrument-hot-only",
76 cl::desc("only insert instrumentation on hot functions "
77 "(needs profile, default: false)"),
78 cl::init(false), cl::Optional,
79 cl::cat(BoltInstrCategory));
81 cl::opt<bool> InstrumentCalls("instrument-calls",
82 cl::desc("record profile for inter-function "
83 "control flow activity (default: true)"),
84 cl::init(true), cl::Optional,
85 cl::cat(BoltInstrCategory));
86 } // namespace opts
88 namespace llvm {
89 namespace bolt {
91 static bool hasAArch64ExclusiveMemop(
92 BinaryFunction &Function,
93 std::unordered_set<const BinaryBasicBlock *> &BBToSkip) {
94 // FIXME ARMv8-a architecture reference manual says that software must avoid
95 // having any explicit memory accesses between exclusive load and associated
96 // store instruction. So for now skip instrumentation for basic blocks that
97 // have these instructions, since it might lead to runtime deadlock.
98 BinaryContext &BC = Function.getBinaryContext();
99 std::queue<std::pair<BinaryBasicBlock *, bool>> BBQueue; // {BB, isLoad}
100 std::unordered_set<BinaryBasicBlock *> Visited;
102 if (Function.getLayout().block_begin() == Function.getLayout().block_end())
103 return 0;
105 BinaryBasicBlock *BBfirst = *Function.getLayout().block_begin();
106 BBQueue.push({BBfirst, false});
108 while (!BBQueue.empty()) {
109 BinaryBasicBlock *BB = BBQueue.front().first;
110 bool IsLoad = BBQueue.front().second;
111 BBQueue.pop();
112 if (!Visited.insert(BB).second)
113 continue;
115 for (const MCInst &Inst : *BB) {
116 // Two loads one after another - skip whole function
117 if (BC.MIB->isAArch64ExclusiveLoad(Inst) && IsLoad) {
118 if (opts::Verbosity >= 2) {
119 outs() << "BOLT-INSTRUMENTER: function " << Function.getPrintName()
120 << " has two exclusive loads. Ignoring the function.\n";
122 return true;
125 if (BC.MIB->isAArch64ExclusiveLoad(Inst))
126 IsLoad = true;
128 if (IsLoad && BBToSkip.insert(BB).second) {
129 if (opts::Verbosity >= 2) {
130 outs() << "BOLT-INSTRUMENTER: skip BB " << BB->getName()
131 << " due to exclusive instruction in function "
132 << Function.getPrintName() << "\n";
136 if (!IsLoad && BC.MIB->isAArch64ExclusiveStore(Inst)) {
137 if (opts::Verbosity >= 2) {
138 outs() << "BOLT-INSTRUMENTER: function " << Function.getPrintName()
139 << " has exclusive store without corresponding load. Ignoring "
140 "the function.\n";
142 return true;
145 if (IsLoad && (BC.MIB->isAArch64ExclusiveStore(Inst) ||
146 BC.MIB->isAArch64ExclusiveClear(Inst)))
147 IsLoad = false;
150 if (IsLoad && BB->succ_size() == 0) {
151 if (opts::Verbosity >= 2) {
152 outs()
153 << "BOLT-INSTRUMENTER: function " << Function.getPrintName()
154 << " has exclusive load in trailing BB. Ignoring the function.\n";
156 return true;
159 for (BinaryBasicBlock *BBS : BB->successors())
160 BBQueue.push({BBS, IsLoad});
163 if (BBToSkip.size() == Visited.size()) {
164 if (opts::Verbosity >= 2) {
165 outs() << "BOLT-INSTRUMENTER: all BBs are marked with true. Ignoring the "
166 "function "
167 << Function.getPrintName() << "\n";
169 return true;
172 return false;
175 uint32_t Instrumentation::getFunctionNameIndex(const BinaryFunction &Function) {
176 auto Iter = FuncToStringIdx.find(&Function);
177 if (Iter != FuncToStringIdx.end())
178 return Iter->second;
179 size_t Idx = Summary->StringTable.size();
180 FuncToStringIdx.emplace(std::make_pair(&Function, Idx));
181 Summary->StringTable.append(getEscapedName(Function.getOneName()));
182 Summary->StringTable.append(1, '\0');
183 return Idx;
186 bool Instrumentation::createCallDescription(FunctionDescription &FuncDesc,
187 const BinaryFunction &FromFunction,
188 uint32_t From, uint32_t FromNodeID,
189 const BinaryFunction &ToFunction,
190 uint32_t To, bool IsInvoke) {
191 CallDescription CD;
192 // Ordinarily, we don't augment direct calls with an explicit counter, except
193 // when forced to do so or when we know this callee could be throwing
194 // exceptions, in which case there is no other way to accurately record its
195 // frequency.
196 bool ForceInstrumentation = opts::ConservativeInstrumentation || IsInvoke;
197 CD.FromLoc.FuncString = getFunctionNameIndex(FromFunction);
198 CD.FromLoc.Offset = From;
199 CD.FromNode = FromNodeID;
200 CD.Target = &ToFunction;
201 CD.ToLoc.FuncString = getFunctionNameIndex(ToFunction);
202 CD.ToLoc.Offset = To;
203 CD.Counter = ForceInstrumentation ? Summary->Counters.size() : 0xffffffff;
204 if (ForceInstrumentation)
205 ++DirectCallCounters;
206 FuncDesc.Calls.emplace_back(CD);
207 return ForceInstrumentation;
210 void Instrumentation::createIndCallDescription(
211 const BinaryFunction &FromFunction, uint32_t From) {
212 IndCallDescription ICD;
213 ICD.FromLoc.FuncString = getFunctionNameIndex(FromFunction);
214 ICD.FromLoc.Offset = From;
215 Summary->IndCallDescriptions.emplace_back(ICD);
218 void Instrumentation::createIndCallTargetDescription(
219 const BinaryFunction &ToFunction, uint32_t To) {
220 IndCallTargetDescription ICD;
221 ICD.ToLoc.FuncString = getFunctionNameIndex(ToFunction);
222 ICD.ToLoc.Offset = To;
223 ICD.Target = &ToFunction;
224 Summary->IndCallTargetDescriptions.emplace_back(ICD);
227 bool Instrumentation::createEdgeDescription(FunctionDescription &FuncDesc,
228 const BinaryFunction &FromFunction,
229 uint32_t From, uint32_t FromNodeID,
230 const BinaryFunction &ToFunction,
231 uint32_t To, uint32_t ToNodeID,
232 bool Instrumented) {
233 EdgeDescription ED;
234 auto Result = FuncDesc.EdgesSet.insert(std::make_pair(FromNodeID, ToNodeID));
235 // Avoid creating duplicated edge descriptions. This happens in CFGs where a
236 // block jumps to its fall-through.
237 if (Result.second == false)
238 return false;
239 ED.FromLoc.FuncString = getFunctionNameIndex(FromFunction);
240 ED.FromLoc.Offset = From;
241 ED.FromNode = FromNodeID;
242 ED.ToLoc.FuncString = getFunctionNameIndex(ToFunction);
243 ED.ToLoc.Offset = To;
244 ED.ToNode = ToNodeID;
245 ED.Counter = Instrumented ? Summary->Counters.size() : 0xffffffff;
246 if (Instrumented)
247 ++BranchCounters;
248 FuncDesc.Edges.emplace_back(ED);
249 return Instrumented;
252 void Instrumentation::createLeafNodeDescription(FunctionDescription &FuncDesc,
253 uint32_t Node) {
254 InstrumentedNode IN;
255 IN.Node = Node;
256 IN.Counter = Summary->Counters.size();
257 ++LeafNodeCounters;
258 FuncDesc.LeafNodes.emplace_back(IN);
261 InstructionListType
262 Instrumentation::createInstrumentationSnippet(BinaryContext &BC, bool IsLeaf) {
263 auto L = BC.scopeLock();
264 MCSymbol *Label = BC.Ctx->createNamedTempSymbol("InstrEntry");
265 Summary->Counters.emplace_back(Label);
266 return BC.MIB->createInstrIncMemory(Label, BC.Ctx.get(), IsLeaf,
267 BC.AsmInfo->getCodePointerSize());
270 // Helper instruction sequence insertion function
271 static BinaryBasicBlock::iterator
272 insertInstructions(InstructionListType &Instrs, BinaryBasicBlock &BB,
273 BinaryBasicBlock::iterator Iter) {
274 for (MCInst &NewInst : Instrs) {
275 Iter = BB.insertInstruction(Iter, NewInst);
276 ++Iter;
278 return Iter;
281 void Instrumentation::instrumentLeafNode(BinaryBasicBlock &BB,
282 BinaryBasicBlock::iterator Iter,
283 bool IsLeaf,
284 FunctionDescription &FuncDesc,
285 uint32_t Node) {
286 createLeafNodeDescription(FuncDesc, Node);
287 InstructionListType CounterInstrs = createInstrumentationSnippet(
288 BB.getFunction()->getBinaryContext(), IsLeaf);
289 insertInstructions(CounterInstrs, BB, Iter);
292 void Instrumentation::instrumentIndirectTarget(BinaryBasicBlock &BB,
293 BinaryBasicBlock::iterator &Iter,
294 BinaryFunction &FromFunction,
295 uint32_t From) {
296 auto L = FromFunction.getBinaryContext().scopeLock();
297 const size_t IndCallSiteID = Summary->IndCallDescriptions.size();
298 createIndCallDescription(FromFunction, From);
300 BinaryContext &BC = FromFunction.getBinaryContext();
301 bool IsTailCall = BC.MIB->isTailCall(*Iter);
302 InstructionListType CounterInstrs = BC.MIB->createInstrumentedIndirectCall(
303 std::move(*Iter),
304 IsTailCall ? IndTailCallHandlerExitBBFunction->getSymbol()
305 : IndCallHandlerExitBBFunction->getSymbol(),
306 IndCallSiteID, &*BC.Ctx);
308 Iter = BB.eraseInstruction(Iter);
309 Iter = insertInstructions(CounterInstrs, BB, Iter);
310 --Iter;
313 bool Instrumentation::instrumentOneTarget(
314 SplitWorklistTy &SplitWorklist, SplitInstrsTy &SplitInstrs,
315 BinaryBasicBlock::iterator &Iter, BinaryFunction &FromFunction,
316 BinaryBasicBlock &FromBB, uint32_t From, BinaryFunction &ToFunc,
317 BinaryBasicBlock *TargetBB, uint32_t ToOffset, bool IsLeaf, bool IsInvoke,
318 FunctionDescription *FuncDesc, uint32_t FromNodeID, uint32_t ToNodeID) {
319 BinaryContext &BC = FromFunction.getBinaryContext();
321 auto L = BC.scopeLock();
322 bool Created = true;
323 if (!TargetBB)
324 Created = createCallDescription(*FuncDesc, FromFunction, From, FromNodeID,
325 ToFunc, ToOffset, IsInvoke);
326 else
327 Created = createEdgeDescription(*FuncDesc, FromFunction, From, FromNodeID,
328 ToFunc, ToOffset, ToNodeID,
329 /*Instrumented=*/true);
330 if (!Created)
331 return false;
334 InstructionListType CounterInstrs = createInstrumentationSnippet(BC, IsLeaf);
336 const MCInst &Inst = *Iter;
337 if (BC.MIB->isCall(Inst)) {
338 // This code handles both
339 // - (regular) inter-function calls (cross-function control transfer),
340 // - (rare) intra-function calls (function-local control transfer)
341 Iter = insertInstructions(CounterInstrs, FromBB, Iter);
342 return true;
345 if (!TargetBB || !FuncDesc)
346 return false;
348 // Indirect branch, conditional branches or fall-throughs
349 // Regular cond branch, put counter at start of target block
351 // N.B.: (FromBB != TargetBBs) checks below handle conditional jumps where
352 // we can't put the instrumentation counter in this block because not all
353 // paths that reach it at this point will be taken and going to the target.
354 if (TargetBB->pred_size() == 1 && &FromBB != TargetBB &&
355 !TargetBB->isEntryPoint()) {
356 insertInstructions(CounterInstrs, *TargetBB, TargetBB->begin());
357 return true;
359 if (FromBB.succ_size() == 1 && &FromBB != TargetBB) {
360 Iter = insertInstructions(CounterInstrs, FromBB, Iter);
361 return true;
363 // Critical edge, create BB and put counter there
364 SplitWorklist.emplace_back(&FromBB, TargetBB);
365 SplitInstrs.emplace_back(std::move(CounterInstrs));
366 return true;
369 void Instrumentation::instrumentFunction(BinaryFunction &Function,
370 MCPlusBuilder::AllocatorIdTy AllocId) {
371 if (Function.hasUnknownControlFlow())
372 return;
374 BinaryContext &BC = Function.getBinaryContext();
375 if (BC.isMachO() && Function.hasName("___GLOBAL_init_65535/1"))
376 return;
378 std::unordered_set<const BinaryBasicBlock *> BBToSkip;
379 if (BC.isAArch64() && hasAArch64ExclusiveMemop(Function, BBToSkip))
380 return;
382 SplitWorklistTy SplitWorklist;
383 SplitInstrsTy SplitInstrs;
385 FunctionDescription *FuncDesc = nullptr;
387 std::unique_lock<llvm::sys::RWMutex> L(FDMutex);
388 Summary->FunctionDescriptions.emplace_back();
389 FuncDesc = &Summary->FunctionDescriptions.back();
392 FuncDesc->Function = &Function;
393 Function.disambiguateJumpTables(AllocId);
394 Function.deleteConservativeEdges();
396 std::unordered_map<const BinaryBasicBlock *, uint32_t> BBToID;
397 uint32_t Id = 0;
398 for (auto BBI = Function.begin(); BBI != Function.end(); ++BBI) {
399 BBToID[&*BBI] = Id++;
401 std::unordered_set<const BinaryBasicBlock *> VisitedSet;
402 // DFS to establish edges we will use for a spanning tree. Edges in the
403 // spanning tree can be instrumentation-free since their count can be
404 // inferred by solving flow equations on a bottom-up traversal of the tree.
405 // Exit basic blocks are always instrumented so we start the traversal with
406 // a minimum number of defined variables to make the equation solvable.
407 std::stack<std::pair<const BinaryBasicBlock *, BinaryBasicBlock *>> Stack;
408 std::unordered_map<const BinaryBasicBlock *,
409 std::set<const BinaryBasicBlock *>>
410 STOutSet;
411 for (auto BBI = Function.getLayout().block_rbegin();
412 BBI != Function.getLayout().block_rend(); ++BBI) {
413 if ((*BBI)->isEntryPoint() || (*BBI)->isLandingPad()) {
414 Stack.push(std::make_pair(nullptr, *BBI));
415 if (opts::InstrumentCalls && (*BBI)->isEntryPoint()) {
416 EntryNode E;
417 E.Node = BBToID[&**BBI];
418 E.Address = (*BBI)->getInputOffset();
419 FuncDesc->EntryNodes.emplace_back(E);
420 createIndCallTargetDescription(Function, (*BBI)->getInputOffset());
425 // Modified version of BinaryFunction::dfs() to build a spanning tree
426 if (!opts::ConservativeInstrumentation) {
427 while (!Stack.empty()) {
428 BinaryBasicBlock *BB;
429 const BinaryBasicBlock *Pred;
430 std::tie(Pred, BB) = Stack.top();
431 Stack.pop();
432 if (llvm::is_contained(VisitedSet, BB))
433 continue;
435 VisitedSet.insert(BB);
436 if (Pred)
437 STOutSet[Pred].insert(BB);
439 for (BinaryBasicBlock *SuccBB : BB->successors())
440 Stack.push(std::make_pair(BB, SuccBB));
444 // Determine whether this is a leaf function, which needs special
445 // instructions to protect the red zone
446 bool IsLeafFunction = true;
447 DenseSet<const BinaryBasicBlock *> InvokeBlocks;
448 for (const BinaryBasicBlock &BB : Function) {
449 for (const MCInst &Inst : BB) {
450 if (BC.MIB->isCall(Inst)) {
451 if (BC.MIB->isInvoke(Inst))
452 InvokeBlocks.insert(&BB);
453 if (!BC.MIB->isTailCall(Inst))
454 IsLeafFunction = false;
459 for (auto BBI = Function.begin(), BBE = Function.end(); BBI != BBE; ++BBI) {
460 BinaryBasicBlock &BB = *BBI;
462 // Skip BBs with exclusive load/stores
463 if (BBToSkip.find(&BB) != BBToSkip.end())
464 continue;
466 bool HasUnconditionalBranch = false;
467 bool HasJumpTable = false;
468 bool IsInvokeBlock = InvokeBlocks.count(&BB) > 0;
470 for (auto I = BB.begin(); I != BB.end(); ++I) {
471 const MCInst &Inst = *I;
472 if (!BC.MIB->getOffset(Inst))
473 continue;
475 const bool IsJumpTable = Function.getJumpTable(Inst);
476 if (IsJumpTable)
477 HasJumpTable = true;
478 else if (BC.MIB->isUnconditionalBranch(Inst))
479 HasUnconditionalBranch = true;
480 else if (!(BC.MIB->isCall(Inst) || BC.MIB->isConditionalBranch(Inst)))
481 continue;
483 const uint32_t FromOffset = *BC.MIB->getOffset(Inst);
484 const MCSymbol *Target = BC.MIB->getTargetSymbol(Inst);
485 BinaryBasicBlock *TargetBB = Function.getBasicBlockForLabel(Target);
486 uint32_t ToOffset = TargetBB ? TargetBB->getInputOffset() : 0;
487 BinaryFunction *TargetFunc =
488 TargetBB ? &Function : BC.getFunctionForSymbol(Target);
489 if (TargetFunc && BC.MIB->isCall(Inst)) {
490 if (opts::InstrumentCalls) {
491 const BinaryBasicBlock *ForeignBB =
492 TargetFunc->getBasicBlockForLabel(Target);
493 if (ForeignBB)
494 ToOffset = ForeignBB->getInputOffset();
495 instrumentOneTarget(SplitWorklist, SplitInstrs, I, Function, BB,
496 FromOffset, *TargetFunc, TargetBB, ToOffset,
497 IsLeafFunction, IsInvokeBlock, FuncDesc,
498 BBToID[&BB]);
500 continue;
502 if (TargetFunc) {
503 // Do not instrument edges in the spanning tree
504 if (llvm::is_contained(STOutSet[&BB], TargetBB)) {
505 auto L = BC.scopeLock();
506 createEdgeDescription(*FuncDesc, Function, FromOffset, BBToID[&BB],
507 Function, ToOffset, BBToID[TargetBB],
508 /*Instrumented=*/false);
509 continue;
511 instrumentOneTarget(SplitWorklist, SplitInstrs, I, Function, BB,
512 FromOffset, *TargetFunc, TargetBB, ToOffset,
513 IsLeafFunction, IsInvokeBlock, FuncDesc,
514 BBToID[&BB], BBToID[TargetBB]);
515 continue;
518 if (IsJumpTable) {
519 for (BinaryBasicBlock *&Succ : BB.successors()) {
520 // Do not instrument edges in the spanning tree
521 if (llvm::is_contained(STOutSet[&BB], &*Succ)) {
522 auto L = BC.scopeLock();
523 createEdgeDescription(*FuncDesc, Function, FromOffset, BBToID[&BB],
524 Function, Succ->getInputOffset(),
525 BBToID[&*Succ], /*Instrumented=*/false);
526 continue;
528 instrumentOneTarget(
529 SplitWorklist, SplitInstrs, I, Function, BB, FromOffset, Function,
530 &*Succ, Succ->getInputOffset(), IsLeafFunction, IsInvokeBlock,
531 FuncDesc, BBToID[&BB], BBToID[&*Succ]);
533 continue;
536 // Handle indirect calls -- could be direct calls with unknown targets
537 // or secondary entry points of known functions, so check it is indirect
538 // to be sure.
539 if (opts::InstrumentCalls && BC.MIB->isIndirectCall(*I))
540 instrumentIndirectTarget(BB, I, Function, FromOffset);
542 } // End of instructions loop
544 // Instrument fallthroughs (when the direct jump instruction is missing)
545 if (!HasUnconditionalBranch && !HasJumpTable && BB.succ_size() > 0 &&
546 BB.size() > 0) {
547 BinaryBasicBlock *FTBB = BB.getFallthrough();
548 assert(FTBB && "expected valid fall-through basic block");
549 auto I = BB.begin();
550 auto LastInstr = BB.end();
551 --LastInstr;
552 while (LastInstr != I && BC.MIB->isPseudo(*LastInstr))
553 --LastInstr;
554 uint32_t FromOffset = 0;
555 // The last instruction in the BB should have an annotation, except
556 // if it was branching to the end of the function as a result of
557 // __builtin_unreachable(), in which case it was deleted by fixBranches.
558 // Ignore this case. FIXME: force fixBranches() to preserve the offset.
559 if (!BC.MIB->getOffset(*LastInstr))
560 continue;
561 FromOffset = *BC.MIB->getOffset(*LastInstr);
563 // Do not instrument edges in the spanning tree
564 if (llvm::is_contained(STOutSet[&BB], FTBB)) {
565 auto L = BC.scopeLock();
566 createEdgeDescription(*FuncDesc, Function, FromOffset, BBToID[&BB],
567 Function, FTBB->getInputOffset(), BBToID[FTBB],
568 /*Instrumented=*/false);
569 continue;
571 instrumentOneTarget(SplitWorklist, SplitInstrs, I, Function, BB,
572 FromOffset, Function, FTBB, FTBB->getInputOffset(),
573 IsLeafFunction, IsInvokeBlock, FuncDesc, BBToID[&BB],
574 BBToID[FTBB]);
576 } // End of BBs loop
578 // Instrument spanning tree leaves
579 if (!opts::ConservativeInstrumentation) {
580 for (auto BBI = Function.begin(), BBE = Function.end(); BBI != BBE; ++BBI) {
581 BinaryBasicBlock &BB = *BBI;
582 if (STOutSet[&BB].size() == 0)
583 instrumentLeafNode(BB, BB.begin(), IsLeafFunction, *FuncDesc,
584 BBToID[&BB]);
588 // Consume list of critical edges: split them and add instrumentation to the
589 // newly created BBs
590 auto Iter = SplitInstrs.begin();
591 for (std::pair<BinaryBasicBlock *, BinaryBasicBlock *> &BBPair :
592 SplitWorklist) {
593 BinaryBasicBlock *NewBB = Function.splitEdge(BBPair.first, BBPair.second);
594 NewBB->addInstructions(Iter->begin(), Iter->end());
595 ++Iter;
598 // Unused now
599 FuncDesc->EdgesSet.clear();
602 Error Instrumentation::runOnFunctions(BinaryContext &BC) {
603 const unsigned Flags = BinarySection::getFlags(/*IsReadOnly=*/false,
604 /*IsText=*/false,
605 /*IsAllocatable=*/true);
606 BC.registerOrUpdateSection(".bolt.instr.counters", ELF::SHT_PROGBITS, Flags,
607 nullptr, 0, 1);
609 BC.registerOrUpdateNoteSection(".bolt.instr.tables", nullptr, 0,
610 /*Alignment=*/1,
611 /*IsReadOnly=*/true, ELF::SHT_NOTE);
613 Summary->IndCallCounterFuncPtr =
614 BC.Ctx->getOrCreateSymbol("__bolt_ind_call_counter_func_pointer");
615 Summary->IndTailCallCounterFuncPtr =
616 BC.Ctx->getOrCreateSymbol("__bolt_ind_tailcall_counter_func_pointer");
618 createAuxiliaryFunctions(BC);
620 ParallelUtilities::PredicateTy SkipPredicate = [&](const BinaryFunction &BF) {
621 return (!BF.isSimple() || BF.isIgnored() ||
622 (opts::InstrumentHotOnly && !BF.getKnownExecutionCount()));
625 ParallelUtilities::WorkFuncWithAllocTy WorkFun =
626 [&](BinaryFunction &BF, MCPlusBuilder::AllocatorIdTy AllocatorId) {
627 instrumentFunction(BF, AllocatorId);
630 ParallelUtilities::runOnEachFunctionWithUniqueAllocId(
631 BC, ParallelUtilities::SchedulingPolicy::SP_INST_QUADRATIC, WorkFun,
632 SkipPredicate, "instrumentation", /* ForceSequential=*/true);
634 if (BC.isMachO()) {
635 if (BC.StartFunctionAddress) {
636 BinaryFunction *Main =
637 BC.getBinaryFunctionAtAddress(*BC.StartFunctionAddress);
638 assert(Main && "Entry point function not found");
639 BinaryBasicBlock &BB = Main->front();
641 ErrorOr<BinarySection &> SetupSection =
642 BC.getUniqueSectionByName("I__setup");
643 if (!SetupSection)
644 return createFatalBOLTError("Cannot find I__setup section\n");
646 MCSymbol *Target = BC.registerNameAtAddress(
647 "__bolt_instr_setup", SetupSection->getAddress(), 0, 0);
648 MCInst NewInst;
649 BC.MIB->createCall(NewInst, Target, BC.Ctx.get());
650 BB.insertInstruction(BB.begin(), std::move(NewInst));
651 } else {
652 BC.errs() << "BOLT-WARNING: Entry point not found\n";
655 if (BinaryData *BD = BC.getBinaryDataByName("___GLOBAL_init_65535/1")) {
656 BinaryFunction *Ctor = BC.getBinaryFunctionAtAddress(BD->getAddress());
657 assert(Ctor && "___GLOBAL_init_65535 function not found");
658 BinaryBasicBlock &BB = Ctor->front();
659 ErrorOr<BinarySection &> FiniSection =
660 BC.getUniqueSectionByName("I__fini");
661 if (!FiniSection)
662 return createFatalBOLTError("Cannot find I__fini section");
664 MCSymbol *Target = BC.registerNameAtAddress(
665 "__bolt_instr_fini", FiniSection->getAddress(), 0, 0);
666 auto IsLEA = [&BC](const MCInst &Inst) { return BC.MIB->isLEA64r(Inst); };
667 const auto LEA = std::find_if(
668 std::next(llvm::find_if(reverse(BB), IsLEA)), BB.rend(), IsLEA);
669 LEA->getOperand(4).setExpr(
670 MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *BC.Ctx));
671 } else {
672 BC.errs() << "BOLT-WARNING: ___GLOBAL_init_65535 not found\n";
676 setupRuntimeLibrary(BC);
677 return Error::success();
680 void Instrumentation::createAuxiliaryFunctions(BinaryContext &BC) {
681 auto createSimpleFunction =
682 [&](StringRef Title, InstructionListType Instrs) -> BinaryFunction * {
683 BinaryFunction *Func = BC.createInjectedBinaryFunction(std::string(Title));
685 std::vector<std::unique_ptr<BinaryBasicBlock>> BBs;
686 BBs.emplace_back(Func->createBasicBlock());
687 BBs.back()->addInstructions(Instrs.begin(), Instrs.end());
688 BBs.back()->setCFIState(0);
689 Func->insertBasicBlocks(nullptr, std::move(BBs),
690 /*UpdateLayout=*/true,
691 /*UpdateCFIState=*/false);
692 Func->updateState(BinaryFunction::State::CFG_Finalized);
693 return Func;
696 // Here we are creating a set of functions to handle BB entry/exit.
697 // IndCallHandlerExitBB contains instructions to finish handling traffic to an
698 // indirect call. We pass it to createInstrumentedIndCallHandlerEntryBB(),
699 // which will check if a pointer to runtime library traffic accounting
700 // function was initialized (it is done during initialization of runtime
701 // library). If it is so - calls it. Then this routine returns to normal
702 // execution by jumping to exit BB.
703 BinaryFunction *IndCallHandlerExitBB =
704 createSimpleFunction("__bolt_instr_ind_call_handler",
705 BC.MIB->createInstrumentedIndCallHandlerExitBB());
707 IndCallHandlerExitBBFunction =
708 createSimpleFunction("__bolt_instr_ind_call_handler_func",
709 BC.MIB->createInstrumentedIndCallHandlerEntryBB(
710 Summary->IndCallCounterFuncPtr,
711 IndCallHandlerExitBB->getSymbol(), &*BC.Ctx));
713 BinaryFunction *IndTailCallHandlerExitBB = createSimpleFunction(
714 "__bolt_instr_ind_tail_call_handler",
715 BC.MIB->createInstrumentedIndTailCallHandlerExitBB());
717 IndTailCallHandlerExitBBFunction = createSimpleFunction(
718 "__bolt_instr_ind_tailcall_handler_func",
719 BC.MIB->createInstrumentedIndCallHandlerEntryBB(
720 Summary->IndTailCallCounterFuncPtr,
721 IndTailCallHandlerExitBB->getSymbol(), &*BC.Ctx));
723 createSimpleFunction("__bolt_num_counters_getter",
724 BC.MIB->createNumCountersGetter(BC.Ctx.get()));
725 createSimpleFunction("__bolt_instr_locations_getter",
726 BC.MIB->createInstrLocationsGetter(BC.Ctx.get()));
727 createSimpleFunction("__bolt_instr_tables_getter",
728 BC.MIB->createInstrTablesGetter(BC.Ctx.get()));
729 createSimpleFunction("__bolt_instr_num_funcs_getter",
730 BC.MIB->createInstrNumFuncsGetter(BC.Ctx.get()));
732 if (BC.isELF()) {
733 if (BC.StartFunctionAddress) {
734 BinaryFunction *Start =
735 BC.getBinaryFunctionAtAddress(*BC.StartFunctionAddress);
736 assert(Start && "Entry point function not found");
737 const MCSymbol *StartSym = Start->getSymbol();
738 createSimpleFunction(
739 "__bolt_start_trampoline",
740 BC.MIB->createSymbolTrampoline(StartSym, BC.Ctx.get()));
742 if (BC.FiniFunctionAddress) {
743 BinaryFunction *Fini =
744 BC.getBinaryFunctionAtAddress(*BC.FiniFunctionAddress);
745 assert(Fini && "Finalization function not found");
746 const MCSymbol *FiniSym = Fini->getSymbol();
747 createSimpleFunction(
748 "__bolt_fini_trampoline",
749 BC.MIB->createSymbolTrampoline(FiniSym, BC.Ctx.get()));
750 } else {
751 // Create dummy return function for trampoline to avoid issues
752 // with unknown symbol in runtime library. E.g. for static PIE
753 // executable
754 createSimpleFunction("__bolt_fini_trampoline",
755 BC.MIB->createReturnInstructionList(BC.Ctx.get()));
760 void Instrumentation::setupRuntimeLibrary(BinaryContext &BC) {
761 uint32_t FuncDescSize = Summary->getFDSize();
763 BC.outs() << "BOLT-INSTRUMENTER: Number of indirect call site descriptors: "
764 << Summary->IndCallDescriptions.size() << "\n";
765 BC.outs() << "BOLT-INSTRUMENTER: Number of indirect call target descriptors: "
766 << Summary->IndCallTargetDescriptions.size() << "\n";
767 BC.outs() << "BOLT-INSTRUMENTER: Number of function descriptors: "
768 << Summary->FunctionDescriptions.size() << "\n";
769 BC.outs() << "BOLT-INSTRUMENTER: Number of branch counters: "
770 << BranchCounters << "\n";
771 BC.outs() << "BOLT-INSTRUMENTER: Number of ST leaf node counters: "
772 << LeafNodeCounters << "\n";
773 BC.outs() << "BOLT-INSTRUMENTER: Number of direct call counters: "
774 << DirectCallCounters << "\n";
775 BC.outs() << "BOLT-INSTRUMENTER: Total number of counters: "
776 << Summary->Counters.size() << "\n";
777 BC.outs() << "BOLT-INSTRUMENTER: Total size of counters: "
778 << (Summary->Counters.size() * 8)
779 << " bytes (static alloc memory)\n";
780 BC.outs() << "BOLT-INSTRUMENTER: Total size of string table emitted: "
781 << Summary->StringTable.size() << " bytes in file\n";
782 BC.outs() << "BOLT-INSTRUMENTER: Total size of descriptors: "
783 << (FuncDescSize +
784 Summary->IndCallDescriptions.size() *
785 sizeof(IndCallDescription) +
786 Summary->IndCallTargetDescriptions.size() *
787 sizeof(IndCallTargetDescription))
788 << " bytes in file\n";
789 BC.outs() << "BOLT-INSTRUMENTER: Profile will be saved to file "
790 << opts::InstrumentationFilename << "\n";
792 InstrumentationRuntimeLibrary *RtLibrary =
793 static_cast<InstrumentationRuntimeLibrary *>(BC.getRuntimeLibrary());
794 assert(RtLibrary && "instrumentation runtime library object must be set");
795 RtLibrary->setSummary(std::move(Summary));
797 } // namespace bolt
798 } // namespace llvm