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