LLVM 18.0.0git
GCOV.cpp
Go to the documentation of this file.
1//===- GCOV.cpp - LLVM coverage tool --------------------------------------===//
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// GCOV implements the interface to read and write coverage files that use
10// 'gcov' format.
11//
12//===----------------------------------------------------------------------===//
13
15#include "llvm/ADT/STLExtras.h"
16#include "llvm/ADT/SmallSet.h"
17#include "llvm/Config/llvm-config.h"
19#include "llvm/Support/Debug.h"
21#include "llvm/Support/Format.h"
22#include "llvm/Support/MD5.h"
23#include "llvm/Support/Path.h"
25#include <algorithm>
26#include <optional>
27#include <system_error>
28
29using namespace llvm;
30
31enum : uint32_t {
34
35 GCOV_TAG_FUNCTION = 0x01000000,
36 GCOV_TAG_BLOCKS = 0x01410000,
37 GCOV_TAG_ARCS = 0x01430000,
38 GCOV_TAG_LINES = 0x01450000,
40 // GCOV_TAG_OBJECT_SUMMARY superseded GCOV_TAG_PROGRAM_SUMMARY in GCC 9.
43};
44
45namespace {
46struct Summary {
48
50 uint64_t lines = 0;
51 uint64_t linesExec = 0;
53 uint64_t branchesExec = 0;
54 uint64_t branchesTaken = 0;
55};
56
57struct LineInfo {
59 uint64_t count = 0;
60 bool exists = false;
61};
62
63struct SourceInfo {
65 SmallString<0> displayName;
66 std::vector<std::vector<const GCOVFunction *>> startLineToFunctions;
67 std::vector<LineInfo> lines;
68 bool ignored = false;
69 SourceInfo(StringRef filename) : filename(filename) {}
70};
71
72class Context {
73public:
75 void print(StringRef filename, StringRef gcno, StringRef gcda,
76 GCOVFile &file);
77
78private:
79 std::string getCoveragePath(StringRef filename, StringRef mainFilename) const;
80 void printFunctionDetails(const GCOVFunction &f, raw_ostream &os) const;
81 void printBranchInfo(const GCOVBlock &Block, uint32_t &edgeIdx,
82 raw_ostream &OS) const;
83 void printSummary(const Summary &summary, raw_ostream &os) const;
84
85 void collectFunction(GCOVFunction &f, Summary &summary);
86 void collectSourceLine(SourceInfo &si, Summary *summary, LineInfo &line,
87 size_t lineNum) const;
88 void collectSource(SourceInfo &si, Summary &summary) const;
89 void annotateSource(SourceInfo &si, const GCOVFile &file, StringRef gcno,
90 StringRef gcda, raw_ostream &os) const;
91 void printSourceToIntermediate(const SourceInfo &si, raw_ostream &os) const;
92
94 std::vector<SourceInfo> sources;
95};
96} // namespace
97
98//===----------------------------------------------------------------------===//
99// GCOVFile implementation.
100
101/// readGCNO - Read GCNO buffer.
103 if (!buf.readGCNOFormat())
104 return false;
105 if (!buf.readGCOVVersion(version))
106 return false;
107
108 checksum = buf.getWord();
109 if (version >= GCOV::V900 && !buf.readString(cwd))
110 return false;
111 if (version >= GCOV::V800)
112 buf.getWord(); // hasUnexecutedBlocks
113
114 uint32_t tag, length;
115 GCOVFunction *fn = nullptr;
116 while ((tag = buf.getWord())) {
117 if (!buf.readInt(length))
118 return false;
119 uint32_t pos = buf.cursor.tell();
120 if (tag == GCOV_TAG_FUNCTION) {
121 functions.push_back(std::make_unique<GCOVFunction>(*this));
122 fn = functions.back().get();
123 fn->ident = buf.getWord();
124 fn->linenoChecksum = buf.getWord();
125 if (version >= GCOV::V407)
126 fn->cfgChecksum = buf.getWord();
127 buf.readString(fn->Name);
128 StringRef filename;
129 if (version < GCOV::V800) {
130 if (!buf.readString(filename))
131 return false;
132 fn->startLine = buf.getWord();
133 } else {
134 fn->artificial = buf.getWord();
135 if (!buf.readString(filename))
136 return false;
137 fn->startLine = buf.getWord();
138 fn->startColumn = buf.getWord();
139 fn->endLine = buf.getWord();
140 if (version >= GCOV::V900)
141 fn->endColumn = buf.getWord();
142 }
143 fn->srcIdx = addNormalizedPathToMap(filename);
144 identToFunction[fn->ident] = fn;
145 } else if (tag == GCOV_TAG_BLOCKS && fn) {
146 if (version < GCOV::V800) {
147 for (uint32_t i = 0; i != length; ++i) {
148 buf.getWord(); // Ignored block flags
149 fn->blocks.push_back(std::make_unique<GCOVBlock>(i));
150 }
151 } else {
152 uint32_t num = buf.getWord();
153 for (uint32_t i = 0; i != num; ++i)
154 fn->blocks.push_back(std::make_unique<GCOVBlock>(i));
155 }
156 } else if (tag == GCOV_TAG_ARCS && fn) {
157 uint32_t srcNo = buf.getWord();
158 if (srcNo >= fn->blocks.size()) {
159 errs() << "unexpected block number: " << srcNo << " (in "
160 << fn->blocks.size() << ")\n";
161 return false;
162 }
163 GCOVBlock *src = fn->blocks[srcNo].get();
164 const uint32_t e =
165 version >= GCOV::V1200 ? (length / 4 - 1) / 2 : (length - 1) / 2;
166 for (uint32_t i = 0; i != e; ++i) {
167 uint32_t dstNo = buf.getWord(), flags = buf.getWord();
168 GCOVBlock *dst = fn->blocks[dstNo].get();
169 auto arc = std::make_unique<GCOVArc>(*src, *dst, flags);
170 src->addDstEdge(arc.get());
171 dst->addSrcEdge(arc.get());
172 if (arc->onTree())
173 fn->treeArcs.push_back(std::move(arc));
174 else
175 fn->arcs.push_back(std::move(arc));
176 }
177 } else if (tag == GCOV_TAG_LINES && fn) {
178 uint32_t srcNo = buf.getWord();
179 if (srcNo >= fn->blocks.size()) {
180 errs() << "unexpected block number: " << srcNo << " (in "
181 << fn->blocks.size() << ")\n";
182 return false;
183 }
184 GCOVBlock &Block = *fn->blocks[srcNo];
185 for (;;) {
186 uint32_t line = buf.getWord();
187 if (line)
188 Block.addLine(line);
189 else {
190 StringRef filename;
191 buf.readString(filename);
192 if (filename.empty())
193 break;
194 // TODO Unhandled
195 }
196 }
197 }
198 pos += version >= GCOV::V1200 ? length : 4 * length;
199 if (pos < buf.cursor.tell())
200 return false;
201 buf.de.skip(buf.cursor, pos - buf.cursor.tell());
202 }
203
204 GCNOInitialized = true;
205 return true;
206}
207
208/// readGCDA - Read GCDA buffer. It is required that readGCDA() can only be
209/// called after readGCNO().
211 assert(GCNOInitialized && "readGCDA() can only be called after readGCNO()");
212 if (!buf.readGCDAFormat())
213 return false;
214 GCOV::GCOVVersion GCDAVersion;
215 if (!buf.readGCOVVersion(GCDAVersion))
216 return false;
217 if (version != GCDAVersion) {
218 errs() << "GCOV versions do not match.\n";
219 return false;
220 }
221
222 uint32_t GCDAChecksum;
223 if (!buf.readInt(GCDAChecksum))
224 return false;
225 if (checksum != GCDAChecksum) {
226 errs() << "file checksums do not match: " << checksum
227 << " != " << GCDAChecksum << "\n";
228 return false;
229 }
230 uint32_t dummy, tag, length;
231 uint32_t ident;
232 GCOVFunction *fn = nullptr;
233 while ((tag = buf.getWord())) {
234 if (!buf.readInt(length))
235 return false;
236 uint32_t pos = buf.cursor.tell();
237 if (tag == GCOV_TAG_OBJECT_SUMMARY) {
238 buf.readInt(runCount);
239 buf.readInt(dummy);
240 } else if (tag == GCOV_TAG_PROGRAM_SUMMARY) {
241 buf.readInt(dummy);
242 buf.readInt(dummy);
243 buf.readInt(runCount);
244 ++programCount;
245 } else if (tag == GCOV_TAG_FUNCTION) {
246 if (length == 0) // Placeholder
247 continue;
248 if (length < 2 || !buf.readInt(ident))
249 return false;
250 auto It = identToFunction.find(ident);
251 uint32_t linenoChecksum, cfgChecksum = 0;
252 buf.readInt(linenoChecksum);
253 if (version >= GCOV::V407)
254 buf.readInt(cfgChecksum);
255 if (It != identToFunction.end()) {
256 fn = It->second;
257 if (linenoChecksum != fn->linenoChecksum ||
258 cfgChecksum != fn->cfgChecksum) {
259 errs() << fn->Name
260 << format(": checksum mismatch, (%u, %u) != (%u, %u)\n",
261 linenoChecksum, cfgChecksum, fn->linenoChecksum,
262 fn->cfgChecksum);
263 return false;
264 }
265 }
266 } else if (tag == GCOV_TAG_COUNTER_ARCS && fn) {
267 uint32_t expected = 2 * fn->arcs.size();
268 if (version >= GCOV::V1200)
269 expected *= 4;
270 if (length != expected) {
271 errs() << fn->Name
272 << format(
273 ": GCOV_TAG_COUNTER_ARCS mismatch, got %u, expected %u\n",
274 length, expected);
275 return false;
276 }
277 for (std::unique_ptr<GCOVArc> &arc : fn->arcs) {
278 if (!buf.readInt64(arc->count))
279 return false;
280 arc->src.count += arc->count;
281 }
282
283 if (fn->blocks.size() >= 2) {
284 GCOVBlock &src = *fn->blocks[0];
285 GCOVBlock &sink =
286 version < GCOV::V408 ? *fn->blocks.back() : *fn->blocks[1];
287 auto arc = std::make_unique<GCOVArc>(sink, src, GCOV_ARC_ON_TREE);
288 sink.addDstEdge(arc.get());
289 src.addSrcEdge(arc.get());
290 fn->treeArcs.push_back(std::move(arc));
291
292 for (GCOVBlock &block : fn->blocksRange())
293 fn->propagateCounts(block, nullptr);
294 for (size_t i = fn->treeArcs.size() - 1; i; --i)
295 fn->treeArcs[i - 1]->src.count += fn->treeArcs[i - 1]->count;
296 }
297 }
298 pos += version >= GCOV::V1200 ? length : 4 * length;
299 if (pos < buf.cursor.tell())
300 return false;
301 buf.de.skip(buf.cursor, pos - buf.cursor.tell());
302 }
303
304 return true;
305}
306
308 for (const GCOVFunction &f : *this)
309 f.print(OS);
310}
311
312#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
313/// dump - Dump GCOVFile content to dbgs() for debugging purposes.
315#endif
316
317unsigned GCOVFile::addNormalizedPathToMap(StringRef filename) {
318 // unify filename, as the same path can have different form
319 SmallString<256> P(filename);
321 filename = P.str();
322
323 auto r = filenameToIdx.try_emplace(filename, filenameToIdx.size());
324 if (r.second)
325 filenames.emplace_back(filename);
326
327 return r.first->second;
328}
329
330bool GCOVArc::onTree() const { return flags & GCOV_ARC_ON_TREE; }
331
332//===----------------------------------------------------------------------===//
333// GCOVFunction implementation.
334
336 if (!demangle)
337 return Name;
338 if (demangled.empty()) {
339 do {
340 if (Name.startswith("_Z")) {
341 // Name is guaranteed to be NUL-terminated.
342 if (char *res = itaniumDemangle(Name.data())) {
343 demangled = res;
344 free(res);
345 break;
346 }
347 }
348 demangled = Name;
349 } while (false);
350 }
351 return demangled;
352}
354
355/// getEntryCount - Get the number of times the function was called by
356/// retrieving the entry block's count.
358 return blocks.front()->getCount();
359}
360
362 return file.getVersion() < GCOV::V408 ? *blocks.back() : *blocks[1];
363}
364
365// For each basic block, the sum of incoming edge counts equals the sum of
366// outgoing edge counts by Kirchoff's circuit law. If the unmeasured arcs form a
367// spanning tree, the count for each unmeasured arc (GCOV_ARC_ON_TREE) can be
368// uniquely identified.
370 // If GCOV_ARC_ON_TREE edges do form a tree, visited is not needed; otherwise
371 // this prevents infinite recursion.
372 if (!visited.insert(&v).second)
373 return 0;
374
375 uint64_t excess = 0;
376 for (GCOVArc *e : v.srcs())
377 if (e != pred)
378 excess += e->onTree() ? propagateCounts(e->src, e) : e->count;
379 for (GCOVArc *e : v.dsts())
380 if (e != pred)
381 excess -= e->onTree() ? propagateCounts(e->dst, e) : e->count;
382 if (int64_t(excess) < 0)
383 excess = -excess;
384 if (pred)
385 pred->count = excess;
386 return excess;
387}
388
390 OS << "===== " << Name << " (" << ident << ") @ " << getFilename() << ":"
391 << startLine << "\n";
392 for (const auto &Block : blocks)
393 Block->print(OS);
394}
395
396#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
397/// dump - Dump GCOVFunction content to dbgs() for debugging purposes.
399#endif
400
401/// collectLineCounts - Collect line counts. This must be used after
402/// reading .gcno and .gcda files.
403
404//===----------------------------------------------------------------------===//
405// GCOVBlock implementation.
406
408 OS << "Block : " << number << " Counter : " << count << "\n";
409 if (!pred.empty()) {
410 OS << "\tSource Edges : ";
411 for (const GCOVArc *Edge : pred)
412 OS << Edge->src.number << " (" << Edge->count << "), ";
413 OS << "\n";
414 }
415 if (!succ.empty()) {
416 OS << "\tDestination Edges : ";
417 for (const GCOVArc *Edge : succ) {
418 if (Edge->flags & GCOV_ARC_ON_TREE)
419 OS << '*';
420 OS << Edge->dst.number << " (" << Edge->count << "), ";
421 }
422 OS << "\n";
423 }
424 if (!lines.empty()) {
425 OS << "\tLines : ";
426 for (uint32_t N : lines)
427 OS << (N) << ",";
428 OS << "\n";
429 }
430}
431
432#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
433/// dump - Dump GCOVBlock content to dbgs() for debugging purposes.
435#endif
436
439 std::vector<std::pair<GCOVBlock *, size_t>> &stack) {
440 GCOVBlock *u;
441 size_t i;
442 stack.clear();
443 stack.emplace_back(src, 0);
444 src->incoming = (GCOVArc *)1; // Mark u available for cycle detection
445 for (;;) {
446 std::tie(u, i) = stack.back();
447 if (i == u->succ.size()) {
448 u->traversable = false;
449 stack.pop_back();
450 if (stack.empty())
451 break;
452 continue;
453 }
454 ++stack.back().second;
455 GCOVArc *succ = u->succ[i];
456 // Ignore saturated arcs (cycleCount has been reduced to 0) and visited
457 // blocks. Ignore self arcs to guard against bad input (.gcno has no
458 // self arcs).
459 if (succ->cycleCount == 0 || !succ->dst.traversable || &succ->dst == u)
460 continue;
461 if (succ->dst.incoming == nullptr) {
462 succ->dst.incoming = succ;
463 stack.emplace_back(&succ->dst, 0);
464 continue;
465 }
466 uint64_t minCount = succ->cycleCount;
467 for (GCOVBlock *v = u;;) {
468 minCount = std::min(minCount, v->incoming->cycleCount);
469 v = &v->incoming->src;
470 if (v == &succ->dst)
471 break;
472 }
473 succ->cycleCount -= minCount;
474 for (GCOVBlock *v = u;;) {
475 v->incoming->cycleCount -= minCount;
476 v = &v->incoming->src;
477 if (v == &succ->dst)
478 break;
479 }
480 return minCount;
481 }
482 return 0;
483}
484
485// Get the total execution count of loops among blocks on the same line.
486// Assuming a reducible flow graph, the count is the sum of back edge counts.
487// Identifying loops is complex, so we simply find cycles and perform cycle
488// cancelling iteratively.
490 std::vector<std::pair<GCOVBlock *, size_t>> stack;
491 uint64_t count = 0, d;
492 for (;;) {
493 // Make blocks on the line traversable and try finding a cycle.
494 for (const auto *b : blocks) {
495 const_cast<GCOVBlock *>(b)->traversable = true;
496 const_cast<GCOVBlock *>(b)->incoming = nullptr;
497 }
498 d = 0;
499 for (const auto *block : blocks) {
500 auto *b = const_cast<GCOVBlock *>(block);
501 if (b->traversable && (d = augmentOneCycle(b, stack)) > 0)
502 break;
503 }
504 if (d == 0)
505 break;
506 count += d;
507 }
508 // If there is no more loop, all traversable bits should have been cleared.
509 // This property is needed by subsequent calls.
510 for (const auto *b : blocks) {
511 assert(!b->traversable);
512 (void)b;
513 }
514 return count;
515}
516
517//===----------------------------------------------------------------------===//
518// FileInfo implementation.
519
520// Format dividend/divisor as a percentage. Return 1 if the result is greater
521// than 0% and less than 1%.
522static uint32_t formatPercentage(uint64_t dividend, uint64_t divisor) {
523 if (!dividend || !divisor)
524 return 0;
525 dividend *= 100;
526 return dividend < divisor ? 1 : dividend / divisor;
527}
528
529// This custom division function mimics gcov's branch ouputs:
530// - Round to closest whole number
531// - Only output 0% or 100% if it's exactly that value
532static uint32_t branchDiv(uint64_t Numerator, uint64_t Divisor) {
533 if (!Numerator)
534 return 0;
535 if (Numerator == Divisor)
536 return 100;
537
538 uint8_t Res = (Numerator * 100 + Divisor / 2) / Divisor;
539 if (Res == 0)
540 return 1;
541 if (Res == 100)
542 return 99;
543 return Res;
544}
545
546namespace {
547struct formatBranchInfo {
548 formatBranchInfo(const GCOV::Options &Options, uint64_t Count, uint64_t Total)
549 : Options(Options), Count(Count), Total(Total) {}
550
551 void print(raw_ostream &OS) const {
552 if (!Total)
553 OS << "never executed";
554 else if (Options.BranchCount)
555 OS << "taken " << Count;
556 else
557 OS << "taken " << branchDiv(Count, Total) << "%";
558 }
559
560 const GCOV::Options &Options;
561 uint64_t Count;
563};
564
565static raw_ostream &operator<<(raw_ostream &OS, const formatBranchInfo &FBI) {
566 FBI.print(OS);
567 return OS;
568}
569
570class LineConsumer {
571 std::unique_ptr<MemoryBuffer> Buffer;
572 StringRef Remaining;
573
574public:
575 LineConsumer() = default;
576 LineConsumer(StringRef Filename) {
577 // Open source files without requiring a NUL terminator. The concurrent
578 // modification may nullify the NUL terminator condition.
580 MemoryBuffer::getFileOrSTDIN(Filename, /*IsText=*/false,
581 /*RequiresNullTerminator=*/false);
582 if (std::error_code EC = BufferOrErr.getError()) {
583 errs() << Filename << ": " << EC.message() << "\n";
584 Remaining = "";
585 } else {
586 Buffer = std::move(BufferOrErr.get());
587 Remaining = Buffer->getBuffer();
588 }
589 }
590 bool empty() { return Remaining.empty(); }
591 void printNext(raw_ostream &OS, uint32_t LineNum) {
593 if (empty())
594 Line = "/*EOF*/";
595 else
596 std::tie(Line, Remaining) = Remaining.split("\n");
597 OS << format("%5u:", LineNum) << Line << "\n";
598 }
599};
600} // end anonymous namespace
601
602/// Convert a path to a gcov filename. If PreservePaths is true, this
603/// translates "/" to "#", ".." to "^", and drops ".", to match gcov.
604static std::string mangleCoveragePath(StringRef Filename, bool PreservePaths) {
605 if (!PreservePaths)
606 return sys::path::filename(Filename).str();
607
608 // This behaviour is defined by gcov in terms of text replacements, so it's
609 // not likely to do anything useful on filesystems with different textual
610 // conventions.
611 llvm::SmallString<256> Result("");
613 for (I = S = Filename.begin(), E = Filename.end(); I != E; ++I) {
614 if (*I != '/')
615 continue;
616
617 if (I - S == 1 && *S == '.') {
618 // ".", the current directory, is skipped.
619 } else if (I - S == 2 && *S == '.' && *(S + 1) == '.') {
620 // "..", the parent directory, is replaced with "^".
621 Result.append("^#");
622 } else {
623 if (S < I)
624 // Leave other components intact,
625 Result.append(S, I);
626 // And separate with "#".
627 Result.push_back('#');
628 }
629 S = I + 1;
630 }
631
632 if (S < I)
633 Result.append(S, I);
634 return std::string(Result.str());
635}
636
637std::string Context::getCoveragePath(StringRef filename,
638 StringRef mainFilename) const {
639 if (options.NoOutput)
640 // This is probably a bug in gcov, but when -n is specified, paths aren't
641 // mangled at all, and the -l and -p options are ignored. Here, we do the
642 // same.
643 return std::string(filename);
644
645 std::string CoveragePath;
646 if (options.LongFileNames && !filename.equals(mainFilename))
647 CoveragePath =
648 mangleCoveragePath(mainFilename, options.PreservePaths) + "##";
649 CoveragePath += mangleCoveragePath(filename, options.PreservePaths);
650 if (options.HashFilenames) {
651 MD5 Hasher;
653 Hasher.update(filename.str());
654 Hasher.final(Result);
655 CoveragePath += "##" + std::string(Result.digest());
656 }
657 CoveragePath += ".gcov";
658 return CoveragePath;
659}
660
661void Context::collectFunction(GCOVFunction &f, Summary &summary) {
662 SourceInfo &si = sources[f.srcIdx];
663 if (f.startLine >= si.startLineToFunctions.size())
664 si.startLineToFunctions.resize(f.startLine + 1);
665 si.startLineToFunctions[f.startLine].push_back(&f);
667 SmallSet<uint32_t, 16> linesExec;
668 for (const GCOVBlock &b : f.blocksRange()) {
669 if (b.lines.empty())
670 continue;
671 uint32_t maxLineNum = *std::max_element(b.lines.begin(), b.lines.end());
672 if (maxLineNum >= si.lines.size())
673 si.lines.resize(maxLineNum + 1);
674 for (uint32_t lineNum : b.lines) {
675 LineInfo &line = si.lines[lineNum];
676 if (lines.insert(lineNum).second)
677 ++summary.lines;
678 if (b.count && linesExec.insert(lineNum).second)
679 ++summary.linesExec;
680 line.exists = true;
681 line.count += b.count;
682 line.blocks.push_back(&b);
683 }
684 }
685}
686
687void Context::collectSourceLine(SourceInfo &si, Summary *summary,
688 LineInfo &line, size_t lineNum) const {
689 uint64_t count = 0;
690 for (const GCOVBlock *b : line.blocks) {
691 if (b->number == 0) {
692 // For nonstandard control flows, arcs into the exit block may be
693 // duplicately counted (fork) or not be counted (abnormal exit), and thus
694 // the (exit,entry) counter may be inaccurate. Count the entry block with
695 // the outgoing arcs.
696 for (const GCOVArc *arc : b->succ)
697 count += arc->count;
698 } else {
699 // Add counts from predecessors that are not on the same line.
700 for (const GCOVArc *arc : b->pred)
701 if (!llvm::is_contained(line.blocks, &arc->src))
702 count += arc->count;
703 }
704 for (GCOVArc *arc : b->succ)
705 arc->cycleCount = arc->count;
706 }
707
708 count += GCOVBlock::getCyclesCount(line.blocks);
709 line.count = count;
710 if (line.exists) {
711 ++summary->lines;
712 if (line.count != 0)
713 ++summary->linesExec;
714 }
715
716 if (options.BranchInfo)
717 for (const GCOVBlock *b : line.blocks) {
718 if (b->getLastLine() != lineNum)
719 continue;
720 int branches = 0, execBranches = 0, takenBranches = 0;
721 for (const GCOVArc *arc : b->succ) {
722 ++branches;
723 if (count != 0)
724 ++execBranches;
725 if (arc->count != 0)
726 ++takenBranches;
727 }
728 if (branches > 1) {
729 summary->branches += branches;
730 summary->branchesExec += execBranches;
731 summary->branchesTaken += takenBranches;
732 }
733 }
734}
735
736void Context::collectSource(SourceInfo &si, Summary &summary) const {
737 size_t lineNum = 0;
738 for (LineInfo &line : si.lines) {
739 collectSourceLine(si, &summary, line, lineNum);
740 ++lineNum;
741 }
742}
743
744void Context::annotateSource(SourceInfo &si, const GCOVFile &file,
745 StringRef gcno, StringRef gcda,
746 raw_ostream &os) const {
747 auto source =
748 options.Intermediate ? LineConsumer() : LineConsumer(si.filename);
749
750 os << " -: 0:Source:" << si.displayName << '\n';
751 os << " -: 0:Graph:" << gcno << '\n';
752 os << " -: 0:Data:" << gcda << '\n';
753 os << " -: 0:Runs:" << file.runCount << '\n';
754 if (file.version < GCOV::V900)
755 os << " -: 0:Programs:" << file.programCount << '\n';
756
757 for (size_t lineNum = 1; !source.empty(); ++lineNum) {
758 if (lineNum >= si.lines.size()) {
759 os << " -:";
760 source.printNext(os, lineNum);
761 continue;
762 }
763
764 const LineInfo &line = si.lines[lineNum];
765 if (options.BranchInfo && lineNum < si.startLineToFunctions.size())
766 for (const auto *f : si.startLineToFunctions[lineNum])
767 printFunctionDetails(*f, os);
768 if (!line.exists)
769 os << " -:";
770 else if (line.count == 0)
771 os << " #####:";
772 else
773 os << format("%9" PRIu64 ":", line.count);
774 source.printNext(os, lineNum);
775
776 uint32_t blockIdx = 0, edgeIdx = 0;
777 for (const GCOVBlock *b : line.blocks) {
778 if (b->getLastLine() != lineNum)
779 continue;
780 if (options.AllBlocks) {
781 if (b->getCount() == 0)
782 os << " $$$$$:";
783 else
784 os << format("%9" PRIu64 ":", b->count);
785 os << format("%5u-block %2u\n", lineNum, blockIdx++);
786 }
787 if (options.BranchInfo) {
788 size_t NumEdges = b->succ.size();
789 if (NumEdges > 1)
790 printBranchInfo(*b, edgeIdx, os);
791 else if (options.UncondBranch && NumEdges == 1) {
792 uint64_t count = b->succ[0]->count;
793 os << format("unconditional %2u ", edgeIdx++)
794 << formatBranchInfo(options, count, count) << '\n';
795 }
796 }
797 }
798 }
799}
800
801void Context::printSourceToIntermediate(const SourceInfo &si,
802 raw_ostream &os) const {
803 os << "file:" << si.filename << '\n';
804 for (const auto &fs : si.startLineToFunctions)
805 for (const GCOVFunction *f : fs)
806 os << "function:" << f->startLine << ',' << f->getEntryCount() << ','
807 << f->getName(options.Demangle) << '\n';
808 for (size_t lineNum = 1, size = si.lines.size(); lineNum < size; ++lineNum) {
809 const LineInfo &line = si.lines[lineNum];
810 if (line.blocks.empty())
811 continue;
812 // GCC 8 (r254259) added third third field for Ada:
813 // lcount:<line>,<count>,<has_unexecuted_blocks>
814 // We don't need the third field.
815 os << "lcount:" << lineNum << ',' << line.count << '\n';
816
817 if (!options.BranchInfo)
818 continue;
819 for (const GCOVBlock *b : line.blocks) {
820 if (b->succ.size() < 2 || b->getLastLine() != lineNum)
821 continue;
822 for (const GCOVArc *arc : b->succ) {
823 const char *type =
824 b->getCount() ? arc->count ? "taken" : "nottaken" : "notexec";
825 os << "branch:" << lineNum << ',' << type << '\n';
826 }
827 }
828 }
829}
830
831void Context::print(StringRef filename, StringRef gcno, StringRef gcda,
832 GCOVFile &file) {
833 for (StringRef filename : file.filenames) {
834 sources.emplace_back(filename);
835 SourceInfo &si = sources.back();
836 si.displayName = si.filename;
837 if (!options.SourcePrefix.empty() &&
838 sys::path::replace_path_prefix(si.displayName, options.SourcePrefix,
839 "") &&
840 !si.displayName.empty()) {
841 // TODO replace_path_prefix may strip the prefix even if the remaining
842 // part does not start with a separator.
843 if (sys::path::is_separator(si.displayName[0]))
844 si.displayName.erase(si.displayName.begin());
845 else
846 si.displayName = si.filename;
847 }
848 if (options.RelativeOnly && sys::path::is_absolute(si.displayName))
849 si.ignored = true;
850 }
851
852 raw_ostream &os = llvm::outs();
853 for (GCOVFunction &f : make_pointee_range(file.functions)) {
854 Summary summary(f.getName(options.Demangle));
855 collectFunction(f, summary);
856 if (options.FuncCoverage && !options.UseStdout) {
857 os << "Function '" << summary.Name << "'\n";
858 printSummary(summary, os);
859 os << '\n';
860 }
861 }
862
863 for (SourceInfo &si : sources) {
864 if (si.ignored)
865 continue;
866 Summary summary(si.displayName);
867 collectSource(si, summary);
868
869 // Print file summary unless -t is specified.
870 std::string gcovName = getCoveragePath(si.filename, filename);
871 if (!options.UseStdout) {
872 os << "File '" << summary.Name << "'\n";
873 printSummary(summary, os);
874 if (!options.NoOutput && !options.Intermediate)
875 os << "Creating '" << gcovName << "'\n";
876 os << '\n';
877 }
878
879 if (options.NoOutput || options.Intermediate)
880 continue;
881 std::optional<raw_fd_ostream> os;
882 if (!options.UseStdout) {
883 std::error_code ec;
884 os.emplace(gcovName, ec, sys::fs::OF_TextWithCRLF);
885 if (ec) {
886 errs() << ec.message() << '\n';
887 continue;
888 }
889 }
890 annotateSource(si, file, gcno, gcda,
891 options.UseStdout ? llvm::outs() : *os);
892 }
893
894 if (options.Intermediate && !options.NoOutput) {
895 // gcov 7.* unexpectedly create multiple .gcov files, which was fixed in 8.0
896 // (PR GCC/82702). We create just one file.
897 std::string outputPath(sys::path::filename(filename));
898 std::error_code ec;
899 raw_fd_ostream os(outputPath + ".gcov", ec, sys::fs::OF_TextWithCRLF);
900 if (ec) {
901 errs() << ec.message() << '\n';
902 return;
903 }
904
905 for (const SourceInfo &si : sources)
906 printSourceToIntermediate(si, os);
907 }
908}
909
910void Context::printFunctionDetails(const GCOVFunction &f,
911 raw_ostream &os) const {
912 const uint64_t entryCount = f.getEntryCount();
913 uint32_t blocksExec = 0;
914 const GCOVBlock &exitBlock = f.getExitBlock();
915 uint64_t exitCount = 0;
916 for (const GCOVArc *arc : exitBlock.pred)
917 exitCount += arc->count;
918 for (const GCOVBlock &b : f.blocksRange())
919 if (b.number != 0 && &b != &exitBlock && b.getCount())
920 ++blocksExec;
921
922 os << "function " << f.getName(options.Demangle) << " called " << entryCount
923 << " returned " << formatPercentage(exitCount, entryCount)
924 << "% blocks executed "
925 << formatPercentage(blocksExec, f.blocks.size() - 2) << "%\n";
926}
927
928/// printBranchInfo - Print conditional branch probabilities.
929void Context::printBranchInfo(const GCOVBlock &Block, uint32_t &edgeIdx,
930 raw_ostream &os) const {
931 uint64_t total = 0;
932 for (const GCOVArc *arc : Block.dsts())
933 total += arc->count;
934 for (const GCOVArc *arc : Block.dsts())
935 os << format("branch %2u ", edgeIdx++)
936 << formatBranchInfo(options, arc->count, total) << '\n';
937}
938
939void Context::printSummary(const Summary &summary, raw_ostream &os) const {
940 os << format("Lines executed:%.2f%% of %" PRIu64 "\n",
941 double(summary.linesExec) * 100 / summary.lines, summary.lines);
942 if (options.BranchInfo) {
943 if (summary.branches == 0) {
944 os << "No branches\n";
945 } else {
946 os << format("Branches executed:%.2f%% of %" PRIu64 "\n",
947 double(summary.branchesExec) * 100 / summary.branches,
948 summary.branches);
949 os << format("Taken at least once:%.2f%% of %" PRIu64 "\n",
950 double(summary.branchesTaken) * 100 / summary.branches,
951 summary.branches);
952 }
953 os << "No calls\n";
954 }
955}
956
957void llvm::gcovOneInput(const GCOV::Options &options, StringRef filename,
958 StringRef gcno, StringRef gcda, GCOVFile &file) {
959 Context fi(options);
960 fi.print(filename, gcno, gcda, file);
961}
arc branch ARC finalize branches
static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val)
bbsections Prepares for basic block by splitting functions into clusters of basic blocks
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
Definition: Compiler.h:510
Looks at all the uses of the given value Returns the Liveness deduced from the uses of this value Adds all uses that cause the result to be MaybeLive to MaybeLiveRetUses If the result is MaybeLiveUses might be modified but its content should be ignored(since it might not be complete). DeadArgumentEliminationPass
@ GCOV_TAG_LINES
Definition: GCOV.cpp:38
@ GCOV_TAG_COUNTER_ARCS
Definition: GCOV.cpp:39
@ GCOV_TAG_PROGRAM_SUMMARY
Definition: GCOV.cpp:42
@ GCOV_ARC_FALLTHROUGH
Definition: GCOV.cpp:33
@ GCOV_TAG_OBJECT_SUMMARY
Definition: GCOV.cpp:41
@ GCOV_ARC_ON_TREE
Definition: GCOV.cpp:32
@ GCOV_TAG_ARCS
Definition: GCOV.cpp:37
@ GCOV_TAG_FUNCTION
Definition: GCOV.cpp:35
@ GCOV_TAG_BLOCKS
Definition: GCOV.cpp:36
static std::string mangleCoveragePath(StringRef Filename, bool PreservePaths)
Convert a path to a gcov filename.
Definition: GCOV.cpp:604
static uint32_t formatPercentage(uint64_t dividend, uint64_t divisor)
Definition: GCOV.cpp:522
static uint32_t branchDiv(uint64_t Numerator, uint64_t Divisor)
Definition: GCOV.cpp:532
hexagon gen pred
static bool sink(Instruction &I, LoopInfo *LI, DominatorTree *DT, const Loop *CurLoop, ICFLoopSafetyInfo *SafetyInfo, MemorySSAUpdater &MSSAU, OptimizationRemarkEmitter *ORE)
When an instruction is found to only be used outside of the loop, this function moves it to the exit ...
Definition: LICM.cpp:1615
static LVOptions Options
Definition: LVOptions.cpp:25
#define I(x, y, z)
Definition: MD5.cpp:58
LLVMContext & Context
#define P(N)
dot regions Print regions of function to dot file(with no function bodies)"
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file contains some templates that are useful if you are working with the STL at all.
raw_pwrite_stream & OS
This file defines the SmallSet class.
unify loop Fixup each natural loop to have a single exit block
uint64_t tell() const
Return the current position of this Cursor.
Definition: DataExtractor.h:71
void skip(Cursor &C, uint64_t Length) const
Advance the Cursor position by the given number of bytes.
Represents either an error or a value T.
Definition: ErrorOr.h:56
reference get()
Definition: ErrorOr.h:149
std::error_code getError() const
Definition: ErrorOr.h:152
GCOVBlock - Collects block information.
Definition: GCOV.h:274
static uint64_t getCyclesCount(const BlockVector &blocks)
Definition: GCOV.cpp:489
SmallVector< uint32_t, 4 > lines
Definition: GCOV.h:313
void addDstEdge(GCOVArc *Edge)
Definition: GCOV.h:289
uint32_t number
Definition: GCOV.h:309
void addSrcEdge(GCOVArc *Edge)
Definition: GCOV.h:287
bool traversable
Definition: GCOV.h:314
void print(raw_ostream &OS) const
collectLineCounts - Collect line counts.
Definition: GCOV.cpp:407
GCOVArc * incoming
Definition: GCOV.h:315
static uint64_t augmentOneCycle(GCOVBlock *src, std::vector< std::pair< GCOVBlock *, size_t > > &stack)
Definition: GCOV.cpp:438
SmallVector< GCOVArc *, 2 > pred
Definition: GCOV.h:311
void dump() const
dump - Dump GCOVBlock content to dbgs() for debugging purposes.
Definition: GCOV.cpp:434
uint64_t count
Definition: GCOV.h:310
SmallVector< GCOVArc *, 2 > succ
Definition: GCOV.h:312
GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific read operations.
Definition: GCOV.h:73
bool readInt(uint32_t &Val)
Definition: GCOV.h:152
DataExtractor::Cursor cursor
Definition: GCOV.h:182
bool readInt64(uint64_t &Val)
Definition: GCOV.h:162
bool readGCOVVersion(GCOV::GCOVVersion &version)
readGCOVVersion - Read GCOV version.
Definition: GCOV.h:108
bool readString(StringRef &str)
Definition: GCOV.h:170
DataExtractor de
Definition: GCOV.h:181
uint32_t getWord()
Definition: GCOV.h:144
bool readGCNOFormat()
readGCNOFormat - Check GCNO signature is valid at the beginning of buffer.
Definition: GCOV.h:79
bool readGCDAFormat()
readGCDAFormat - Check GCDA signature is valid at the beginning of buffer.
Definition: GCOV.h:94
GCOVFile - Collects coverage information for one pair of coverage file (.gcno and ....
Definition: GCOV.h:191
SmallVector< std::unique_ptr< GCOVFunction >, 16 > functions
Definition: GCOV.h:209
uint32_t checksum
Definition: GCOV.h:207
void print(raw_ostream &OS) const
Definition: GCOV.cpp:307
uint32_t programCount
Definition: GCOV.h:212
uint32_t runCount
Definition: GCOV.h:211
GCOV::GCOVVersion version
Definition: GCOV.h:206
std::vector< std::string > filenames
Definition: GCOV.h:201
GCOV::GCOVVersion getVersion() const
Definition: GCOV.h:197
void dump() const
dump - Dump GCOVFile content to dbgs() for debugging purposes.
Definition: GCOV.cpp:314
std::map< uint32_t, GCOVFunction * > identToFunction
Definition: GCOV.h:210
StringRef cwd
Definition: GCOV.h:208
bool GCNOInitialized
Definition: GCOV.h:205
StringMap< unsigned > filenameToIdx
Definition: GCOV.h:202
bool readGCNO(GCOVBuffer &Buffer)
readGCNO - Read GCNO buffer.
Definition: GCOV.cpp:102
bool readGCDA(GCOVBuffer &Buffer)
readGCDA - Read GCDA buffer.
Definition: GCOV.cpp:210
GCOVFunction - Collects function information.
Definition: GCOV.h:236
uint64_t getEntryCount() const
getEntryCount - Get the number of times the function was called by retrieving the entry block's count...
Definition: GCOV.cpp:357
uint32_t endColumn
Definition: GCOV.h:263
SmallVector< std::unique_ptr< GCOVArc >, 0 > treeArcs
Definition: GCOV.h:269
StringRef getName(bool demangle) const
Definition: GCOV.cpp:335
uint32_t cfgChecksum
Definition: GCOV.h:259
void dump() const
dump - Dump GCOVFunction content to dbgs() for debugging purposes.
Definition: GCOV.cpp:398
StringRef Name
Definition: GCOV.h:265
uint8_t artificial
Definition: GCOV.h:264
uint64_t propagateCounts(const GCOVBlock &v, GCOVArc *pred)
Definition: GCOV.cpp:369
uint32_t endLine
Definition: GCOV.h:262
SmallVector< std::unique_ptr< GCOVBlock >, 0 > blocks
Definition: GCOV.h:268
GCOVBlock & getExitBlock() const
Definition: GCOV.cpp:361
StringRef getFilename() const
Definition: GCOV.cpp:353
DenseSet< const GCOVBlock * > visited
Definition: GCOV.h:270
uint32_t startLine
Definition: GCOV.h:260
SmallString< 0 > demangled
Definition: GCOV.h:266
void print(raw_ostream &OS) const
Definition: GCOV.cpp:389
uint32_t startColumn
Definition: GCOV.h:261
uint32_t linenoChecksum
Definition: GCOV.h:258
iterator_range< BlockIterator > blocksRange() const
Definition: GCOV.h:248
SmallVector< std::unique_ptr< GCOVArc >, 0 > arcs
Definition: GCOV.h:269
uint32_t ident
Definition: GCOV.h:257
unsigned srcIdx
Definition: GCOV.h:267
GCOVFile & file
Definition: GCOV.h:256
Definition: MD5.h:41
void update(ArrayRef< uint8_t > Data)
Updates the hash for the byte stream provided.
Definition: MD5.cpp:189
void final(MD5Result &Result)
Finishes off the hash and puts the result in result.
Definition: MD5.cpp:234
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFileOrSTDIN(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, or open stdin if the Filename is "-".
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
Definition: SmallSet.h:135
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
Definition: SmallSet.h:179
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition: SmallString.h:26
bool empty() const
Definition: SmallVector.h:94
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
unsigned size() const
Definition: StringMap.h:95
std::pair< iterator, bool > try_emplace(StringRef Key, ArgsTy &&...Args)
Emplace a new element for the specified key into the map if the key isn't already in the map.
Definition: StringMap.h:341
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
Definition: StringRef.h:704
std::string str() const
str - Get the contents as an std::string.
Definition: StringRef.h:222
constexpr bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:134
bool startswith(StringRef Prefix) const
Definition: StringRef.h:261
bool equals(StringRef RHS) const
equals - Check for string equality, this is more efficient than compare() when the relative ordering ...
Definition: StringRef.h:164
const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
Definition: StringRef.h:131
A raw_ostream that writes to a file descriptor.
Definition: raw_ostream.h:454
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
GCOVVersion
Definition: GCOV.h:42
@ V407
Definition: GCOV.h:42
@ V800
Definition: GCOV.h:42
@ V408
Definition: GCOV.h:42
@ V900
Definition: GCOV.h:42
@ V1200
Definition: GCOV.h:42
LVOptions & options()
Definition: LVOptions.h:445
bool exists(const basic_file_status &status)
Does file exist?
Definition: Path.cpp:1079
@ OF_TextWithCRLF
The file should be opened in text mode and use a carriage linefeed '\r '.
Definition: FileSystem.h:768
bool remove_dots(SmallVectorImpl< char > &path, bool remove_dot_dot=false, Style style=Style::native)
In-place remove any '.
Definition: Path.cpp:717
StringRef filename(StringRef path, Style style=Style::native)
Get filename.
Definition: Path.cpp:579
bool is_absolute(const Twine &path, Style style=Style::native)
Is path absolute?
Definition: Path.cpp:673
bool replace_path_prefix(SmallVectorImpl< char > &Path, StringRef OldPrefix, StringRef NewPrefix, Style style=Style::native)
Replace matching path prefix with another path.
Definition: Path.cpp:520
bool is_separator(char value, Style style=Style::native)
Check whether the given char is a path separator on the host OS.
Definition: Path.cpp:603
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
raw_fd_ostream & outs()
This returns a reference to a raw_fd_ostream for standard output.
iterator_range< pointee_iterator< WrappedIteratorT > > make_pointee_range(RangeT &&Range)
Definition: iterator.h:336
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Definition: Format.h:125
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
auto count(R &&Range, const E &Element)
Wrapper function around std::count to count the number of times an element Element occurs in the give...
Definition: STLExtras.h:1919
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
Definition: APFixedPoint.h:292
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition: STLExtras.h:1884
void gcovOneInput(const GCOV::Options &options, StringRef filename, StringRef gcno, StringRef gcda, GCOVFile &file)
Definition: GCOV.cpp:957
char * itaniumDemangle(std::string_view mangled_name)
Returns a non-NULL pointer to a NUL-terminated C style string that should be explicitly freed,...
std::string demangle(std::string_view MangledName)
Attempt to demangle a string using different demangling schemes.
Definition: Demangle.cpp:20
#define N
uint64_t count
Definition: GCOV.h:231
bool onTree() const
Definition: GCOV.cpp:330
GCOVBlock & src
Definition: GCOV.h:228
uint64_t cycleCount
Definition: GCOV.h:232
uint32_t flags
Definition: GCOV.h:230
A struct for passing gcov options between functions.
Definition: GCOV.h:45