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