1//===- GCOVProfiling.cpp - Insert edge counters for gcov profiling --------===//
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 pass implements GCOV-style profiling. When this pass is run it emits
10// "gcno" files next to the existing source, and instruments the code that runs
11// to records the edges between blocks that run and emit a complementary "gcda"
12// file on exit.
13//
14//===----------------------------------------------------------------------===//
15
16#include "llvm/ADT/Hashing.h"
17#include "llvm/ADT/MapVector.h"
18#include "llvm/ADT/STLExtras.h"
19#include "llvm/ADT/Sequence.h"
20#include "llvm/ADT/StringMap.h"
21#include "llvm/Analysis/BlockFrequencyInfo.h"
22#include "llvm/Analysis/BranchProbabilityInfo.h"
23#include "llvm/Analysis/TargetLibraryInfo.h"
24#include "llvm/IR/DebugInfo.h"
25#include "llvm/IR/DebugLoc.h"
26#include "llvm/IR/EHPersonalities.h"
27#include "llvm/IR/IRBuilder.h"
28#include "llvm/IR/InstIterator.h"
29#include "llvm/IR/Instructions.h"
30#include "llvm/IR/IntrinsicInst.h"
31#include "llvm/IR/Module.h"
32#include "llvm/Support/CRC.h"
33#include "llvm/Support/CommandLine.h"
34#include "llvm/Support/Debug.h"
35#include "llvm/Support/FileSystem.h"
36#include "llvm/Support/Path.h"
37#include "llvm/Support/Regex.h"
38#include "llvm/Support/raw_ostream.h"
39#include "llvm/Transforms/Instrumentation.h"
40#include "llvm/Transforms/Instrumentation/CFGMST.h"
41#include "llvm/Transforms/Instrumentation/GCOVProfiler.h"
42#include "llvm/Transforms/Utils/ModuleUtils.h"
43#include <algorithm>
44#include <memory>
45#include <string>
46#include <utility>
47
48using namespace llvm;
49namespace endian = llvm::support::endian;
50
51#define DEBUG_TYPE "insert-gcov-profiling"
52
53enum : uint32_t {
54 GCOV_ARC_ON_TREE = 1 << 0,
55
56 GCOV_TAG_FUNCTION = 0x01000000,
57 GCOV_TAG_BLOCKS = 0x01410000,
58 GCOV_TAG_ARCS = 0x01430000,
59 GCOV_TAG_LINES = 0x01450000,
60};
61
62static cl::opt<std::string> DefaultGCOVVersion("default-gcov-version",
63 cl::init(Val: "408*"), cl::Hidden,
64 cl::ValueRequired);
65
66static cl::opt<bool> AtomicCounter("gcov-atomic-counter", cl::Hidden,
67 cl::desc("Make counter updates atomic"));
68
69// Returns the number of words which will be used to represent this string.
70static unsigned wordsOfString(StringRef s) {
71 // Length + NUL-terminated string + 0~3 padding NULs.
72 return (s.size() / 4) + 2;
73}
74
75GCOVOptions GCOVOptions::getDefault() {
76 GCOVOptions Options;
77 Options.EmitNotes = true;
78 Options.EmitData = true;
79 Options.NoRedZone = false;
80 Options.Atomic = AtomicCounter;
81
82 if (DefaultGCOVVersion.size() != 4) {
83 llvm::report_fatal_error(reason: Twine("Invalid -default-gcov-version: ") +
84 DefaultGCOVVersion, /*GenCrashDiag=*/gen_crash_diag: false);
85 }
86 memcpy(dest: Options.Version, src: DefaultGCOVVersion.c_str(), n: 4);
87 return Options;
88}
89
90namespace {
91class GCOVFunction;
92
93class GCOVProfiler {
94public:
95 GCOVProfiler() : GCOVProfiler(GCOVOptions::getDefault()) {}
96 GCOVProfiler(const GCOVOptions &Opts) : Options(Opts) {}
97 bool
98 runOnModule(Module &M, function_ref<BlockFrequencyInfo *(Function &F)> GetBFI,
99 function_ref<BranchProbabilityInfo *(Function &F)> GetBPI,
100 std::function<const TargetLibraryInfo &(Function &F)> GetTLI);
101
102 void write(uint32_t i) {
103 char Bytes[4];
104 endian::write32(P: Bytes, V: i, E: Endian);
105 os->write(Ptr: Bytes, Size: 4);
106 }
107 void writeString(StringRef s) {
108 write(i: wordsOfString(s) - 1);
109 os->write(Ptr: s.data(), Size: s.size());
110 os->write_zeros(NumZeros: 4 - s.size() % 4);
111 }
112 void writeBytes(const char *Bytes, int Size) { os->write(Ptr: Bytes, Size); }
113
114private:
115 // Create the .gcno files for the Module based on DebugInfo.
116 bool
117 emitProfileNotes(NamedMDNode *CUNode, bool HasExecOrFork,
118 function_ref<BlockFrequencyInfo *(Function &F)> GetBFI,
119 function_ref<BranchProbabilityInfo *(Function &F)> GetBPI,
120 function_ref<const TargetLibraryInfo &(Function &F)> GetTLI);
121
122 Function *createInternalFunction(FunctionType *FTy, StringRef Name,
123 StringRef MangledType = "");
124 void emitGlobalConstructor(
125 SmallVectorImpl<std::pair<GlobalVariable *, MDNode *>> &CountersBySP);
126
127 bool isFunctionInstrumented(const Function &F);
128 std::vector<Regex> createRegexesFromString(StringRef RegexesStr);
129 static bool doesFilenameMatchARegex(StringRef Filename,
130 std::vector<Regex> &Regexes);
131
132 // Get pointers to the functions in the runtime library.
133 FunctionCallee getStartFileFunc(const TargetLibraryInfo *TLI);
134 FunctionCallee getEmitFunctionFunc(const TargetLibraryInfo *TLI);
135 FunctionCallee getEmitArcsFunc(const TargetLibraryInfo *TLI);
136 FunctionCallee getSummaryInfoFunc();
137 FunctionCallee getEndFileFunc();
138
139 // Add the function to write out all our counters to the global destructor
140 // list.
141 Function *
142 insertCounterWriteout(ArrayRef<std::pair<GlobalVariable *, MDNode *>>);
143 Function *insertReset(ArrayRef<std::pair<GlobalVariable *, MDNode *>>);
144
145 bool AddFlushBeforeForkAndExec();
146
147 enum class GCovFileType { GCNO, GCDA };
148 std::string mangleName(const DICompileUnit *CU, GCovFileType FileType);
149
150 GCOVOptions Options;
151 llvm::endianness Endian;
152 raw_ostream *os;
153
154 // Checksum, produced by hash of EdgeDestinations
155 SmallVector<uint32_t, 4> FileChecksums;
156
157 Module *M = nullptr;
158 std::function<const TargetLibraryInfo &(Function &F)> GetTLI;
159 LLVMContext *Ctx = nullptr;
160 SmallVector<std::unique_ptr<GCOVFunction>, 16> Funcs;
161 std::vector<Regex> FilterRe;
162 std::vector<Regex> ExcludeRe;
163 DenseSet<const BasicBlock *> ExecBlocks;
164 StringMap<bool> InstrumentedFiles;
165};
166
167struct BBInfo {
168 BBInfo *Group;
169 uint32_t Index;
170 uint32_t Rank = 0;
171
172 BBInfo(unsigned Index) : Group(this), Index(Index) {}
173 std::string infoString() const {
174 return (Twine("Index=") + Twine(Index)).str();
175 }
176};
177
178struct Edge {
179 // This class implements the CFG edges. Note the CFG can be a multi-graph.
180 // So there might be multiple edges with same SrcBB and DestBB.
181 const BasicBlock *SrcBB;
182 const BasicBlock *DestBB;
183 uint64_t Weight;
184 BasicBlock *Place = nullptr;
185 uint32_t SrcNumber, DstNumber;
186 bool InMST = false;
187 bool Removed = false;
188 bool IsCritical = false;
189
190 Edge(const BasicBlock *Src, const BasicBlock *Dest, uint64_t W = 1)
191 : SrcBB(Src), DestBB(Dest), Weight(W) {}
192
193 // Return the information string of an edge.
194 std::string infoString() const {
195 return (Twine(Removed ? "-" : " ") + (InMST ? " " : "*") +
196 (IsCritical ? "c" : " ") + " W=" + Twine(Weight))
197 .str();
198 }
199};
200}
201
202static StringRef getFunctionName(const DISubprogram *SP) {
203 if (!SP->getLinkageName().empty())
204 return SP->getLinkageName();
205 return SP->getName();
206}
207
208/// Extract a filename for a DISubprogram.
209///
210/// Prefer relative paths in the coverage notes. Clang also may split
211/// up absolute paths into a directory and filename component. When
212/// the relative path doesn't exist, reconstruct the absolute path.
213static SmallString<128> getFilename(const DISubprogram *SP) {
214 SmallString<128> Path;
215 StringRef RelPath = SP->getFilename();
216 if (sys::fs::exists(Path: RelPath))
217 Path = RelPath;
218 else
219 sys::path::append(path&: Path, a: SP->getDirectory(), b: SP->getFilename());
220 return Path;
221}
222
223namespace {
224 class GCOVRecord {
225 protected:
226 GCOVProfiler *P;
227
228 GCOVRecord(GCOVProfiler *P) : P(P) {}
229
230 void write(uint32_t i) { P->write(i); }
231 void writeString(StringRef s) { P->writeString(s); }
232 void writeBytes(const char *Bytes, int Size) { P->writeBytes(Bytes, Size); }
233 };
234
235 class GCOVFunction;
236 class GCOVBlock;
237
238 // Constructed only by requesting it from a GCOVBlock, this object stores a
239 // list of line numbers and a single filename, representing lines that belong
240 // to the block.
241 class GCOVLines : public GCOVRecord {
242 public:
243 void addLine(uint32_t Line) {
244 assert(Line != 0 && "Line zero is not a valid real line number.");
245 Lines.push_back(Elt: Line);
246 }
247
248 uint32_t length() const {
249 return 1 + wordsOfString(s: Filename) + Lines.size();
250 }
251
252 void writeOut() {
253 write(i: 0);
254 writeString(s: Filename);
255 for (uint32_t L : Lines)
256 write(i: L);
257 }
258
259 GCOVLines(GCOVProfiler *P, StringRef F)
260 : GCOVRecord(P), Filename(std::string(F)) {}
261
262 private:
263 std::string Filename;
264 SmallVector<uint32_t, 32> Lines;
265 };
266
267
268 // Represent a basic block in GCOV. Each block has a unique number in the
269 // function, number of lines belonging to each block, and a set of edges to
270 // other blocks.
271 class GCOVBlock : public GCOVRecord {
272 public:
273 GCOVLines &getFile(StringRef Filename) {
274 return LinesByFile.try_emplace(Key: Filename, Args&: P, Args&: Filename).first->second;
275 }
276
277 void addEdge(GCOVBlock &Successor, uint32_t Flags) {
278 OutEdges.emplace_back(Args: &Successor, Args&: Flags);
279 }
280
281 void writeOut() {
282 uint32_t Len = 3;
283 SmallVector<StringMapEntry<GCOVLines> *, 32> SortedLinesByFile;
284 for (auto &I : LinesByFile) {
285 Len += I.second.length();
286 SortedLinesByFile.push_back(Elt: &I);
287 }
288
289 write(i: GCOV_TAG_LINES);
290 write(i: Len);
291 write(i: Number);
292
293 llvm::sort(C&: SortedLinesByFile, Comp: [](StringMapEntry<GCOVLines> *LHS,
294 StringMapEntry<GCOVLines> *RHS) {
295 return LHS->getKey() < RHS->getKey();
296 });
297 for (auto &I : SortedLinesByFile)
298 I->getValue().writeOut();
299 write(i: 0);
300 write(i: 0);
301 }
302
303 GCOVBlock(const GCOVBlock &RHS) : GCOVRecord(RHS), Number(RHS.Number) {
304 // Only allow copy before edges and lines have been added. After that,
305 // there are inter-block pointers (eg: edges) that won't take kindly to
306 // blocks being copied or moved around.
307 assert(LinesByFile.empty());
308 assert(OutEdges.empty());
309 }
310
311 uint32_t Number;
312 SmallVector<std::pair<GCOVBlock *, uint32_t>, 4> OutEdges;
313
314 private:
315 friend class GCOVFunction;
316
317 GCOVBlock(GCOVProfiler *P, uint32_t Number)
318 : GCOVRecord(P), Number(Number) {}
319
320 StringMap<GCOVLines> LinesByFile;
321 };
322
323 // A function has a unique identifier, a checksum (we leave as zero) and a
324 // set of blocks and a map of edges between blocks. This is the only GCOV
325 // object users can construct, the blocks and lines will be rooted here.
326 class GCOVFunction : public GCOVRecord {
327 public:
328 GCOVFunction(GCOVProfiler *P, Function *F, const DISubprogram *SP,
329 unsigned EndLine, uint32_t Ident, int Version)
330 : GCOVRecord(P), SP(SP), EndLine(EndLine), Ident(Ident),
331 Version(Version), EntryBlock(P, 0), ReturnBlock(P, 1) {
332 LLVM_DEBUG(dbgs() << "Function: " << getFunctionName(SP) << "\n");
333 bool ExitBlockBeforeBody = Version >= 48;
334 uint32_t i = ExitBlockBeforeBody ? 2 : 1;
335 for (BasicBlock &BB : *F)
336 Blocks.insert(KV: std::make_pair(x: &BB, y: GCOVBlock(P, i++)));
337 if (!ExitBlockBeforeBody)
338 ReturnBlock.Number = i;
339
340 std::string FunctionNameAndLine;
341 raw_string_ostream FNLOS(FunctionNameAndLine);
342 FNLOS << getFunctionName(SP) << SP->getLine();
343 FNLOS.flush();
344 FuncChecksum = hash_value(arg: FunctionNameAndLine);
345 }
346
347 GCOVBlock &getBlock(const BasicBlock *BB) {
348 return Blocks.find(Key: const_cast<BasicBlock *>(BB))->second;
349 }
350
351 GCOVBlock &getEntryBlock() { return EntryBlock; }
352 GCOVBlock &getReturnBlock() {
353 return ReturnBlock;
354 }
355
356 uint32_t getFuncChecksum() const {
357 return FuncChecksum;
358 }
359
360 void writeOut(uint32_t CfgChecksum) {
361 write(i: GCOV_TAG_FUNCTION);
362 SmallString<128> Filename = getFilename(SP);
363 uint32_t BlockLen =
364 2 + (Version >= 47) + wordsOfString(s: getFunctionName(SP));
365 if (Version < 80)
366 BlockLen += wordsOfString(s: Filename) + 1;
367 else
368 BlockLen += 1 + wordsOfString(s: Filename) + 3 + (Version >= 90);
369
370 write(i: BlockLen);
371 write(i: Ident);
372 write(i: FuncChecksum);
373 if (Version >= 47)
374 write(i: CfgChecksum);
375 writeString(s: getFunctionName(SP));
376 if (Version < 80) {
377 writeString(s: Filename);
378 write(i: SP->getLine());
379 } else {
380 write(i: SP->isArtificial()); // artificial
381 writeString(s: Filename);
382 write(i: SP->getLine()); // start_line
383 write(i: 0); // start_column
384 // EndLine is the last line with !dbg. It is not the } line as in GCC,
385 // but good enough.
386 write(i: EndLine);
387 if (Version >= 90)
388 write(i: 0); // end_column
389 }
390
391 // Emit count of blocks.
392 write(i: GCOV_TAG_BLOCKS);
393 if (Version < 80) {
394 write(i: Blocks.size() + 2);
395 for (int i = Blocks.size() + 2; i; --i)
396 write(i: 0);
397 } else {
398 write(i: 1);
399 write(i: Blocks.size() + 2);
400 }
401 LLVM_DEBUG(dbgs() << (Blocks.size() + 1) << " blocks\n");
402
403 // Emit edges between blocks.
404 const uint32_t Outgoing = EntryBlock.OutEdges.size();
405 if (Outgoing) {
406 write(i: GCOV_TAG_ARCS);
407 write(i: Outgoing * 2 + 1);
408 write(i: EntryBlock.Number);
409 for (const auto &E : EntryBlock.OutEdges) {
410 write(i: E.first->Number);
411 write(i: E.second);
412 }
413 }
414 for (auto &It : Blocks) {
415 const GCOVBlock &Block = It.second;
416 if (Block.OutEdges.empty()) continue;
417
418 write(i: GCOV_TAG_ARCS);
419 write(i: Block.OutEdges.size() * 2 + 1);
420 write(i: Block.Number);
421 for (const auto &E : Block.OutEdges) {
422 write(i: E.first->Number);
423 write(i: E.second);
424 }
425 }
426
427 // Emit lines for each block.
428 for (auto &It : Blocks)
429 It.second.writeOut();
430 }
431
432 public:
433 const DISubprogram *SP;
434 unsigned EndLine;
435 uint32_t Ident;
436 uint32_t FuncChecksum;
437 int Version;
438 MapVector<BasicBlock *, GCOVBlock> Blocks;
439 GCOVBlock EntryBlock;
440 GCOVBlock ReturnBlock;
441 };
442}
443
444// RegexesStr is a string containing differents regex separated by a semi-colon.
445// For example "foo\..*$;bar\..*$".
446std::vector<Regex> GCOVProfiler::createRegexesFromString(StringRef RegexesStr) {
447 std::vector<Regex> Regexes;
448 while (!RegexesStr.empty()) {
449 std::pair<StringRef, StringRef> HeadTail = RegexesStr.split(Separator: ';');
450 if (!HeadTail.first.empty()) {
451 Regex Re(HeadTail.first);
452 std::string Err;
453 if (!Re.isValid(Error&: Err)) {
454 Ctx->emitError(ErrorStr: Twine("Regex ") + HeadTail.first +
455 " is not valid: " + Err);
456 }
457 Regexes.emplace_back(args: std::move(Re));
458 }
459 RegexesStr = HeadTail.second;
460 }
461 return Regexes;
462}
463
464bool GCOVProfiler::doesFilenameMatchARegex(StringRef Filename,
465 std::vector<Regex> &Regexes) {
466 for (Regex &Re : Regexes)
467 if (Re.match(String: Filename))
468 return true;
469 return false;
470}
471
472bool GCOVProfiler::isFunctionInstrumented(const Function &F) {
473 if (FilterRe.empty() && ExcludeRe.empty()) {
474 return true;
475 }
476 SmallString<128> Filename = getFilename(SP: F.getSubprogram());
477 auto It = InstrumentedFiles.find(Key: Filename);
478 if (It != InstrumentedFiles.end()) {
479 return It->second;
480 }
481
482 SmallString<256> RealPath;
483 StringRef RealFilename;
484
485 // Path can be
486 // /usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/*.h so for
487 // such a case we must get the real_path.
488 if (sys::fs::real_path(path: Filename, output&: RealPath)) {
489 // real_path can fail with path like "foo.c".
490 RealFilename = Filename;
491 } else {
492 RealFilename = RealPath;
493 }
494
495 bool ShouldInstrument;
496 if (FilterRe.empty()) {
497 ShouldInstrument = !doesFilenameMatchARegex(Filename: RealFilename, Regexes&: ExcludeRe);
498 } else if (ExcludeRe.empty()) {
499 ShouldInstrument = doesFilenameMatchARegex(Filename: RealFilename, Regexes&: FilterRe);
500 } else {
501 ShouldInstrument = doesFilenameMatchARegex(Filename: RealFilename, Regexes&: FilterRe) &&
502 !doesFilenameMatchARegex(Filename: RealFilename, Regexes&: ExcludeRe);
503 }
504 InstrumentedFiles[Filename] = ShouldInstrument;
505 return ShouldInstrument;
506}
507
508std::string GCOVProfiler::mangleName(const DICompileUnit *CU,
509 GCovFileType OutputType) {
510 bool Notes = OutputType == GCovFileType::GCNO;
511
512 if (NamedMDNode *GCov = M->getNamedMetadata(Name: "llvm.gcov")) {
513 for (int i = 0, e = GCov->getNumOperands(); i != e; ++i) {
514 MDNode *N = GCov->getOperand(i);
515 bool ThreeElement = N->getNumOperands() == 3;
516 if (!ThreeElement && N->getNumOperands() != 2)
517 continue;
518 if (dyn_cast<MDNode>(Val: N->getOperand(I: ThreeElement ? 2 : 1)) != CU)
519 continue;
520
521 if (ThreeElement) {
522 // These nodes have no mangling to apply, it's stored mangled in the
523 // bitcode.
524 MDString *NotesFile = dyn_cast<MDString>(Val: N->getOperand(I: 0));
525 MDString *DataFile = dyn_cast<MDString>(Val: N->getOperand(I: 1));
526 if (!NotesFile || !DataFile)
527 continue;
528 return std::string(Notes ? NotesFile->getString()
529 : DataFile->getString());
530 }
531
532 MDString *GCovFile = dyn_cast<MDString>(Val: N->getOperand(I: 0));
533 if (!GCovFile)
534 continue;
535
536 SmallString<128> Filename = GCovFile->getString();
537 sys::path::replace_extension(path&: Filename, extension: Notes ? "gcno" : "gcda");
538 return std::string(Filename);
539 }
540 }
541
542 SmallString<128> Filename = CU->getFilename();
543 sys::path::replace_extension(path&: Filename, extension: Notes ? "gcno" : "gcda");
544 StringRef FName = sys::path::filename(path: Filename);
545 SmallString<128> CurPath;
546 if (sys::fs::current_path(result&: CurPath))
547 return std::string(FName);
548 sys::path::append(path&: CurPath, a: FName);
549 return std::string(CurPath);
550}
551
552bool GCOVProfiler::runOnModule(
553 Module &M, function_ref<BlockFrequencyInfo *(Function &F)> GetBFI,
554 function_ref<BranchProbabilityInfo *(Function &F)> GetBPI,
555 std::function<const TargetLibraryInfo &(Function &F)> GetTLI) {
556 this->M = &M;
557 this->GetTLI = std::move(GetTLI);
558 Ctx = &M.getContext();
559
560 NamedMDNode *CUNode = M.getNamedMetadata(Name: "llvm.dbg.cu");
561 if (!CUNode || (!Options.EmitNotes && !Options.EmitData))
562 return false;
563
564 bool HasExecOrFork = AddFlushBeforeForkAndExec();
565
566 FilterRe = createRegexesFromString(RegexesStr: Options.Filter);
567 ExcludeRe = createRegexesFromString(RegexesStr: Options.Exclude);
568 emitProfileNotes(CUNode, HasExecOrFork, GetBFI, GetBPI, GetTLI: this->GetTLI);
569 return true;
570}
571
572PreservedAnalyses GCOVProfilerPass::run(Module &M,
573 ModuleAnalysisManager &AM) {
574
575 GCOVProfiler Profiler(GCOVOpts);
576 FunctionAnalysisManager &FAM =
577 AM.getResult<FunctionAnalysisManagerModuleProxy>(IR&: M).getManager();
578
579 auto GetBFI = [&FAM](Function &F) {
580 return &FAM.getResult<BlockFrequencyAnalysis>(IR&: F);
581 };
582 auto GetBPI = [&FAM](Function &F) {
583 return &FAM.getResult<BranchProbabilityAnalysis>(IR&: F);
584 };
585 auto GetTLI = [&FAM](Function &F) -> const TargetLibraryInfo & {
586 return FAM.getResult<TargetLibraryAnalysis>(IR&: F);
587 };
588
589 if (!Profiler.runOnModule(M, GetBFI, GetBPI, GetTLI))
590 return PreservedAnalyses::all();
591
592 return PreservedAnalyses::none();
593}
594
595static bool functionHasLines(const Function &F, unsigned &EndLine) {
596 // Check whether this function actually has any source lines. Not only
597 // do these waste space, they also can crash gcov.
598 EndLine = 0;
599 for (const auto &BB : F) {
600 for (const auto &I : BB) {
601 // Debug intrinsic locations correspond to the location of the
602 // declaration, not necessarily any statements or expressions.
603 if (isa<DbgInfoIntrinsic>(Val: &I)) continue;
604
605 const DebugLoc &Loc = I.getDebugLoc();
606 if (!Loc)
607 continue;
608
609 // Artificial lines such as calls to the global constructors.
610 if (Loc.getLine() == 0) continue;
611 EndLine = std::max(a: EndLine, b: Loc.getLine());
612
613 return true;
614 }
615 }
616 return false;
617}
618
619static bool isUsingScopeBasedEH(Function &F) {
620 if (!F.hasPersonalityFn()) return false;
621
622 EHPersonality Personality = classifyEHPersonality(Pers: F.getPersonalityFn());
623 return isScopedEHPersonality(Pers: Personality);
624}
625
626bool GCOVProfiler::AddFlushBeforeForkAndExec() {
627 const TargetLibraryInfo *TLI = nullptr;
628 SmallVector<CallInst *, 2> Forks;
629 SmallVector<CallInst *, 2> Execs;
630 for (auto &F : M->functions()) {
631 TLI = TLI == nullptr ? &GetTLI(F) : TLI;
632 for (auto &I : instructions(F)) {
633 if (CallInst *CI = dyn_cast<CallInst>(Val: &I)) {
634 if (Function *Callee = CI->getCalledFunction()) {
635 LibFunc LF;
636 if (TLI->getLibFunc(FDecl: *Callee, F&: LF)) {
637 if (LF == LibFunc_fork) {
638#if !defined(_WIN32)
639 Forks.push_back(Elt: CI);
640#endif
641 } else if (LF == LibFunc_execl || LF == LibFunc_execle ||
642 LF == LibFunc_execlp || LF == LibFunc_execv ||
643 LF == LibFunc_execvp || LF == LibFunc_execve ||
644 LF == LibFunc_execvpe || LF == LibFunc_execvP) {
645 Execs.push_back(Elt: CI);
646 }
647 }
648 }
649 }
650 }
651 }
652
653 for (auto *F : Forks) {
654 IRBuilder<> Builder(F);
655 BasicBlock *Parent = F->getParent();
656 auto NextInst = ++F->getIterator();
657
658 // We've a fork so just reset the counters in the child process
659 FunctionType *FTy = FunctionType::get(Result: Builder.getInt32Ty(), Params: {}, isVarArg: false);
660 FunctionCallee GCOVFork = M->getOrInsertFunction(
661 Name: "__gcov_fork", T: FTy,
662 AttributeList: TLI->getAttrList(C: Ctx, ArgNos: {}, /*Signed=*/true, /*Ret=*/true));
663 F->setCalledFunction(GCOVFork);
664
665 // We split just after the fork to have a counter for the lines after
666 // Anyway there's a bug:
667 // void foo() { fork(); }
668 // void bar() { foo(); blah(); }
669 // then "blah();" will be called 2 times but showed as 1
670 // because "blah()" belongs to the same block as "foo();"
671 Parent->splitBasicBlock(I: NextInst);
672
673 // back() is a br instruction with a debug location
674 // equals to the one from NextAfterFork
675 // So to avoid to have two debug locs on two blocks just change it
676 DebugLoc Loc = F->getDebugLoc();
677 Parent->back().setDebugLoc(Loc);
678 }
679
680 for (auto *E : Execs) {
681 IRBuilder<> Builder(E);
682 BasicBlock *Parent = E->getParent();
683 auto NextInst = ++E->getIterator();
684
685 // Since the process is replaced by a new one we need to write out gcdas
686 // No need to reset the counters since they'll be lost after the exec**
687 FunctionType *FTy = FunctionType::get(Result: Builder.getVoidTy(), Params: {}, isVarArg: false);
688 FunctionCallee WriteoutF =
689 M->getOrInsertFunction(Name: "llvm_writeout_files", T: FTy);
690 Builder.CreateCall(Callee: WriteoutF);
691
692 DebugLoc Loc = E->getDebugLoc();
693 Builder.SetInsertPoint(&*NextInst);
694 // If the exec** fails we must reset the counters since they've been
695 // dumped
696 FunctionCallee ResetF = M->getOrInsertFunction(Name: "llvm_reset_counters", T: FTy);
697 Builder.CreateCall(Callee: ResetF)->setDebugLoc(Loc);
698 ExecBlocks.insert(V: Parent);
699 Parent->splitBasicBlock(I: NextInst);
700 Parent->back().setDebugLoc(Loc);
701 }
702
703 return !Forks.empty() || !Execs.empty();
704}
705
706static BasicBlock *getInstrBB(CFGMST<Edge, BBInfo> &MST, Edge &E,
707 const DenseSet<const BasicBlock *> &ExecBlocks) {
708 if (E.InMST || E.Removed)
709 return nullptr;
710
711 BasicBlock *SrcBB = const_cast<BasicBlock *>(E.SrcBB);
712 BasicBlock *DestBB = const_cast<BasicBlock *>(E.DestBB);
713 // For a fake edge, instrument the real BB.
714 if (SrcBB == nullptr)
715 return DestBB;
716 if (DestBB == nullptr)
717 return SrcBB;
718
719 auto CanInstrument = [](BasicBlock *BB) -> BasicBlock * {
720 // There are basic blocks (such as catchswitch) cannot be instrumented.
721 // If the returned first insertion point is the end of BB, skip this BB.
722 if (BB->getFirstInsertionPt() == BB->end())
723 return nullptr;
724 return BB;
725 };
726
727 // Instrument the SrcBB if it has a single successor,
728 // otherwise, the DestBB if this is not a critical edge.
729 Instruction *TI = SrcBB->getTerminator();
730 if (TI->getNumSuccessors() <= 1 && !ExecBlocks.count(V: SrcBB))
731 return CanInstrument(SrcBB);
732 if (!E.IsCritical)
733 return CanInstrument(DestBB);
734
735 // Some IndirectBr critical edges cannot be split by the previous
736 // SplitIndirectBrCriticalEdges call. Bail out.
737 const unsigned SuccNum = GetSuccessorNumber(BB: SrcBB, Succ: DestBB);
738 BasicBlock *InstrBB =
739 isa<IndirectBrInst>(Val: TI) ? nullptr : SplitCriticalEdge(TI, SuccNum);
740 if (!InstrBB)
741 return nullptr;
742
743 MST.addEdge(Src: SrcBB, Dest: InstrBB, W: 0);
744 MST.addEdge(Src: InstrBB, Dest: DestBB, W: 0).InMST = true;
745 E.Removed = true;
746
747 return CanInstrument(InstrBB);
748}
749
750#ifndef NDEBUG
751static void dumpEdges(CFGMST<Edge, BBInfo> &MST, GCOVFunction &GF) {
752 size_t ID = 0;
753 for (const auto &E : make_pointee_range(Range&: MST.allEdges())) {
754 GCOVBlock &Src = E.SrcBB ? GF.getBlock(BB: E.SrcBB) : GF.getEntryBlock();
755 GCOVBlock &Dst = E.DestBB ? GF.getBlock(BB: E.DestBB) : GF.getReturnBlock();
756 dbgs() << " Edge " << ID++ << ": " << Src.Number << "->" << Dst.Number
757 << E.infoString() << "\n";
758 }
759}
760#endif
761
762bool GCOVProfiler::emitProfileNotes(
763 NamedMDNode *CUNode, bool HasExecOrFork,
764 function_ref<BlockFrequencyInfo *(Function &F)> GetBFI,
765 function_ref<BranchProbabilityInfo *(Function &F)> GetBPI,
766 function_ref<const TargetLibraryInfo &(Function &F)> GetTLI) {
767 int Version;
768 {
769 uint8_t c3 = Options.Version[0];
770 uint8_t c2 = Options.Version[1];
771 uint8_t c1 = Options.Version[2];
772 Version = c3 >= 'A' ? (c3 - 'A') * 100 + (c2 - '0') * 10 + c1 - '0'
773 : (c3 - '0') * 10 + c1 - '0';
774 }
775
776 bool EmitGCDA = Options.EmitData;
777 for (unsigned i = 0, e = CUNode->getNumOperands(); i != e; ++i) {
778 // Each compile unit gets its own .gcno file. This means that whether we run
779 // this pass over the original .o's as they're produced, or run it after
780 // LTO, we'll generate the same .gcno files.
781
782 auto *CU = cast<DICompileUnit>(Val: CUNode->getOperand(i));
783
784 // Skip module skeleton (and module) CUs.
785 if (CU->getDWOId())
786 continue;
787
788 std::vector<uint8_t> EdgeDestinations;
789 SmallVector<std::pair<GlobalVariable *, MDNode *>, 8> CountersBySP;
790
791 Endian = M->getDataLayout().isLittleEndian() ? llvm::endianness::little
792 : llvm::endianness::big;
793 unsigned FunctionIdent = 0;
794 for (auto &F : M->functions()) {
795 DISubprogram *SP = F.getSubprogram();
796 unsigned EndLine;
797 if (!SP) continue;
798 if (!functionHasLines(F, EndLine) || !isFunctionInstrumented(F))
799 continue;
800 // TODO: Functions using scope-based EH are currently not supported.
801 if (isUsingScopeBasedEH(F)) continue;
802 if (F.hasFnAttribute(llvm::Attribute::NoProfile))
803 continue;
804 if (F.hasFnAttribute(llvm::Attribute::SkipProfile))
805 continue;
806
807 // Add the function line number to the lines of the entry block
808 // to have a counter for the function definition.
809 uint32_t Line = SP->getLine();
810 auto Filename = getFilename(SP);
811
812 BranchProbabilityInfo *BPI = GetBPI(F);
813 BlockFrequencyInfo *BFI = GetBFI(F);
814
815 // Split indirectbr critical edges here before computing the MST rather
816 // than later in getInstrBB() to avoid invalidating it.
817 SplitIndirectBrCriticalEdges(F, /*IgnoreBlocksWithoutPHI=*/false, BPI,
818 BFI);
819
820 CFGMST<Edge, BBInfo> MST(F, /*InstrumentFuncEntry_=*/false, BPI, BFI);
821
822 // getInstrBB can split basic blocks and push elements to AllEdges.
823 for (size_t I : llvm::seq<size_t>(Begin: 0, End: MST.numEdges())) {
824 auto &E = *MST.allEdges()[I];
825 // For now, disable spanning tree optimization when fork or exec* is
826 // used.
827 if (HasExecOrFork)
828 E.InMST = false;
829 E.Place = getInstrBB(MST, E, ExecBlocks);
830 }
831 // Basic blocks in F are finalized at this point.
832 BasicBlock &EntryBlock = F.getEntryBlock();
833 Funcs.push_back(Elt: std::make_unique<GCOVFunction>(args: this, args: &F, args&: SP, args&: EndLine,
834 args: FunctionIdent++, args&: Version));
835 GCOVFunction &Func = *Funcs.back();
836
837 // Some non-tree edges are IndirectBr which cannot be split. Ignore them
838 // as well.
839 llvm::erase_if(C&: MST.allEdges(), P: [](std::unique_ptr<Edge> &E) {
840 return E->Removed || (!E->InMST && !E->Place);
841 });
842 const size_t Measured =
843 std::stable_partition(
844 first: MST.allEdges().begin(), last: MST.allEdges().end(),
845 pred: [](std::unique_ptr<Edge> &E) { return E->Place; }) -
846 MST.allEdges().begin();
847 for (size_t I : llvm::seq<size_t>(Begin: 0, End: Measured)) {
848 Edge &E = *MST.allEdges()[I];
849 GCOVBlock &Src =
850 E.SrcBB ? Func.getBlock(BB: E.SrcBB) : Func.getEntryBlock();
851 GCOVBlock &Dst =
852 E.DestBB ? Func.getBlock(BB: E.DestBB) : Func.getReturnBlock();
853 E.SrcNumber = Src.Number;
854 E.DstNumber = Dst.Number;
855 }
856 std::stable_sort(
857 first: MST.allEdges().begin(), last: MST.allEdges().begin() + Measured,
858 comp: [](const std::unique_ptr<Edge> &L, const std::unique_ptr<Edge> &R) {
859 return L->SrcNumber != R->SrcNumber ? L->SrcNumber < R->SrcNumber
860 : L->DstNumber < R->DstNumber;
861 });
862
863 for (const Edge &E : make_pointee_range(Range&: MST.allEdges())) {
864 GCOVBlock &Src =
865 E.SrcBB ? Func.getBlock(BB: E.SrcBB) : Func.getEntryBlock();
866 GCOVBlock &Dst =
867 E.DestBB ? Func.getBlock(BB: E.DestBB) : Func.getReturnBlock();
868 Src.addEdge(Successor&: Dst, Flags: E.Place ? 0 : uint32_t(GCOV_ARC_ON_TREE));
869 }
870
871 // Artificial functions such as global initializers
872 if (!SP->isArtificial())
873 Func.getBlock(BB: &EntryBlock).getFile(Filename).addLine(Line);
874
875 LLVM_DEBUG(dumpEdges(MST, Func));
876
877 for (auto &GB : Func.Blocks) {
878 const BasicBlock &BB = *GB.first;
879 auto &Block = GB.second;
880 for (auto Succ : Block.OutEdges) {
881 uint32_t Idx = Succ.first->Number;
882 do EdgeDestinations.push_back(x: Idx & 255);
883 while ((Idx >>= 8) > 0);
884 }
885
886 for (const auto &I : BB) {
887 // Debug intrinsic locations correspond to the location of the
888 // declaration, not necessarily any statements or expressions.
889 if (isa<DbgInfoIntrinsic>(Val: &I)) continue;
890
891 const DebugLoc &Loc = I.getDebugLoc();
892 if (!Loc)
893 continue;
894
895 // Artificial lines such as calls to the global constructors.
896 if (Loc.getLine() == 0 || Loc.isImplicitCode())
897 continue;
898
899 if (Line == Loc.getLine()) continue;
900 Line = Loc.getLine();
901 MDNode *Scope = Loc.getScope();
902 // TODO: Handle blocks from another file due to #line, #include, etc.
903 if (isa<DILexicalBlockFile>(Val: Scope) || SP != getDISubprogram(Scope))
904 continue;
905
906 GCOVLines &Lines = Block.getFile(Filename);
907 Lines.addLine(Line: Loc.getLine());
908 }
909 Line = 0;
910 }
911 if (EmitGCDA) {
912 DISubprogram *SP = F.getSubprogram();
913 ArrayType *CounterTy = ArrayType::get(ElementType: Type::getInt64Ty(C&: *Ctx), NumElements: Measured);
914 GlobalVariable *Counters = new GlobalVariable(
915 *M, CounterTy, false, GlobalValue::InternalLinkage,
916 Constant::getNullValue(Ty: CounterTy), "__llvm_gcov_ctr");
917 CountersBySP.emplace_back(Args&: Counters, Args&: SP);
918
919 for (size_t I : llvm::seq<size_t>(Begin: 0, End: Measured)) {
920 const Edge &E = *MST.allEdges()[I];
921 IRBuilder<> Builder(E.Place, E.Place->getFirstInsertionPt());
922 Value *V = Builder.CreateConstInBoundsGEP2_64(
923 Ty: Counters->getValueType(), Ptr: Counters, Idx0: 0, Idx1: I);
924 // Disable sanitizers to decrease size bloat. We don't expect
925 // sanitizers to catch interesting issues.
926 Instruction *Inst;
927 if (Options.Atomic) {
928 Inst = Builder.CreateAtomicRMW(Op: AtomicRMWInst::Add, Ptr: V,
929 Val: Builder.getInt64(C: 1), Align: MaybeAlign(),
930 Ordering: AtomicOrdering::Monotonic);
931 } else {
932 LoadInst *OldCount =
933 Builder.CreateLoad(Ty: Builder.getInt64Ty(), Ptr: V, Name: "gcov_ctr");
934 OldCount->setNoSanitizeMetadata();
935 Value *NewCount = Builder.CreateAdd(LHS: OldCount, RHS: Builder.getInt64(C: 1));
936 Inst = Builder.CreateStore(Val: NewCount, Ptr: V);
937 }
938 Inst->setNoSanitizeMetadata();
939 }
940 }
941 }
942
943 char Tmp[4];
944 JamCRC JC;
945 JC.update(Data: EdgeDestinations);
946 uint32_t Stamp = JC.getCRC();
947 FileChecksums.push_back(Elt: Stamp);
948
949 if (Options.EmitNotes) {
950 std::error_code EC;
951 raw_fd_ostream out(mangleName(CU, OutputType: GCovFileType::GCNO), EC,
952 sys::fs::OF_None);
953 if (EC) {
954 Ctx->emitError(
955 ErrorStr: Twine("failed to open coverage notes file for writing: ") +
956 EC.message());
957 continue;
958 }
959 os = &out;
960 if (Endian == llvm::endianness::big) {
961 out.write(Ptr: "gcno", Size: 4);
962 out.write(Ptr: Options.Version, Size: 4);
963 } else {
964 out.write(Ptr: "oncg", Size: 4);
965 std::reverse_copy(first: Options.Version, last: Options.Version + 4, result: Tmp);
966 out.write(Ptr: Tmp, Size: 4);
967 }
968 write(i: Stamp);
969 if (Version >= 90)
970 writeString(s: ""); // unuseful current_working_directory
971 if (Version >= 80)
972 write(i: 0); // unuseful has_unexecuted_blocks
973
974 for (auto &Func : Funcs)
975 Func->writeOut(CfgChecksum: Stamp);
976
977 write(i: 0);
978 write(i: 0);
979 out.close();
980 }
981
982 if (EmitGCDA) {
983 emitGlobalConstructor(CountersBySP);
984 EmitGCDA = false;
985 }
986 }
987 return true;
988}
989
990Function *GCOVProfiler::createInternalFunction(FunctionType *FTy,
991 StringRef Name,
992 StringRef MangledType /*=""*/) {
993 Function *F = Function::createWithDefaultAttr(
994 Ty: FTy, Linkage: GlobalValue::InternalLinkage, AddrSpace: 0, N: Name, M);
995 F->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
996 F->addFnAttr(Attribute::NoUnwind);
997 if (Options.NoRedZone)
998 F->addFnAttr(Attribute::NoRedZone);
999 if (!MangledType.empty())
1000 setKCFIType(M&: *M, F&: *F, MangledType);
1001 return F;
1002}
1003
1004void GCOVProfiler::emitGlobalConstructor(
1005 SmallVectorImpl<std::pair<GlobalVariable *, MDNode *>> &CountersBySP) {
1006 Function *WriteoutF = insertCounterWriteout(CountersBySP);
1007 Function *ResetF = insertReset(CountersBySP);
1008
1009 // Create a small bit of code that registers the "__llvm_gcov_writeout" to
1010 // be executed at exit and the "__llvm_gcov_reset" function to be executed
1011 // when "__gcov_flush" is called.
1012 FunctionType *FTy = FunctionType::get(Result: Type::getVoidTy(C&: *Ctx), isVarArg: false);
1013 Function *F = createInternalFunction(FTy, Name: "__llvm_gcov_init", MangledType: "_ZTSFvvE");
1014 F->addFnAttr(Attribute::NoInline);
1015
1016 BasicBlock *BB = BasicBlock::Create(Context&: *Ctx, Name: "entry", Parent: F);
1017 IRBuilder<> Builder(BB);
1018
1019 FTy = FunctionType::get(Result: Type::getVoidTy(C&: *Ctx), isVarArg: false);
1020 auto *PFTy = PointerType::get(ElementType: FTy, AddressSpace: 0);
1021 FTy = FunctionType::get(Result: Builder.getVoidTy(), Params: {PFTy, PFTy}, isVarArg: false);
1022
1023 // Initialize the environment and register the local writeout, flush and
1024 // reset functions.
1025 FunctionCallee GCOVInit = M->getOrInsertFunction(Name: "llvm_gcov_init", T: FTy);
1026 Builder.CreateCall(Callee: GCOVInit, Args: {WriteoutF, ResetF});
1027 Builder.CreateRetVoid();
1028
1029 appendToGlobalCtors(M&: *M, F, Priority: 0);
1030}
1031
1032FunctionCallee GCOVProfiler::getStartFileFunc(const TargetLibraryInfo *TLI) {
1033 Type *Args[] = {
1034 PointerType::getUnqual(C&: *Ctx), // const char *orig_filename
1035 Type::getInt32Ty(C&: *Ctx), // uint32_t version
1036 Type::getInt32Ty(C&: *Ctx), // uint32_t checksum
1037 };
1038 FunctionType *FTy = FunctionType::get(Result: Type::getVoidTy(C&: *Ctx), Params: Args, isVarArg: false);
1039 return M->getOrInsertFunction(Name: "llvm_gcda_start_file", T: FTy,
1040 AttributeList: TLI->getAttrList(C: Ctx, ArgNos: {1, 2}, /*Signed=*/false));
1041}
1042
1043FunctionCallee GCOVProfiler::getEmitFunctionFunc(const TargetLibraryInfo *TLI) {
1044 Type *Args[] = {
1045 Type::getInt32Ty(C&: *Ctx), // uint32_t ident
1046 Type::getInt32Ty(C&: *Ctx), // uint32_t func_checksum
1047 Type::getInt32Ty(C&: *Ctx), // uint32_t cfg_checksum
1048 };
1049 FunctionType *FTy = FunctionType::get(Result: Type::getVoidTy(C&: *Ctx), Params: Args, isVarArg: false);
1050 return M->getOrInsertFunction(Name: "llvm_gcda_emit_function", T: FTy,
1051 AttributeList: TLI->getAttrList(C: Ctx, ArgNos: {0, 1, 2}, /*Signed=*/false));
1052}
1053
1054FunctionCallee GCOVProfiler::getEmitArcsFunc(const TargetLibraryInfo *TLI) {
1055 Type *Args[] = {
1056 Type::getInt32Ty(C&: *Ctx), // uint32_t num_counters
1057 PointerType::getUnqual(C&: *Ctx), // uint64_t *counters
1058 };
1059 FunctionType *FTy = FunctionType::get(Result: Type::getVoidTy(C&: *Ctx), Params: Args, isVarArg: false);
1060 return M->getOrInsertFunction(Name: "llvm_gcda_emit_arcs", T: FTy,
1061 AttributeList: TLI->getAttrList(C: Ctx, ArgNos: {0}, /*Signed=*/false));
1062}
1063
1064FunctionCallee GCOVProfiler::getSummaryInfoFunc() {
1065 FunctionType *FTy = FunctionType::get(Result: Type::getVoidTy(C&: *Ctx), isVarArg: false);
1066 return M->getOrInsertFunction(Name: "llvm_gcda_summary_info", T: FTy);
1067}
1068
1069FunctionCallee GCOVProfiler::getEndFileFunc() {
1070 FunctionType *FTy = FunctionType::get(Result: Type::getVoidTy(C&: *Ctx), isVarArg: false);
1071 return M->getOrInsertFunction(Name: "llvm_gcda_end_file", T: FTy);
1072}
1073
1074Function *GCOVProfiler::insertCounterWriteout(
1075 ArrayRef<std::pair<GlobalVariable *, MDNode *> > CountersBySP) {
1076 FunctionType *WriteoutFTy = FunctionType::get(Result: Type::getVoidTy(C&: *Ctx), isVarArg: false);
1077 Function *WriteoutF = M->getFunction(Name: "__llvm_gcov_writeout");
1078 if (!WriteoutF)
1079 WriteoutF =
1080 createInternalFunction(FTy: WriteoutFTy, Name: "__llvm_gcov_writeout", MangledType: "_ZTSFvvE");
1081 WriteoutF->addFnAttr(Attribute::NoInline);
1082
1083 BasicBlock *BB = BasicBlock::Create(Context&: *Ctx, Name: "entry", Parent: WriteoutF);
1084 IRBuilder<> Builder(BB);
1085
1086 auto *TLI = &GetTLI(*WriteoutF);
1087
1088 FunctionCallee StartFile = getStartFileFunc(TLI);
1089 FunctionCallee EmitFunction = getEmitFunctionFunc(TLI);
1090 FunctionCallee EmitArcs = getEmitArcsFunc(TLI);
1091 FunctionCallee SummaryInfo = getSummaryInfoFunc();
1092 FunctionCallee EndFile = getEndFileFunc();
1093
1094 NamedMDNode *CUNodes = M->getNamedMetadata(Name: "llvm.dbg.cu");
1095 if (!CUNodes) {
1096 Builder.CreateRetVoid();
1097 return WriteoutF;
1098 }
1099
1100 // Collect the relevant data into a large constant data structure that we can
1101 // walk to write out everything.
1102 StructType *StartFileCallArgsTy = StructType::create(
1103 Elements: {Builder.getPtrTy(), Builder.getInt32Ty(), Builder.getInt32Ty()},
1104 Name: "start_file_args_ty");
1105 StructType *EmitFunctionCallArgsTy = StructType::create(
1106 Elements: {Builder.getInt32Ty(), Builder.getInt32Ty(), Builder.getInt32Ty()},
1107 Name: "emit_function_args_ty");
1108 auto *PtrTy = Builder.getPtrTy();
1109 StructType *EmitArcsCallArgsTy =
1110 StructType::create(Elements: {Builder.getInt32Ty(), PtrTy}, Name: "emit_arcs_args_ty");
1111 StructType *FileInfoTy = StructType::create(
1112 Elements: {StartFileCallArgsTy, Builder.getInt32Ty(), PtrTy, PtrTy}, Name: "file_info");
1113
1114 Constant *Zero32 = Builder.getInt32(C: 0);
1115 // Build an explicit array of two zeros for use in ConstantExpr GEP building.
1116 Constant *TwoZero32s[] = {Zero32, Zero32};
1117
1118 SmallVector<Constant *, 8> FileInfos;
1119 for (int i : llvm::seq<int>(Begin: 0, End: CUNodes->getNumOperands())) {
1120 auto *CU = cast<DICompileUnit>(Val: CUNodes->getOperand(i));
1121
1122 // Skip module skeleton (and module) CUs.
1123 if (CU->getDWOId())
1124 continue;
1125
1126 std::string FilenameGcda = mangleName(CU, OutputType: GCovFileType::GCDA);
1127 uint32_t CfgChecksum = FileChecksums.empty() ? 0 : FileChecksums[i];
1128 auto *StartFileCallArgs = ConstantStruct::get(
1129 T: StartFileCallArgsTy,
1130 V: {Builder.CreateGlobalStringPtr(Str: FilenameGcda),
1131 Builder.getInt32(C: endian::read32be(P: Options.Version)),
1132 Builder.getInt32(C: CfgChecksum)});
1133
1134 SmallVector<Constant *, 8> EmitFunctionCallArgsArray;
1135 SmallVector<Constant *, 8> EmitArcsCallArgsArray;
1136 for (int j : llvm::seq<int>(Begin: 0, End: CountersBySP.size())) {
1137 uint32_t FuncChecksum = Funcs.empty() ? 0 : Funcs[j]->getFuncChecksum();
1138 EmitFunctionCallArgsArray.push_back(Elt: ConstantStruct::get(
1139 T: EmitFunctionCallArgsTy,
1140 V: {Builder.getInt32(C: j),
1141 Builder.getInt32(C: FuncChecksum),
1142 Builder.getInt32(C: CfgChecksum)}));
1143
1144 GlobalVariable *GV = CountersBySP[j].first;
1145 unsigned Arcs = cast<ArrayType>(Val: GV->getValueType())->getNumElements();
1146 EmitArcsCallArgsArray.push_back(Elt: ConstantStruct::get(
1147 T: EmitArcsCallArgsTy,
1148 V: {Builder.getInt32(C: Arcs), ConstantExpr::getInBoundsGetElementPtr(
1149 Ty: GV->getValueType(), C: GV, IdxList: TwoZero32s)}));
1150 }
1151 // Create global arrays for the two emit calls.
1152 int CountersSize = CountersBySP.size();
1153 assert(CountersSize == (int)EmitFunctionCallArgsArray.size() &&
1154 "Mismatched array size!");
1155 assert(CountersSize == (int)EmitArcsCallArgsArray.size() &&
1156 "Mismatched array size!");
1157 auto *EmitFunctionCallArgsArrayTy =
1158 ArrayType::get(ElementType: EmitFunctionCallArgsTy, NumElements: CountersSize);
1159 auto *EmitFunctionCallArgsArrayGV = new GlobalVariable(
1160 *M, EmitFunctionCallArgsArrayTy, /*isConstant*/ true,
1161 GlobalValue::InternalLinkage,
1162 ConstantArray::get(T: EmitFunctionCallArgsArrayTy,
1163 V: EmitFunctionCallArgsArray),
1164 Twine("__llvm_internal_gcov_emit_function_args.") + Twine(i));
1165 auto *EmitArcsCallArgsArrayTy =
1166 ArrayType::get(ElementType: EmitArcsCallArgsTy, NumElements: CountersSize);
1167 EmitFunctionCallArgsArrayGV->setUnnamedAddr(
1168 GlobalValue::UnnamedAddr::Global);
1169 auto *EmitArcsCallArgsArrayGV = new GlobalVariable(
1170 *M, EmitArcsCallArgsArrayTy, /*isConstant*/ true,
1171 GlobalValue::InternalLinkage,
1172 ConstantArray::get(T: EmitArcsCallArgsArrayTy, V: EmitArcsCallArgsArray),
1173 Twine("__llvm_internal_gcov_emit_arcs_args.") + Twine(i));
1174 EmitArcsCallArgsArrayGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
1175
1176 FileInfos.push_back(Elt: ConstantStruct::get(
1177 T: FileInfoTy,
1178 V: {StartFileCallArgs, Builder.getInt32(C: CountersSize),
1179 ConstantExpr::getInBoundsGetElementPtr(Ty: EmitFunctionCallArgsArrayTy,
1180 C: EmitFunctionCallArgsArrayGV,
1181 IdxList: TwoZero32s),
1182 ConstantExpr::getInBoundsGetElementPtr(
1183 Ty: EmitArcsCallArgsArrayTy, C: EmitArcsCallArgsArrayGV, IdxList: TwoZero32s)}));
1184 }
1185
1186 // If we didn't find anything to actually emit, bail on out.
1187 if (FileInfos.empty()) {
1188 Builder.CreateRetVoid();
1189 return WriteoutF;
1190 }
1191
1192 // To simplify code, we cap the number of file infos we write out to fit
1193 // easily in a 32-bit signed integer. This gives consistent behavior between
1194 // 32-bit and 64-bit systems without requiring (potentially very slow) 64-bit
1195 // operations on 32-bit systems. It also seems unreasonable to try to handle
1196 // more than 2 billion files.
1197 if ((int64_t)FileInfos.size() > (int64_t)INT_MAX)
1198 FileInfos.resize(INT_MAX);
1199
1200 // Create a global for the entire data structure so we can walk it more
1201 // easily.
1202 auto *FileInfoArrayTy = ArrayType::get(ElementType: FileInfoTy, NumElements: FileInfos.size());
1203 auto *FileInfoArrayGV = new GlobalVariable(
1204 *M, FileInfoArrayTy, /*isConstant*/ true, GlobalValue::InternalLinkage,
1205 ConstantArray::get(T: FileInfoArrayTy, V: FileInfos),
1206 "__llvm_internal_gcov_emit_file_info");
1207 FileInfoArrayGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
1208
1209 // Create the CFG for walking this data structure.
1210 auto *FileLoopHeader =
1211 BasicBlock::Create(Context&: *Ctx, Name: "file.loop.header", Parent: WriteoutF);
1212 auto *CounterLoopHeader =
1213 BasicBlock::Create(Context&: *Ctx, Name: "counter.loop.header", Parent: WriteoutF);
1214 auto *FileLoopLatch = BasicBlock::Create(Context&: *Ctx, Name: "file.loop.latch", Parent: WriteoutF);
1215 auto *ExitBB = BasicBlock::Create(Context&: *Ctx, Name: "exit", Parent: WriteoutF);
1216
1217 // We always have at least one file, so just branch to the header.
1218 Builder.CreateBr(Dest: FileLoopHeader);
1219
1220 // The index into the files structure is our loop induction variable.
1221 Builder.SetInsertPoint(FileLoopHeader);
1222 PHINode *IV = Builder.CreatePHI(Ty: Builder.getInt32Ty(), /*NumReservedValues*/ 2,
1223 Name: "file_idx");
1224 IV->addIncoming(V: Builder.getInt32(C: 0), BB);
1225 auto *FileInfoPtr = Builder.CreateInBoundsGEP(
1226 Ty: FileInfoArrayTy, Ptr: FileInfoArrayGV, IdxList: {Builder.getInt32(C: 0), IV});
1227 auto *StartFileCallArgsPtr =
1228 Builder.CreateStructGEP(Ty: FileInfoTy, Ptr: FileInfoPtr, Idx: 0, Name: "start_file_args");
1229 auto *StartFileCall = Builder.CreateCall(
1230 Callee: StartFile,
1231 Args: {Builder.CreateLoad(Ty: StartFileCallArgsTy->getElementType(N: 0),
1232 Ptr: Builder.CreateStructGEP(Ty: StartFileCallArgsTy,
1233 Ptr: StartFileCallArgsPtr, Idx: 0),
1234 Name: "filename"),
1235 Builder.CreateLoad(Ty: StartFileCallArgsTy->getElementType(N: 1),
1236 Ptr: Builder.CreateStructGEP(Ty: StartFileCallArgsTy,
1237 Ptr: StartFileCallArgsPtr, Idx: 1),
1238 Name: "version"),
1239 Builder.CreateLoad(Ty: StartFileCallArgsTy->getElementType(N: 2),
1240 Ptr: Builder.CreateStructGEP(Ty: StartFileCallArgsTy,
1241 Ptr: StartFileCallArgsPtr, Idx: 2),
1242 Name: "stamp")});
1243 if (auto AK = TLI->getExtAttrForI32Param(Signed: false))
1244 StartFileCall->addParamAttr(ArgNo: 2, Kind: AK);
1245 auto *NumCounters = Builder.CreateLoad(
1246 Ty: FileInfoTy->getElementType(N: 1),
1247 Ptr: Builder.CreateStructGEP(Ty: FileInfoTy, Ptr: FileInfoPtr, Idx: 1), Name: "num_ctrs");
1248 auto *EmitFunctionCallArgsArray =
1249 Builder.CreateLoad(Ty: FileInfoTy->getElementType(N: 2),
1250 Ptr: Builder.CreateStructGEP(Ty: FileInfoTy, Ptr: FileInfoPtr, Idx: 2),
1251 Name: "emit_function_args");
1252 auto *EmitArcsCallArgsArray = Builder.CreateLoad(
1253 Ty: FileInfoTy->getElementType(N: 3),
1254 Ptr: Builder.CreateStructGEP(Ty: FileInfoTy, Ptr: FileInfoPtr, Idx: 3), Name: "emit_arcs_args");
1255 auto *EnterCounterLoopCond =
1256 Builder.CreateICmpSLT(LHS: Builder.getInt32(C: 0), RHS: NumCounters);
1257 Builder.CreateCondBr(Cond: EnterCounterLoopCond, True: CounterLoopHeader, False: FileLoopLatch);
1258
1259 Builder.SetInsertPoint(CounterLoopHeader);
1260 auto *JV = Builder.CreatePHI(Ty: Builder.getInt32Ty(), /*NumReservedValues*/ 2,
1261 Name: "ctr_idx");
1262 JV->addIncoming(V: Builder.getInt32(C: 0), BB: FileLoopHeader);
1263 auto *EmitFunctionCallArgsPtr = Builder.CreateInBoundsGEP(
1264 Ty: EmitFunctionCallArgsTy, Ptr: EmitFunctionCallArgsArray, IdxList: JV);
1265 auto *EmitFunctionCall = Builder.CreateCall(
1266 Callee: EmitFunction,
1267 Args: {Builder.CreateLoad(Ty: EmitFunctionCallArgsTy->getElementType(N: 0),
1268 Ptr: Builder.CreateStructGEP(Ty: EmitFunctionCallArgsTy,
1269 Ptr: EmitFunctionCallArgsPtr, Idx: 0),
1270 Name: "ident"),
1271 Builder.CreateLoad(Ty: EmitFunctionCallArgsTy->getElementType(N: 1),
1272 Ptr: Builder.CreateStructGEP(Ty: EmitFunctionCallArgsTy,
1273 Ptr: EmitFunctionCallArgsPtr, Idx: 1),
1274 Name: "func_checkssum"),
1275 Builder.CreateLoad(Ty: EmitFunctionCallArgsTy->getElementType(N: 2),
1276 Ptr: Builder.CreateStructGEP(Ty: EmitFunctionCallArgsTy,
1277 Ptr: EmitFunctionCallArgsPtr, Idx: 2),
1278 Name: "cfg_checksum")});
1279 if (auto AK = TLI->getExtAttrForI32Param(Signed: false)) {
1280 EmitFunctionCall->addParamAttr(ArgNo: 0, Kind: AK);
1281 EmitFunctionCall->addParamAttr(ArgNo: 1, Kind: AK);
1282 EmitFunctionCall->addParamAttr(ArgNo: 2, Kind: AK);
1283 }
1284 auto *EmitArcsCallArgsPtr =
1285 Builder.CreateInBoundsGEP(Ty: EmitArcsCallArgsTy, Ptr: EmitArcsCallArgsArray, IdxList: JV);
1286 auto *EmitArcsCall = Builder.CreateCall(
1287 Callee: EmitArcs,
1288 Args: {Builder.CreateLoad(
1289 Ty: EmitArcsCallArgsTy->getElementType(N: 0),
1290 Ptr: Builder.CreateStructGEP(Ty: EmitArcsCallArgsTy, Ptr: EmitArcsCallArgsPtr, Idx: 0),
1291 Name: "num_counters"),
1292 Builder.CreateLoad(
1293 Ty: EmitArcsCallArgsTy->getElementType(N: 1),
1294 Ptr: Builder.CreateStructGEP(Ty: EmitArcsCallArgsTy, Ptr: EmitArcsCallArgsPtr, Idx: 1),
1295 Name: "counters")});
1296 if (auto AK = TLI->getExtAttrForI32Param(Signed: false))
1297 EmitArcsCall->addParamAttr(ArgNo: 0, Kind: AK);
1298 auto *NextJV = Builder.CreateAdd(LHS: JV, RHS: Builder.getInt32(C: 1));
1299 auto *CounterLoopCond = Builder.CreateICmpSLT(LHS: NextJV, RHS: NumCounters);
1300 Builder.CreateCondBr(Cond: CounterLoopCond, True: CounterLoopHeader, False: FileLoopLatch);
1301 JV->addIncoming(V: NextJV, BB: CounterLoopHeader);
1302
1303 Builder.SetInsertPoint(FileLoopLatch);
1304 Builder.CreateCall(Callee: SummaryInfo, Args: {});
1305 Builder.CreateCall(Callee: EndFile, Args: {});
1306 auto *NextIV = Builder.CreateAdd(LHS: IV, RHS: Builder.getInt32(C: 1), Name: "next_file_idx");
1307 auto *FileLoopCond =
1308 Builder.CreateICmpSLT(LHS: NextIV, RHS: Builder.getInt32(C: FileInfos.size()));
1309 Builder.CreateCondBr(Cond: FileLoopCond, True: FileLoopHeader, False: ExitBB);
1310 IV->addIncoming(V: NextIV, BB: FileLoopLatch);
1311
1312 Builder.SetInsertPoint(ExitBB);
1313 Builder.CreateRetVoid();
1314
1315 return WriteoutF;
1316}
1317
1318Function *GCOVProfiler::insertReset(
1319 ArrayRef<std::pair<GlobalVariable *, MDNode *>> CountersBySP) {
1320 FunctionType *FTy = FunctionType::get(Result: Type::getVoidTy(C&: *Ctx), isVarArg: false);
1321 Function *ResetF = M->getFunction(Name: "__llvm_gcov_reset");
1322 if (!ResetF)
1323 ResetF = createInternalFunction(FTy, Name: "__llvm_gcov_reset", MangledType: "_ZTSFvvE");
1324 ResetF->addFnAttr(Attribute::NoInline);
1325
1326 BasicBlock *Entry = BasicBlock::Create(Context&: *Ctx, Name: "entry", Parent: ResetF);
1327 IRBuilder<> Builder(Entry);
1328 LLVMContext &C = Entry->getContext();
1329
1330 // Zero out the counters.
1331 for (const auto &I : CountersBySP) {
1332 GlobalVariable *GV = I.first;
1333 auto *GVTy = cast<ArrayType>(Val: GV->getValueType());
1334 Builder.CreateMemSet(Ptr: GV, Val: Constant::getNullValue(Ty: Type::getInt8Ty(C)),
1335 Size: GVTy->getNumElements() *
1336 GVTy->getElementType()->getScalarSizeInBits() / 8,
1337 Align: GV->getAlign());
1338 }
1339
1340 Type *RetTy = ResetF->getReturnType();
1341 if (RetTy->isVoidTy())
1342 Builder.CreateRetVoid();
1343 else if (RetTy->isIntegerTy())
1344 // Used if __llvm_gcov_reset was implicitly declared.
1345 Builder.CreateRet(V: ConstantInt::get(Ty: RetTy, V: 0));
1346 else
1347 report_fatal_error(reason: "invalid return type for __llvm_gcov_reset");
1348
1349 return ResetF;
1350}
1351

source code of llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp