10b57cec5SDimitry Andric //===- GCOV.cpp - LLVM coverage tool --------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // GCOV implements the interface to read and write coverage files that use
100b57cec5SDimitry Andric // 'gcov' format.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "llvm/ProfileData/GCOV.h"
150b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
1681ad6265SDimitry Andric #include "llvm/ADT/SmallSet.h"
170b57cec5SDimitry Andric #include "llvm/Config/llvm-config.h"
18e8d8bef9SDimitry Andric #include "llvm/Demangle/Demangle.h"
190b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
200b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
210b57cec5SDimitry Andric #include "llvm/Support/Format.h"
220b57cec5SDimitry Andric #include "llvm/Support/MD5.h"
23e8d8bef9SDimitry Andric #include "llvm/Support/Path.h"
240b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
250b57cec5SDimitry Andric #include <algorithm>
26bdd1243dSDimitry Andric #include <optional>
270b57cec5SDimitry Andric #include <system_error>
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric using namespace llvm;
300b57cec5SDimitry Andric 
315ffd83dbSDimitry Andric enum : uint32_t {
325ffd83dbSDimitry Andric   GCOV_ARC_ON_TREE = 1 << 0,
335ffd83dbSDimitry Andric   GCOV_ARC_FALLTHROUGH = 1 << 2,
345ffd83dbSDimitry Andric 
355ffd83dbSDimitry Andric   GCOV_TAG_FUNCTION = 0x01000000,
365ffd83dbSDimitry Andric   GCOV_TAG_BLOCKS = 0x01410000,
375ffd83dbSDimitry Andric   GCOV_TAG_ARCS = 0x01430000,
385ffd83dbSDimitry Andric   GCOV_TAG_LINES = 0x01450000,
395ffd83dbSDimitry Andric   GCOV_TAG_COUNTER_ARCS = 0x01a10000,
405ffd83dbSDimitry Andric   // GCOV_TAG_OBJECT_SUMMARY superseded GCOV_TAG_PROGRAM_SUMMARY in GCC 9.
415ffd83dbSDimitry Andric   GCOV_TAG_OBJECT_SUMMARY = 0xa1000000,
425ffd83dbSDimitry Andric   GCOV_TAG_PROGRAM_SUMMARY = 0xa3000000,
435ffd83dbSDimitry Andric };
445ffd83dbSDimitry Andric 
45e8d8bef9SDimitry Andric namespace {
46e8d8bef9SDimitry Andric struct Summary {
47e8d8bef9SDimitry Andric   Summary(StringRef Name) : Name(Name) {}
48e8d8bef9SDimitry Andric 
49e8d8bef9SDimitry Andric   StringRef Name;
50e8d8bef9SDimitry Andric   uint64_t lines = 0;
51e8d8bef9SDimitry Andric   uint64_t linesExec = 0;
52e8d8bef9SDimitry Andric   uint64_t branches = 0;
53e8d8bef9SDimitry Andric   uint64_t branchesExec = 0;
54e8d8bef9SDimitry Andric   uint64_t branchesTaken = 0;
55e8d8bef9SDimitry Andric };
56e8d8bef9SDimitry Andric 
57e8d8bef9SDimitry Andric struct LineInfo {
58e8d8bef9SDimitry Andric   SmallVector<const GCOVBlock *, 1> blocks;
59e8d8bef9SDimitry Andric   uint64_t count = 0;
60e8d8bef9SDimitry Andric   bool exists = false;
61e8d8bef9SDimitry Andric };
62e8d8bef9SDimitry Andric 
63e8d8bef9SDimitry Andric struct SourceInfo {
64e8d8bef9SDimitry Andric   StringRef filename;
65e8d8bef9SDimitry Andric   SmallString<0> displayName;
66e8d8bef9SDimitry Andric   std::vector<std::vector<const GCOVFunction *>> startLineToFunctions;
67e8d8bef9SDimitry Andric   std::vector<LineInfo> lines;
68e8d8bef9SDimitry Andric   bool ignored = false;
69e8d8bef9SDimitry Andric   SourceInfo(StringRef filename) : filename(filename) {}
70e8d8bef9SDimitry Andric };
71e8d8bef9SDimitry Andric 
72e8d8bef9SDimitry Andric class Context {
73e8d8bef9SDimitry Andric public:
74e8d8bef9SDimitry Andric   Context(const GCOV::Options &Options) : options(Options) {}
75e8d8bef9SDimitry Andric   void print(StringRef filename, StringRef gcno, StringRef gcda,
76e8d8bef9SDimitry Andric              GCOVFile &file);
77e8d8bef9SDimitry Andric 
78e8d8bef9SDimitry Andric private:
79e8d8bef9SDimitry Andric   std::string getCoveragePath(StringRef filename, StringRef mainFilename) const;
80e8d8bef9SDimitry Andric   void printFunctionDetails(const GCOVFunction &f, raw_ostream &os) const;
81e8d8bef9SDimitry Andric   void printBranchInfo(const GCOVBlock &Block, uint32_t &edgeIdx,
82e8d8bef9SDimitry Andric                        raw_ostream &OS) const;
83e8d8bef9SDimitry Andric   void printSummary(const Summary &summary, raw_ostream &os) const;
84e8d8bef9SDimitry Andric 
85e8d8bef9SDimitry Andric   void collectFunction(GCOVFunction &f, Summary &summary);
86e8d8bef9SDimitry Andric   void collectSourceLine(SourceInfo &si, Summary *summary, LineInfo &line,
87e8d8bef9SDimitry Andric                          size_t lineNum) const;
88e8d8bef9SDimitry Andric   void collectSource(SourceInfo &si, Summary &summary) const;
89e8d8bef9SDimitry Andric   void annotateSource(SourceInfo &si, const GCOVFile &file, StringRef gcno,
90e8d8bef9SDimitry Andric                       StringRef gcda, raw_ostream &os) const;
91e8d8bef9SDimitry Andric   void printSourceToIntermediate(const SourceInfo &si, raw_ostream &os) const;
92e8d8bef9SDimitry Andric 
93e8d8bef9SDimitry Andric   const GCOV::Options &options;
94e8d8bef9SDimitry Andric   std::vector<SourceInfo> sources;
95e8d8bef9SDimitry Andric };
96e8d8bef9SDimitry Andric } // namespace
97e8d8bef9SDimitry Andric 
980b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
990b57cec5SDimitry Andric // GCOVFile implementation.
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric /// readGCNO - Read GCNO buffer.
1025ffd83dbSDimitry Andric bool GCOVFile::readGCNO(GCOVBuffer &buf) {
1035ffd83dbSDimitry Andric   if (!buf.readGCNOFormat())
1040b57cec5SDimitry Andric     return false;
105fe6060f1SDimitry Andric   if (!buf.readGCOVVersion(version))
1060b57cec5SDimitry Andric     return false;
1070b57cec5SDimitry Andric 
108fe6060f1SDimitry Andric   checksum = buf.getWord();
109fe6060f1SDimitry Andric   if (version >= GCOV::V900 && !buf.readString(cwd))
110fe6060f1SDimitry Andric     return false;
111fe6060f1SDimitry Andric   if (version >= GCOV::V800)
1125ffd83dbSDimitry Andric     buf.getWord(); // hasUnexecutedBlocks
1135ffd83dbSDimitry Andric 
1145ffd83dbSDimitry Andric   uint32_t tag, length;
115e8d8bef9SDimitry Andric   GCOVFunction *fn = nullptr;
1165ffd83dbSDimitry Andric   while ((tag = buf.getWord())) {
1175ffd83dbSDimitry Andric     if (!buf.readInt(length))
1180b57cec5SDimitry Andric       return false;
119fe6060f1SDimitry Andric     uint32_t pos = buf.cursor.tell();
1205ffd83dbSDimitry Andric     if (tag == GCOV_TAG_FUNCTION) {
121e8d8bef9SDimitry Andric       functions.push_back(std::make_unique<GCOVFunction>(*this));
122e8d8bef9SDimitry Andric       fn = functions.back().get();
1235ffd83dbSDimitry Andric       fn->ident = buf.getWord();
1245ffd83dbSDimitry Andric       fn->linenoChecksum = buf.getWord();
125fe6060f1SDimitry Andric       if (version >= GCOV::V407)
1265ffd83dbSDimitry Andric         fn->cfgChecksum = buf.getWord();
1275ffd83dbSDimitry Andric       buf.readString(fn->Name);
1285ffd83dbSDimitry Andric       StringRef filename;
129fe6060f1SDimitry Andric       if (version < GCOV::V800) {
130fe6060f1SDimitry Andric         if (!buf.readString(filename))
131fe6060f1SDimitry Andric           return false;
1325ffd83dbSDimitry Andric         fn->startLine = buf.getWord();
1335ffd83dbSDimitry Andric       } else {
1345ffd83dbSDimitry Andric         fn->artificial = buf.getWord();
135fe6060f1SDimitry Andric         if (!buf.readString(filename))
136fe6060f1SDimitry Andric           return false;
1375ffd83dbSDimitry Andric         fn->startLine = buf.getWord();
1385ffd83dbSDimitry Andric         fn->startColumn = buf.getWord();
1395ffd83dbSDimitry Andric         fn->endLine = buf.getWord();
140fe6060f1SDimitry Andric         if (version >= GCOV::V900)
1415ffd83dbSDimitry Andric           fn->endColumn = buf.getWord();
1425ffd83dbSDimitry Andric       }
14306c3fb27SDimitry Andric       fn->srcIdx = addNormalizedPathToMap(filename);
144fe6060f1SDimitry Andric       identToFunction[fn->ident] = fn;
1455ffd83dbSDimitry Andric     } else if (tag == GCOV_TAG_BLOCKS && fn) {
146fe6060f1SDimitry Andric       if (version < GCOV::V800) {
1475ffd83dbSDimitry Andric         for (uint32_t i = 0; i != length; ++i) {
1485ffd83dbSDimitry Andric           buf.getWord(); // Ignored block flags
149e8d8bef9SDimitry Andric           fn->blocks.push_back(std::make_unique<GCOVBlock>(i));
1505ffd83dbSDimitry Andric         }
1515ffd83dbSDimitry Andric       } else {
1525ffd83dbSDimitry Andric         uint32_t num = buf.getWord();
1535ffd83dbSDimitry Andric         for (uint32_t i = 0; i != num; ++i)
154e8d8bef9SDimitry Andric           fn->blocks.push_back(std::make_unique<GCOVBlock>(i));
1555ffd83dbSDimitry Andric       }
1565ffd83dbSDimitry Andric     } else if (tag == GCOV_TAG_ARCS && fn) {
1575ffd83dbSDimitry Andric       uint32_t srcNo = buf.getWord();
158e8d8bef9SDimitry Andric       if (srcNo >= fn->blocks.size()) {
1595ffd83dbSDimitry Andric         errs() << "unexpected block number: " << srcNo << " (in "
160e8d8bef9SDimitry Andric                << fn->blocks.size() << ")\n";
1615ffd83dbSDimitry Andric         return false;
1625ffd83dbSDimitry Andric       }
163e8d8bef9SDimitry Andric       GCOVBlock *src = fn->blocks[srcNo].get();
164fe6060f1SDimitry Andric       const uint32_t e =
165fe6060f1SDimitry Andric           version >= GCOV::V1200 ? (length / 4 - 1) / 2 : (length - 1) / 2;
166fe6060f1SDimitry Andric       for (uint32_t i = 0; i != e; ++i) {
1675ffd83dbSDimitry Andric         uint32_t dstNo = buf.getWord(), flags = buf.getWord();
168e8d8bef9SDimitry Andric         GCOVBlock *dst = fn->blocks[dstNo].get();
169e8d8bef9SDimitry Andric         auto arc = std::make_unique<GCOVArc>(*src, *dst, flags);
1705ffd83dbSDimitry Andric         src->addDstEdge(arc.get());
1715ffd83dbSDimitry Andric         dst->addSrcEdge(arc.get());
172e8d8bef9SDimitry Andric         if (arc->onTree())
1735ffd83dbSDimitry Andric           fn->treeArcs.push_back(std::move(arc));
1745ffd83dbSDimitry Andric         else
1755ffd83dbSDimitry Andric           fn->arcs.push_back(std::move(arc));
1765ffd83dbSDimitry Andric       }
1775ffd83dbSDimitry Andric     } else if (tag == GCOV_TAG_LINES && fn) {
1785ffd83dbSDimitry Andric       uint32_t srcNo = buf.getWord();
179e8d8bef9SDimitry Andric       if (srcNo >= fn->blocks.size()) {
1805ffd83dbSDimitry Andric         errs() << "unexpected block number: " << srcNo << " (in "
181e8d8bef9SDimitry Andric                << fn->blocks.size() << ")\n";
1825ffd83dbSDimitry Andric         return false;
1835ffd83dbSDimitry Andric       }
184e8d8bef9SDimitry Andric       GCOVBlock &Block = *fn->blocks[srcNo];
1855ffd83dbSDimitry Andric       for (;;) {
1865ffd83dbSDimitry Andric         uint32_t line = buf.getWord();
1875ffd83dbSDimitry Andric         if (line)
1885ffd83dbSDimitry Andric           Block.addLine(line);
1895ffd83dbSDimitry Andric         else {
190fe6060f1SDimitry Andric           StringRef filename;
191fe6060f1SDimitry Andric           buf.readString(filename);
1925ffd83dbSDimitry Andric           if (filename.empty())
1930b57cec5SDimitry Andric             break;
1945ffd83dbSDimitry Andric           // TODO Unhandled
1955ffd83dbSDimitry Andric         }
1965ffd83dbSDimitry Andric       }
1975ffd83dbSDimitry Andric     }
198fe6060f1SDimitry Andric     pos += version >= GCOV::V1200 ? length : 4 * length;
199fe6060f1SDimitry Andric     if (pos < buf.cursor.tell())
200fe6060f1SDimitry Andric       return false;
201fe6060f1SDimitry Andric     buf.de.skip(buf.cursor, pos - buf.cursor.tell());
2020b57cec5SDimitry Andric   }
2030b57cec5SDimitry Andric 
2040b57cec5SDimitry Andric   GCNOInitialized = true;
2050b57cec5SDimitry Andric   return true;
2060b57cec5SDimitry Andric }
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric /// readGCDA - Read GCDA buffer. It is required that readGCDA() can only be
2090b57cec5SDimitry Andric /// called after readGCNO().
2105ffd83dbSDimitry Andric bool GCOVFile::readGCDA(GCOVBuffer &buf) {
2110b57cec5SDimitry Andric   assert(GCNOInitialized && "readGCDA() can only be called after readGCNO()");
2125ffd83dbSDimitry Andric   if (!buf.readGCDAFormat())
2130b57cec5SDimitry Andric     return false;
2140b57cec5SDimitry Andric   GCOV::GCOVVersion GCDAVersion;
2155ffd83dbSDimitry Andric   if (!buf.readGCOVVersion(GCDAVersion))
2160b57cec5SDimitry Andric     return false;
217fe6060f1SDimitry Andric   if (version != GCDAVersion) {
2180b57cec5SDimitry Andric     errs() << "GCOV versions do not match.\n";
2190b57cec5SDimitry Andric     return false;
2200b57cec5SDimitry Andric   }
2210b57cec5SDimitry Andric 
2220b57cec5SDimitry Andric   uint32_t GCDAChecksum;
2235ffd83dbSDimitry Andric   if (!buf.readInt(GCDAChecksum))
2240b57cec5SDimitry Andric     return false;
225fe6060f1SDimitry Andric   if (checksum != GCDAChecksum) {
226fe6060f1SDimitry Andric     errs() << "file checksums do not match: " << checksum
227fe6060f1SDimitry Andric            << " != " << GCDAChecksum << "\n";
2280b57cec5SDimitry Andric     return false;
2290b57cec5SDimitry Andric   }
2305ffd83dbSDimitry Andric   uint32_t dummy, tag, length;
2315ffd83dbSDimitry Andric   uint32_t ident;
2325ffd83dbSDimitry Andric   GCOVFunction *fn = nullptr;
2335ffd83dbSDimitry Andric   while ((tag = buf.getWord())) {
2345ffd83dbSDimitry Andric     if (!buf.readInt(length))
2350b57cec5SDimitry Andric       return false;
2365ffd83dbSDimitry Andric     uint32_t pos = buf.cursor.tell();
2375ffd83dbSDimitry Andric     if (tag == GCOV_TAG_OBJECT_SUMMARY) {
238fe6060f1SDimitry Andric       buf.readInt(runCount);
2395ffd83dbSDimitry Andric       buf.readInt(dummy);
2405ffd83dbSDimitry Andric       // clang<11 uses a fake 4.2 format which sets length to 9.
2415ffd83dbSDimitry Andric       if (length == 9)
242fe6060f1SDimitry Andric         buf.readInt(runCount);
2435ffd83dbSDimitry Andric     } else if (tag == GCOV_TAG_PROGRAM_SUMMARY) {
2445ffd83dbSDimitry Andric       // clang<11 uses a fake 4.2 format which sets length to 0.
2455ffd83dbSDimitry Andric       if (length > 0) {
2465ffd83dbSDimitry Andric         buf.readInt(dummy);
2475ffd83dbSDimitry Andric         buf.readInt(dummy);
248fe6060f1SDimitry Andric         buf.readInt(runCount);
2490b57cec5SDimitry Andric       }
250fe6060f1SDimitry Andric       ++programCount;
2515ffd83dbSDimitry Andric     } else if (tag == GCOV_TAG_FUNCTION) {
2525ffd83dbSDimitry Andric       if (length == 0) // Placeholder
2535ffd83dbSDimitry Andric         continue;
2545ffd83dbSDimitry Andric       // As of GCC 10, GCOV_TAG_FUNCTION_LENGTH has never been larger than 3.
2555ffd83dbSDimitry Andric       // However, clang<11 uses a fake 4.2 format which may set length larger
2565ffd83dbSDimitry Andric       // than 3.
2575ffd83dbSDimitry Andric       if (length < 2 || !buf.readInt(ident))
2585ffd83dbSDimitry Andric         return false;
259fe6060f1SDimitry Andric       auto It = identToFunction.find(ident);
2605ffd83dbSDimitry Andric       uint32_t linenoChecksum, cfgChecksum = 0;
2615ffd83dbSDimitry Andric       buf.readInt(linenoChecksum);
262fe6060f1SDimitry Andric       if (version >= GCOV::V407)
2635ffd83dbSDimitry Andric         buf.readInt(cfgChecksum);
264fe6060f1SDimitry Andric       if (It != identToFunction.end()) {
2655ffd83dbSDimitry Andric         fn = It->second;
2665ffd83dbSDimitry Andric         if (linenoChecksum != fn->linenoChecksum ||
2675ffd83dbSDimitry Andric             cfgChecksum != fn->cfgChecksum) {
2685ffd83dbSDimitry Andric           errs() << fn->Name
2695ffd83dbSDimitry Andric                  << format(": checksum mismatch, (%u, %u) != (%u, %u)\n",
2705ffd83dbSDimitry Andric                            linenoChecksum, cfgChecksum, fn->linenoChecksum,
2715ffd83dbSDimitry Andric                            fn->cfgChecksum);
2725ffd83dbSDimitry Andric           return false;
2735ffd83dbSDimitry Andric         }
2745ffd83dbSDimitry Andric       }
2755ffd83dbSDimitry Andric     } else if (tag == GCOV_TAG_COUNTER_ARCS && fn) {
276fe6060f1SDimitry Andric       uint32_t expected = 2 * fn->arcs.size();
277fe6060f1SDimitry Andric       if (version >= GCOV::V1200)
278fe6060f1SDimitry Andric         expected *= 4;
279fe6060f1SDimitry Andric       if (length != expected) {
2805ffd83dbSDimitry Andric         errs() << fn->Name
2815ffd83dbSDimitry Andric                << format(
2825ffd83dbSDimitry Andric                       ": GCOV_TAG_COUNTER_ARCS mismatch, got %u, expected %u\n",
283fe6060f1SDimitry Andric                       length, expected);
2845ffd83dbSDimitry Andric         return false;
2855ffd83dbSDimitry Andric       }
2865ffd83dbSDimitry Andric       for (std::unique_ptr<GCOVArc> &arc : fn->arcs) {
287e8d8bef9SDimitry Andric         if (!buf.readInt64(arc->count))
2885ffd83dbSDimitry Andric           return false;
289e8d8bef9SDimitry Andric         arc->src.count += arc->count;
290e8d8bef9SDimitry Andric       }
291e8d8bef9SDimitry Andric 
292e8d8bef9SDimitry Andric       if (fn->blocks.size() >= 2) {
293e8d8bef9SDimitry Andric         GCOVBlock &src = *fn->blocks[0];
294e8d8bef9SDimitry Andric         GCOVBlock &sink =
295fe6060f1SDimitry Andric             version < GCOV::V408 ? *fn->blocks.back() : *fn->blocks[1];
296e8d8bef9SDimitry Andric         auto arc = std::make_unique<GCOVArc>(sink, src, GCOV_ARC_ON_TREE);
297e8d8bef9SDimitry Andric         sink.addDstEdge(arc.get());
298e8d8bef9SDimitry Andric         src.addSrcEdge(arc.get());
299e8d8bef9SDimitry Andric         fn->treeArcs.push_back(std::move(arc));
300e8d8bef9SDimitry Andric 
301e8d8bef9SDimitry Andric         for (GCOVBlock &block : fn->blocksRange())
302e8d8bef9SDimitry Andric           fn->propagateCounts(block, nullptr);
303e8d8bef9SDimitry Andric         for (size_t i = fn->treeArcs.size() - 1; i; --i)
304e8d8bef9SDimitry Andric           fn->treeArcs[i - 1]->src.count += fn->treeArcs[i - 1]->count;
3055ffd83dbSDimitry Andric       }
3065ffd83dbSDimitry Andric     }
307fe6060f1SDimitry Andric     pos += version >= GCOV::V1200 ? length : 4 * length;
3085ffd83dbSDimitry Andric     if (pos < buf.cursor.tell())
3095ffd83dbSDimitry Andric       return false;
3105ffd83dbSDimitry Andric     buf.de.skip(buf.cursor, pos - buf.cursor.tell());
3110b57cec5SDimitry Andric   }
3120b57cec5SDimitry Andric 
3130b57cec5SDimitry Andric   return true;
3140b57cec5SDimitry Andric }
3150b57cec5SDimitry Andric 
3160b57cec5SDimitry Andric void GCOVFile::print(raw_ostream &OS) const {
3175ffd83dbSDimitry Andric   for (const GCOVFunction &f : *this)
3185ffd83dbSDimitry Andric     f.print(OS);
3190b57cec5SDimitry Andric }
3200b57cec5SDimitry Andric 
3210b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
3220b57cec5SDimitry Andric /// dump - Dump GCOVFile content to dbgs() for debugging purposes.
3230b57cec5SDimitry Andric LLVM_DUMP_METHOD void GCOVFile::dump() const { print(dbgs()); }
3240b57cec5SDimitry Andric #endif
3250b57cec5SDimitry Andric 
32606c3fb27SDimitry Andric unsigned GCOVFile::addNormalizedPathToMap(StringRef filename) {
32706c3fb27SDimitry Andric   // unify filename, as the same path can have different form
32806c3fb27SDimitry Andric   SmallString<256> P(filename);
32906c3fb27SDimitry Andric   sys::path::remove_dots(P, true);
33006c3fb27SDimitry Andric   filename = P.str();
33106c3fb27SDimitry Andric 
33206c3fb27SDimitry Andric   auto r = filenameToIdx.try_emplace(filename, filenameToIdx.size());
33306c3fb27SDimitry Andric   if (r.second)
33406c3fb27SDimitry Andric     filenames.emplace_back(filename);
33506c3fb27SDimitry Andric 
33606c3fb27SDimitry Andric   return r.first->second;
33706c3fb27SDimitry Andric }
33806c3fb27SDimitry Andric 
339e8d8bef9SDimitry Andric bool GCOVArc::onTree() const { return flags & GCOV_ARC_ON_TREE; }
3400b57cec5SDimitry Andric 
3410b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
3420b57cec5SDimitry Andric // GCOVFunction implementation.
3430b57cec5SDimitry Andric 
344e8d8bef9SDimitry Andric StringRef GCOVFunction::getName(bool demangle) const {
345e8d8bef9SDimitry Andric   if (!demangle)
346e8d8bef9SDimitry Andric     return Name;
347e8d8bef9SDimitry Andric   if (demangled.empty()) {
348e8d8bef9SDimitry Andric     do {
349e8d8bef9SDimitry Andric       if (Name.startswith("_Z")) {
350e8d8bef9SDimitry Andric         // Name is guaranteed to be NUL-terminated.
35106c3fb27SDimitry Andric         if (char *res = itaniumDemangle(Name.data())) {
352e8d8bef9SDimitry Andric           demangled = res;
353e8d8bef9SDimitry Andric           free(res);
354e8d8bef9SDimitry Andric           break;
355e8d8bef9SDimitry Andric         }
356e8d8bef9SDimitry Andric       }
357e8d8bef9SDimitry Andric       demangled = Name;
35804eeddc0SDimitry Andric     } while (false);
359e8d8bef9SDimitry Andric   }
360e8d8bef9SDimitry Andric   return demangled;
361e8d8bef9SDimitry Andric }
3625ffd83dbSDimitry Andric StringRef GCOVFunction::getFilename() const { return file.filenames[srcIdx]; }
3630b57cec5SDimitry Andric 
3640b57cec5SDimitry Andric /// getEntryCount - Get the number of times the function was called by
3650b57cec5SDimitry Andric /// retrieving the entry block's count.
3660b57cec5SDimitry Andric uint64_t GCOVFunction::getEntryCount() const {
367e8d8bef9SDimitry Andric   return blocks.front()->getCount();
3680b57cec5SDimitry Andric }
3690b57cec5SDimitry Andric 
370e8d8bef9SDimitry Andric GCOVBlock &GCOVFunction::getExitBlock() const {
371e8d8bef9SDimitry Andric   return file.getVersion() < GCOV::V408 ? *blocks.back() : *blocks[1];
372e8d8bef9SDimitry Andric }
373e8d8bef9SDimitry Andric 
374e8d8bef9SDimitry Andric // For each basic block, the sum of incoming edge counts equals the sum of
375e8d8bef9SDimitry Andric // outgoing edge counts by Kirchoff's circuit law. If the unmeasured arcs form a
376e8d8bef9SDimitry Andric // spanning tree, the count for each unmeasured arc (GCOV_ARC_ON_TREE) can be
377e8d8bef9SDimitry Andric // uniquely identified.
378e8d8bef9SDimitry Andric uint64_t GCOVFunction::propagateCounts(const GCOVBlock &v, GCOVArc *pred) {
379e8d8bef9SDimitry Andric   // If GCOV_ARC_ON_TREE edges do form a tree, visited is not needed; otherwise
380e8d8bef9SDimitry Andric   // this prevents infinite recursion.
381e8d8bef9SDimitry Andric   if (!visited.insert(&v).second)
382e8d8bef9SDimitry Andric     return 0;
383e8d8bef9SDimitry Andric 
384e8d8bef9SDimitry Andric   uint64_t excess = 0;
385e8d8bef9SDimitry Andric   for (GCOVArc *e : v.srcs())
386e8d8bef9SDimitry Andric     if (e != pred)
387e8d8bef9SDimitry Andric       excess += e->onTree() ? propagateCounts(e->src, e) : e->count;
388e8d8bef9SDimitry Andric   for (GCOVArc *e : v.dsts())
389e8d8bef9SDimitry Andric     if (e != pred)
390e8d8bef9SDimitry Andric       excess -= e->onTree() ? propagateCounts(e->dst, e) : e->count;
391e8d8bef9SDimitry Andric   if (int64_t(excess) < 0)
392e8d8bef9SDimitry Andric     excess = -excess;
393e8d8bef9SDimitry Andric   if (pred)
394e8d8bef9SDimitry Andric     pred->count = excess;
395e8d8bef9SDimitry Andric   return excess;
3960b57cec5SDimitry Andric }
3970b57cec5SDimitry Andric 
3980b57cec5SDimitry Andric void GCOVFunction::print(raw_ostream &OS) const {
3995ffd83dbSDimitry Andric   OS << "===== " << Name << " (" << ident << ") @ " << getFilename() << ":"
4005ffd83dbSDimitry Andric      << startLine << "\n";
401e8d8bef9SDimitry Andric   for (const auto &Block : blocks)
4020b57cec5SDimitry Andric     Block->print(OS);
4030b57cec5SDimitry Andric }
4040b57cec5SDimitry Andric 
4050b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
4060b57cec5SDimitry Andric /// dump - Dump GCOVFunction content to dbgs() for debugging purposes.
4070b57cec5SDimitry Andric LLVM_DUMP_METHOD void GCOVFunction::dump() const { print(dbgs()); }
4080b57cec5SDimitry Andric #endif
4090b57cec5SDimitry Andric 
4100b57cec5SDimitry Andric /// collectLineCounts - Collect line counts. This must be used after
4110b57cec5SDimitry Andric /// reading .gcno and .gcda files.
4120b57cec5SDimitry Andric 
4130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
4140b57cec5SDimitry Andric // GCOVBlock implementation.
4150b57cec5SDimitry Andric 
4160b57cec5SDimitry Andric void GCOVBlock::print(raw_ostream &OS) const {
417e8d8bef9SDimitry Andric   OS << "Block : " << number << " Counter : " << count << "\n";
4185ffd83dbSDimitry Andric   if (!pred.empty()) {
4190b57cec5SDimitry Andric     OS << "\tSource Edges : ";
4205ffd83dbSDimitry Andric     for (const GCOVArc *Edge : pred)
421e8d8bef9SDimitry Andric       OS << Edge->src.number << " (" << Edge->count << "), ";
4220b57cec5SDimitry Andric     OS << "\n";
4230b57cec5SDimitry Andric   }
4245ffd83dbSDimitry Andric   if (!succ.empty()) {
4250b57cec5SDimitry Andric     OS << "\tDestination Edges : ";
426e8d8bef9SDimitry Andric     for (const GCOVArc *Edge : succ) {
427e8d8bef9SDimitry Andric       if (Edge->flags & GCOV_ARC_ON_TREE)
428e8d8bef9SDimitry Andric         OS << '*';
429e8d8bef9SDimitry Andric       OS << Edge->dst.number << " (" << Edge->count << "), ";
430e8d8bef9SDimitry Andric     }
4310b57cec5SDimitry Andric     OS << "\n";
4320b57cec5SDimitry Andric   }
433e8d8bef9SDimitry Andric   if (!lines.empty()) {
4340b57cec5SDimitry Andric     OS << "\tLines : ";
435e8d8bef9SDimitry Andric     for (uint32_t N : lines)
4360b57cec5SDimitry Andric       OS << (N) << ",";
4370b57cec5SDimitry Andric     OS << "\n";
4380b57cec5SDimitry Andric   }
4390b57cec5SDimitry Andric }
4400b57cec5SDimitry Andric 
4410b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
4420b57cec5SDimitry Andric /// dump - Dump GCOVBlock content to dbgs() for debugging purposes.
4430b57cec5SDimitry Andric LLVM_DUMP_METHOD void GCOVBlock::dump() const { print(dbgs()); }
4440b57cec5SDimitry Andric #endif
4450b57cec5SDimitry Andric 
446e8d8bef9SDimitry Andric uint64_t
447e8d8bef9SDimitry Andric GCOVBlock::augmentOneCycle(GCOVBlock *src,
448e8d8bef9SDimitry Andric                            std::vector<std::pair<GCOVBlock *, size_t>> &stack) {
449e8d8bef9SDimitry Andric   GCOVBlock *u;
450e8d8bef9SDimitry Andric   size_t i;
451e8d8bef9SDimitry Andric   stack.clear();
452e8d8bef9SDimitry Andric   stack.emplace_back(src, 0);
453e8d8bef9SDimitry Andric   src->incoming = (GCOVArc *)1; // Mark u available for cycle detection
454e8d8bef9SDimitry Andric   for (;;) {
455e8d8bef9SDimitry Andric     std::tie(u, i) = stack.back();
456e8d8bef9SDimitry Andric     if (i == u->succ.size()) {
457e8d8bef9SDimitry Andric       u->traversable = false;
458e8d8bef9SDimitry Andric       stack.pop_back();
459e8d8bef9SDimitry Andric       if (stack.empty())
460e8d8bef9SDimitry Andric         break;
4610b57cec5SDimitry Andric       continue;
4620b57cec5SDimitry Andric     }
463e8d8bef9SDimitry Andric     ++stack.back().second;
464e8d8bef9SDimitry Andric     GCOVArc *succ = u->succ[i];
465e8d8bef9SDimitry Andric     // Ignore saturated arcs (cycleCount has been reduced to 0) and visited
466e8d8bef9SDimitry Andric     // blocks. Ignore self arcs to guard against bad input (.gcno has no
467e8d8bef9SDimitry Andric     // self arcs).
468e8d8bef9SDimitry Andric     if (succ->cycleCount == 0 || !succ->dst.traversable || &succ->dst == u)
469e8d8bef9SDimitry Andric       continue;
470e8d8bef9SDimitry Andric     if (succ->dst.incoming == nullptr) {
471e8d8bef9SDimitry Andric       succ->dst.incoming = succ;
472e8d8bef9SDimitry Andric       stack.emplace_back(&succ->dst, 0);
4730b57cec5SDimitry Andric       continue;
4740b57cec5SDimitry Andric     }
475e8d8bef9SDimitry Andric     uint64_t minCount = succ->cycleCount;
476e8d8bef9SDimitry Andric     for (GCOVBlock *v = u;;) {
477e8d8bef9SDimitry Andric       minCount = std::min(minCount, v->incoming->cycleCount);
478e8d8bef9SDimitry Andric       v = &v->incoming->src;
479e8d8bef9SDimitry Andric       if (v == &succ->dst)
480e8d8bef9SDimitry Andric         break;
4810b57cec5SDimitry Andric     }
482e8d8bef9SDimitry Andric     succ->cycleCount -= minCount;
483e8d8bef9SDimitry Andric     for (GCOVBlock *v = u;;) {
484e8d8bef9SDimitry Andric       v->incoming->cycleCount -= minCount;
485e8d8bef9SDimitry Andric       v = &v->incoming->src;
486e8d8bef9SDimitry Andric       if (v == &succ->dst)
487e8d8bef9SDimitry Andric         break;
4880b57cec5SDimitry Andric     }
489e8d8bef9SDimitry Andric     return minCount;
490e8d8bef9SDimitry Andric   }
491e8d8bef9SDimitry Andric   return 0;
4920b57cec5SDimitry Andric }
4930b57cec5SDimitry Andric 
494e8d8bef9SDimitry Andric // Get the total execution count of loops among blocks on the same line.
495e8d8bef9SDimitry Andric // Assuming a reducible flow graph, the count is the sum of back edge counts.
496e8d8bef9SDimitry Andric // Identifying loops is complex, so we simply find cycles and perform cycle
497e8d8bef9SDimitry Andric // cancelling iteratively.
498e8d8bef9SDimitry Andric uint64_t GCOVBlock::getCyclesCount(const BlockVector &blocks) {
499e8d8bef9SDimitry Andric   std::vector<std::pair<GCOVBlock *, size_t>> stack;
500e8d8bef9SDimitry Andric   uint64_t count = 0, d;
501e8d8bef9SDimitry Andric   for (;;) {
502e8d8bef9SDimitry Andric     // Make blocks on the line traversable and try finding a cycle.
503bdd1243dSDimitry Andric     for (const auto *b : blocks) {
504e8d8bef9SDimitry Andric       const_cast<GCOVBlock *>(b)->traversable = true;
505e8d8bef9SDimitry Andric       const_cast<GCOVBlock *>(b)->incoming = nullptr;
5060b57cec5SDimitry Andric     }
507e8d8bef9SDimitry Andric     d = 0;
508bdd1243dSDimitry Andric     for (const auto *block : blocks) {
509e8d8bef9SDimitry Andric       auto *b = const_cast<GCOVBlock *>(block);
510e8d8bef9SDimitry Andric       if (b->traversable && (d = augmentOneCycle(b, stack)) > 0)
511e8d8bef9SDimitry Andric         break;
5120b57cec5SDimitry Andric     }
513e8d8bef9SDimitry Andric     if (d == 0)
514e8d8bef9SDimitry Andric       break;
515e8d8bef9SDimitry Andric     count += d;
5160b57cec5SDimitry Andric   }
517e8d8bef9SDimitry Andric   // If there is no more loop, all traversable bits should have been cleared.
518e8d8bef9SDimitry Andric   // This property is needed by subsequent calls.
519bdd1243dSDimitry Andric   for (const auto *b : blocks) {
520e8d8bef9SDimitry Andric     assert(!b->traversable);
521e8d8bef9SDimitry Andric     (void)b;
5220b57cec5SDimitry Andric   }
523e8d8bef9SDimitry Andric   return count;
5240b57cec5SDimitry Andric }
5250b57cec5SDimitry Andric 
5260b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
5270b57cec5SDimitry Andric // FileInfo implementation.
5280b57cec5SDimitry Andric 
529e8d8bef9SDimitry Andric // Format dividend/divisor as a percentage. Return 1 if the result is greater
530e8d8bef9SDimitry Andric // than 0% and less than 1%.
531e8d8bef9SDimitry Andric static uint32_t formatPercentage(uint64_t dividend, uint64_t divisor) {
532e8d8bef9SDimitry Andric   if (!dividend || !divisor)
5330b57cec5SDimitry Andric     return 0;
534e8d8bef9SDimitry Andric   dividend *= 100;
535e8d8bef9SDimitry Andric   return dividend < divisor ? 1 : dividend / divisor;
5360b57cec5SDimitry Andric }
5370b57cec5SDimitry Andric 
5380b57cec5SDimitry Andric // This custom division function mimics gcov's branch ouputs:
5390b57cec5SDimitry Andric //   - Round to closest whole number
5400b57cec5SDimitry Andric //   - Only output 0% or 100% if it's exactly that value
5410b57cec5SDimitry Andric static uint32_t branchDiv(uint64_t Numerator, uint64_t Divisor) {
5420b57cec5SDimitry Andric   if (!Numerator)
5430b57cec5SDimitry Andric     return 0;
5440b57cec5SDimitry Andric   if (Numerator == Divisor)
5450b57cec5SDimitry Andric     return 100;
5460b57cec5SDimitry Andric 
5470b57cec5SDimitry Andric   uint8_t Res = (Numerator * 100 + Divisor / 2) / Divisor;
5480b57cec5SDimitry Andric   if (Res == 0)
5490b57cec5SDimitry Andric     return 1;
5500b57cec5SDimitry Andric   if (Res == 100)
5510b57cec5SDimitry Andric     return 99;
5520b57cec5SDimitry Andric   return Res;
5530b57cec5SDimitry Andric }
5540b57cec5SDimitry Andric 
5550b57cec5SDimitry Andric namespace {
5560b57cec5SDimitry Andric struct formatBranchInfo {
5570b57cec5SDimitry Andric   formatBranchInfo(const GCOV::Options &Options, uint64_t Count, uint64_t Total)
5580b57cec5SDimitry Andric       : Options(Options), Count(Count), Total(Total) {}
5590b57cec5SDimitry Andric 
5600b57cec5SDimitry Andric   void print(raw_ostream &OS) const {
5610b57cec5SDimitry Andric     if (!Total)
5620b57cec5SDimitry Andric       OS << "never executed";
5630b57cec5SDimitry Andric     else if (Options.BranchCount)
5640b57cec5SDimitry Andric       OS << "taken " << Count;
5650b57cec5SDimitry Andric     else
5660b57cec5SDimitry Andric       OS << "taken " << branchDiv(Count, Total) << "%";
5670b57cec5SDimitry Andric   }
5680b57cec5SDimitry Andric 
5690b57cec5SDimitry Andric   const GCOV::Options &Options;
5700b57cec5SDimitry Andric   uint64_t Count;
5710b57cec5SDimitry Andric   uint64_t Total;
5720b57cec5SDimitry Andric };
5730b57cec5SDimitry Andric 
5740b57cec5SDimitry Andric static raw_ostream &operator<<(raw_ostream &OS, const formatBranchInfo &FBI) {
5750b57cec5SDimitry Andric   FBI.print(OS);
5760b57cec5SDimitry Andric   return OS;
5770b57cec5SDimitry Andric }
5780b57cec5SDimitry Andric 
5790b57cec5SDimitry Andric class LineConsumer {
5800b57cec5SDimitry Andric   std::unique_ptr<MemoryBuffer> Buffer;
5810b57cec5SDimitry Andric   StringRef Remaining;
5820b57cec5SDimitry Andric 
5830b57cec5SDimitry Andric public:
5845ffd83dbSDimitry Andric   LineConsumer() = default;
5850b57cec5SDimitry Andric   LineConsumer(StringRef Filename) {
586e8d8bef9SDimitry Andric     // Open source files without requiring a NUL terminator. The concurrent
587e8d8bef9SDimitry Andric     // modification may nullify the NUL terminator condition.
5880b57cec5SDimitry Andric     ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
589fe6060f1SDimitry Andric         MemoryBuffer::getFileOrSTDIN(Filename, /*IsText=*/false,
590e8d8bef9SDimitry Andric                                      /*RequiresNullTerminator=*/false);
5910b57cec5SDimitry Andric     if (std::error_code EC = BufferOrErr.getError()) {
5920b57cec5SDimitry Andric       errs() << Filename << ": " << EC.message() << "\n";
5930b57cec5SDimitry Andric       Remaining = "";
5940b57cec5SDimitry Andric     } else {
5950b57cec5SDimitry Andric       Buffer = std::move(BufferOrErr.get());
5960b57cec5SDimitry Andric       Remaining = Buffer->getBuffer();
5970b57cec5SDimitry Andric     }
5980b57cec5SDimitry Andric   }
5990b57cec5SDimitry Andric   bool empty() { return Remaining.empty(); }
6000b57cec5SDimitry Andric   void printNext(raw_ostream &OS, uint32_t LineNum) {
6010b57cec5SDimitry Andric     StringRef Line;
6020b57cec5SDimitry Andric     if (empty())
6030b57cec5SDimitry Andric       Line = "/*EOF*/";
6040b57cec5SDimitry Andric     else
6050b57cec5SDimitry Andric       std::tie(Line, Remaining) = Remaining.split("\n");
6060b57cec5SDimitry Andric     OS << format("%5u:", LineNum) << Line << "\n";
6070b57cec5SDimitry Andric   }
6080b57cec5SDimitry Andric };
6090b57cec5SDimitry Andric } // end anonymous namespace
6100b57cec5SDimitry Andric 
6110b57cec5SDimitry Andric /// Convert a path to a gcov filename. If PreservePaths is true, this
6120b57cec5SDimitry Andric /// translates "/" to "#", ".." to "^", and drops ".", to match gcov.
6130b57cec5SDimitry Andric static std::string mangleCoveragePath(StringRef Filename, bool PreservePaths) {
6140b57cec5SDimitry Andric   if (!PreservePaths)
6150b57cec5SDimitry Andric     return sys::path::filename(Filename).str();
6160b57cec5SDimitry Andric 
6170b57cec5SDimitry Andric   // This behaviour is defined by gcov in terms of text replacements, so it's
6180b57cec5SDimitry Andric   // not likely to do anything useful on filesystems with different textual
6190b57cec5SDimitry Andric   // conventions.
6200b57cec5SDimitry Andric   llvm::SmallString<256> Result("");
6210b57cec5SDimitry Andric   StringRef::iterator I, S, E;
6220b57cec5SDimitry Andric   for (I = S = Filename.begin(), E = Filename.end(); I != E; ++I) {
6230b57cec5SDimitry Andric     if (*I != '/')
6240b57cec5SDimitry Andric       continue;
6250b57cec5SDimitry Andric 
6260b57cec5SDimitry Andric     if (I - S == 1 && *S == '.') {
6270b57cec5SDimitry Andric       // ".", the current directory, is skipped.
6280b57cec5SDimitry Andric     } else if (I - S == 2 && *S == '.' && *(S + 1) == '.') {
6290b57cec5SDimitry Andric       // "..", the parent directory, is replaced with "^".
6300b57cec5SDimitry Andric       Result.append("^#");
6310b57cec5SDimitry Andric     } else {
6320b57cec5SDimitry Andric       if (S < I)
6330b57cec5SDimitry Andric         // Leave other components intact,
6340b57cec5SDimitry Andric         Result.append(S, I);
6350b57cec5SDimitry Andric       // And separate with "#".
6360b57cec5SDimitry Andric       Result.push_back('#');
6370b57cec5SDimitry Andric     }
6380b57cec5SDimitry Andric     S = I + 1;
6390b57cec5SDimitry Andric   }
6400b57cec5SDimitry Andric 
6410b57cec5SDimitry Andric   if (S < I)
6420b57cec5SDimitry Andric     Result.append(S, I);
6435ffd83dbSDimitry Andric   return std::string(Result.str());
6440b57cec5SDimitry Andric }
6450b57cec5SDimitry Andric 
646e8d8bef9SDimitry Andric std::string Context::getCoveragePath(StringRef filename,
647e8d8bef9SDimitry Andric                                      StringRef mainFilename) const {
648e8d8bef9SDimitry Andric   if (options.NoOutput)
6490b57cec5SDimitry Andric     // This is probably a bug in gcov, but when -n is specified, paths aren't
6500b57cec5SDimitry Andric     // mangled at all, and the -l and -p options are ignored. Here, we do the
6510b57cec5SDimitry Andric     // same.
652e8d8bef9SDimitry Andric     return std::string(filename);
6530b57cec5SDimitry Andric 
6540b57cec5SDimitry Andric   std::string CoveragePath;
655e8d8bef9SDimitry Andric   if (options.LongFileNames && !filename.equals(mainFilename))
6560b57cec5SDimitry Andric     CoveragePath =
657e8d8bef9SDimitry Andric         mangleCoveragePath(mainFilename, options.PreservePaths) + "##";
658e8d8bef9SDimitry Andric   CoveragePath += mangleCoveragePath(filename, options.PreservePaths);
659e8d8bef9SDimitry Andric   if (options.HashFilenames) {
6600b57cec5SDimitry Andric     MD5 Hasher;
6610b57cec5SDimitry Andric     MD5::MD5Result Result;
662e8d8bef9SDimitry Andric     Hasher.update(filename.str());
6630b57cec5SDimitry Andric     Hasher.final(Result);
6645ffd83dbSDimitry Andric     CoveragePath += "##" + std::string(Result.digest());
6650b57cec5SDimitry Andric   }
6660b57cec5SDimitry Andric   CoveragePath += ".gcov";
6670b57cec5SDimitry Andric   return CoveragePath;
6680b57cec5SDimitry Andric }
6690b57cec5SDimitry Andric 
670e8d8bef9SDimitry Andric void Context::collectFunction(GCOVFunction &f, Summary &summary) {
671e8d8bef9SDimitry Andric   SourceInfo &si = sources[f.srcIdx];
672e8d8bef9SDimitry Andric   if (f.startLine >= si.startLineToFunctions.size())
673e8d8bef9SDimitry Andric     si.startLineToFunctions.resize(f.startLine + 1);
674e8d8bef9SDimitry Andric   si.startLineToFunctions[f.startLine].push_back(&f);
67581ad6265SDimitry Andric   SmallSet<uint32_t, 16> lines;
67681ad6265SDimitry Andric   SmallSet<uint32_t, 16> linesExec;
677e8d8bef9SDimitry Andric   for (const GCOVBlock &b : f.blocksRange()) {
678e8d8bef9SDimitry Andric     if (b.lines.empty())
6790b57cec5SDimitry Andric       continue;
680e8d8bef9SDimitry Andric     uint32_t maxLineNum = *std::max_element(b.lines.begin(), b.lines.end());
681e8d8bef9SDimitry Andric     if (maxLineNum >= si.lines.size())
682e8d8bef9SDimitry Andric       si.lines.resize(maxLineNum + 1);
683e8d8bef9SDimitry Andric     for (uint32_t lineNum : b.lines) {
684e8d8bef9SDimitry Andric       LineInfo &line = si.lines[lineNum];
68581ad6265SDimitry Andric       if (lines.insert(lineNum).second)
686e8d8bef9SDimitry Andric         ++summary.lines;
68781ad6265SDimitry Andric       if (b.count && linesExec.insert(lineNum).second)
688e8d8bef9SDimitry Andric         ++summary.linesExec;
689e8d8bef9SDimitry Andric       line.exists = true;
690e8d8bef9SDimitry Andric       line.count += b.count;
691e8d8bef9SDimitry Andric       line.blocks.push_back(&b);
692e8d8bef9SDimitry Andric     }
693e8d8bef9SDimitry Andric   }
694e8d8bef9SDimitry Andric }
695e8d8bef9SDimitry Andric 
696e8d8bef9SDimitry Andric void Context::collectSourceLine(SourceInfo &si, Summary *summary,
697e8d8bef9SDimitry Andric                                 LineInfo &line, size_t lineNum) const {
698e8d8bef9SDimitry Andric   uint64_t count = 0;
699e8d8bef9SDimitry Andric   for (const GCOVBlock *b : line.blocks) {
700e8d8bef9SDimitry Andric     if (b->number == 0) {
701e8d8bef9SDimitry Andric       // For nonstandard control flows, arcs into the exit block may be
702e8d8bef9SDimitry Andric       // duplicately counted (fork) or not be counted (abnormal exit), and thus
703e8d8bef9SDimitry Andric       // the (exit,entry) counter may be inaccurate. Count the entry block with
704e8d8bef9SDimitry Andric       // the outgoing arcs.
705e8d8bef9SDimitry Andric       for (const GCOVArc *arc : b->succ)
706e8d8bef9SDimitry Andric         count += arc->count;
707e8d8bef9SDimitry Andric     } else {
708e8d8bef9SDimitry Andric       // Add counts from predecessors that are not on the same line.
709e8d8bef9SDimitry Andric       for (const GCOVArc *arc : b->pred)
710e8d8bef9SDimitry Andric         if (!llvm::is_contained(line.blocks, &arc->src))
711e8d8bef9SDimitry Andric           count += arc->count;
712e8d8bef9SDimitry Andric     }
713e8d8bef9SDimitry Andric     for (GCOVArc *arc : b->succ)
714e8d8bef9SDimitry Andric       arc->cycleCount = arc->count;
715e8d8bef9SDimitry Andric   }
716e8d8bef9SDimitry Andric 
717e8d8bef9SDimitry Andric   count += GCOVBlock::getCyclesCount(line.blocks);
718e8d8bef9SDimitry Andric   line.count = count;
719e8d8bef9SDimitry Andric   if (line.exists) {
720e8d8bef9SDimitry Andric     ++summary->lines;
721e8d8bef9SDimitry Andric     if (line.count != 0)
722e8d8bef9SDimitry Andric       ++summary->linesExec;
723e8d8bef9SDimitry Andric   }
724e8d8bef9SDimitry Andric 
725e8d8bef9SDimitry Andric   if (options.BranchInfo)
726e8d8bef9SDimitry Andric     for (const GCOVBlock *b : line.blocks) {
727e8d8bef9SDimitry Andric       if (b->getLastLine() != lineNum)
728e8d8bef9SDimitry Andric         continue;
729e8d8bef9SDimitry Andric       int branches = 0, execBranches = 0, takenBranches = 0;
730e8d8bef9SDimitry Andric       for (const GCOVArc *arc : b->succ) {
731e8d8bef9SDimitry Andric         ++branches;
732e8d8bef9SDimitry Andric         if (count != 0)
733e8d8bef9SDimitry Andric           ++execBranches;
734e8d8bef9SDimitry Andric         if (arc->count != 0)
735e8d8bef9SDimitry Andric           ++takenBranches;
736e8d8bef9SDimitry Andric       }
737e8d8bef9SDimitry Andric       if (branches > 1) {
738e8d8bef9SDimitry Andric         summary->branches += branches;
739e8d8bef9SDimitry Andric         summary->branchesExec += execBranches;
740e8d8bef9SDimitry Andric         summary->branchesTaken += takenBranches;
741e8d8bef9SDimitry Andric       }
742e8d8bef9SDimitry Andric     }
743e8d8bef9SDimitry Andric }
744e8d8bef9SDimitry Andric 
745e8d8bef9SDimitry Andric void Context::collectSource(SourceInfo &si, Summary &summary) const {
746e8d8bef9SDimitry Andric   size_t lineNum = 0;
747e8d8bef9SDimitry Andric   for (LineInfo &line : si.lines) {
748e8d8bef9SDimitry Andric     collectSourceLine(si, &summary, line, lineNum);
749e8d8bef9SDimitry Andric     ++lineNum;
750e8d8bef9SDimitry Andric   }
751e8d8bef9SDimitry Andric }
752e8d8bef9SDimitry Andric 
753e8d8bef9SDimitry Andric void Context::annotateSource(SourceInfo &si, const GCOVFile &file,
754e8d8bef9SDimitry Andric                              StringRef gcno, StringRef gcda,
755e8d8bef9SDimitry Andric                              raw_ostream &os) const {
756e8d8bef9SDimitry Andric   auto source =
757e8d8bef9SDimitry Andric       options.Intermediate ? LineConsumer() : LineConsumer(si.filename);
758e8d8bef9SDimitry Andric 
759e8d8bef9SDimitry Andric   os << "        -:    0:Source:" << si.displayName << '\n';
760e8d8bef9SDimitry Andric   os << "        -:    0:Graph:" << gcno << '\n';
761e8d8bef9SDimitry Andric   os << "        -:    0:Data:" << gcda << '\n';
762fe6060f1SDimitry Andric   os << "        -:    0:Runs:" << file.runCount << '\n';
763fe6060f1SDimitry Andric   if (file.version < GCOV::V900)
764fe6060f1SDimitry Andric     os << "        -:    0:Programs:" << file.programCount << '\n';
765e8d8bef9SDimitry Andric 
766e8d8bef9SDimitry Andric   for (size_t lineNum = 1; !source.empty(); ++lineNum) {
767e8d8bef9SDimitry Andric     if (lineNum >= si.lines.size()) {
768e8d8bef9SDimitry Andric       os << "        -:";
769e8d8bef9SDimitry Andric       source.printNext(os, lineNum);
770e8d8bef9SDimitry Andric       continue;
771e8d8bef9SDimitry Andric     }
772e8d8bef9SDimitry Andric 
773e8d8bef9SDimitry Andric     const LineInfo &line = si.lines[lineNum];
774e8d8bef9SDimitry Andric     if (options.BranchInfo && lineNum < si.startLineToFunctions.size())
775e8d8bef9SDimitry Andric       for (const auto *f : si.startLineToFunctions[lineNum])
776e8d8bef9SDimitry Andric         printFunctionDetails(*f, os);
777e8d8bef9SDimitry Andric     if (!line.exists)
778e8d8bef9SDimitry Andric       os << "        -:";
779e8d8bef9SDimitry Andric     else if (line.count == 0)
780e8d8bef9SDimitry Andric       os << "    #####:";
781e8d8bef9SDimitry Andric     else
782e8d8bef9SDimitry Andric       os << format("%9" PRIu64 ":", line.count);
783e8d8bef9SDimitry Andric     source.printNext(os, lineNum);
784e8d8bef9SDimitry Andric 
785e8d8bef9SDimitry Andric     uint32_t blockIdx = 0, edgeIdx = 0;
786e8d8bef9SDimitry Andric     for (const GCOVBlock *b : line.blocks) {
787e8d8bef9SDimitry Andric       if (b->getLastLine() != lineNum)
788e8d8bef9SDimitry Andric         continue;
789e8d8bef9SDimitry Andric       if (options.AllBlocks) {
790e8d8bef9SDimitry Andric         if (b->getCount() == 0)
791e8d8bef9SDimitry Andric           os << "    $$$$$:";
792e8d8bef9SDimitry Andric         else
793e8d8bef9SDimitry Andric           os << format("%9" PRIu64 ":", b->count);
794e8d8bef9SDimitry Andric         os << format("%5u-block %2u\n", lineNum, blockIdx++);
795e8d8bef9SDimitry Andric       }
796e8d8bef9SDimitry Andric       if (options.BranchInfo) {
797e8d8bef9SDimitry Andric         size_t NumEdges = b->succ.size();
7980b57cec5SDimitry Andric         if (NumEdges > 1)
799e8d8bef9SDimitry Andric           printBranchInfo(*b, edgeIdx, os);
800e8d8bef9SDimitry Andric         else if (options.UncondBranch && NumEdges == 1) {
801e8d8bef9SDimitry Andric           uint64_t count = b->succ[0]->count;
802e8d8bef9SDimitry Andric           os << format("unconditional %2u ", edgeIdx++)
803e8d8bef9SDimitry Andric              << formatBranchInfo(options, count, count) << '\n';
8040b57cec5SDimitry Andric         }
8050b57cec5SDimitry Andric       }
8060b57cec5SDimitry Andric     }
8070b57cec5SDimitry Andric   }
8080b57cec5SDimitry Andric }
8090b57cec5SDimitry Andric 
810e8d8bef9SDimitry Andric void Context::printSourceToIntermediate(const SourceInfo &si,
811e8d8bef9SDimitry Andric                                         raw_ostream &os) const {
812e8d8bef9SDimitry Andric   os << "file:" << si.filename << '\n';
813e8d8bef9SDimitry Andric   for (const auto &fs : si.startLineToFunctions)
814e8d8bef9SDimitry Andric     for (const GCOVFunction *f : fs)
8155ffd83dbSDimitry Andric       os << "function:" << f->startLine << ',' << f->getEntryCount() << ','
816e8d8bef9SDimitry Andric          << f->getName(options.Demangle) << '\n';
817e8d8bef9SDimitry Andric   for (size_t lineNum = 1, size = si.lines.size(); lineNum < size; ++lineNum) {
818e8d8bef9SDimitry Andric     const LineInfo &line = si.lines[lineNum];
819e8d8bef9SDimitry Andric     if (line.blocks.empty())
8205ffd83dbSDimitry Andric       continue;
8215ffd83dbSDimitry Andric     // GCC 8 (r254259) added third third field for Ada:
8225ffd83dbSDimitry Andric     // lcount:<line>,<count>,<has_unexecuted_blocks>
8235ffd83dbSDimitry Andric     // We don't need the third field.
824e8d8bef9SDimitry Andric     os << "lcount:" << lineNum << ',' << line.count << '\n';
8255ffd83dbSDimitry Andric 
826e8d8bef9SDimitry Andric     if (!options.BranchInfo)
8275ffd83dbSDimitry Andric       continue;
828e8d8bef9SDimitry Andric     for (const GCOVBlock *b : line.blocks) {
829e8d8bef9SDimitry Andric       if (b->succ.size() < 2 || b->getLastLine() != lineNum)
8305ffd83dbSDimitry Andric         continue;
831e8d8bef9SDimitry Andric       for (const GCOVArc *arc : b->succ) {
832e8d8bef9SDimitry Andric         const char *type =
833e8d8bef9SDimitry Andric             b->getCount() ? arc->count ? "taken" : "nottaken" : "notexec";
834e8d8bef9SDimitry Andric         os << "branch:" << lineNum << ',' << type << '\n';
8355ffd83dbSDimitry Andric       }
8365ffd83dbSDimitry Andric     }
8375ffd83dbSDimitry Andric   }
8385ffd83dbSDimitry Andric }
8395ffd83dbSDimitry Andric 
840e8d8bef9SDimitry Andric void Context::print(StringRef filename, StringRef gcno, StringRef gcda,
841e8d8bef9SDimitry Andric                     GCOVFile &file) {
842e8d8bef9SDimitry Andric   for (StringRef filename : file.filenames) {
843e8d8bef9SDimitry Andric     sources.emplace_back(filename);
844e8d8bef9SDimitry Andric     SourceInfo &si = sources.back();
845e8d8bef9SDimitry Andric     si.displayName = si.filename;
846e8d8bef9SDimitry Andric     if (!options.SourcePrefix.empty() &&
847e8d8bef9SDimitry Andric         sys::path::replace_path_prefix(si.displayName, options.SourcePrefix,
848e8d8bef9SDimitry Andric                                        "") &&
849e8d8bef9SDimitry Andric         !si.displayName.empty()) {
850e8d8bef9SDimitry Andric       // TODO replace_path_prefix may strip the prefix even if the remaining
851e8d8bef9SDimitry Andric       // part does not start with a separator.
852e8d8bef9SDimitry Andric       if (sys::path::is_separator(si.displayName[0]))
853e8d8bef9SDimitry Andric         si.displayName.erase(si.displayName.begin());
8540b57cec5SDimitry Andric       else
855e8d8bef9SDimitry Andric         si.displayName = si.filename;
856e8d8bef9SDimitry Andric     }
857e8d8bef9SDimitry Andric     if (options.RelativeOnly && sys::path::is_absolute(si.displayName))
858e8d8bef9SDimitry Andric       si.ignored = true;
859e8d8bef9SDimitry Andric   }
860e8d8bef9SDimitry Andric 
861e8d8bef9SDimitry Andric   raw_ostream &os = llvm::outs();
862e8d8bef9SDimitry Andric   for (GCOVFunction &f : make_pointee_range(file.functions)) {
863e8d8bef9SDimitry Andric     Summary summary(f.getName(options.Demangle));
864e8d8bef9SDimitry Andric     collectFunction(f, summary);
865e8d8bef9SDimitry Andric     if (options.FuncCoverage && !options.UseStdout) {
866e8d8bef9SDimitry Andric       os << "Function '" << summary.Name << "'\n";
867e8d8bef9SDimitry Andric       printSummary(summary, os);
868e8d8bef9SDimitry Andric       os << '\n';
869e8d8bef9SDimitry Andric     }
870e8d8bef9SDimitry Andric   }
871e8d8bef9SDimitry Andric 
872e8d8bef9SDimitry Andric   for (SourceInfo &si : sources) {
873e8d8bef9SDimitry Andric     if (si.ignored)
874e8d8bef9SDimitry Andric       continue;
875e8d8bef9SDimitry Andric     Summary summary(si.displayName);
876e8d8bef9SDimitry Andric     collectSource(si, summary);
877e8d8bef9SDimitry Andric 
878e8d8bef9SDimitry Andric     // Print file summary unless -t is specified.
879e8d8bef9SDimitry Andric     std::string gcovName = getCoveragePath(si.filename, filename);
880e8d8bef9SDimitry Andric     if (!options.UseStdout) {
881e8d8bef9SDimitry Andric       os << "File '" << summary.Name << "'\n";
882e8d8bef9SDimitry Andric       printSummary(summary, os);
883e8d8bef9SDimitry Andric       if (!options.NoOutput && !options.Intermediate)
884e8d8bef9SDimitry Andric         os << "Creating '" << gcovName << "'\n";
885e8d8bef9SDimitry Andric       os << '\n';
886e8d8bef9SDimitry Andric     }
887e8d8bef9SDimitry Andric 
888e8d8bef9SDimitry Andric     if (options.NoOutput || options.Intermediate)
889e8d8bef9SDimitry Andric       continue;
890bdd1243dSDimitry Andric     std::optional<raw_fd_ostream> os;
891e8d8bef9SDimitry Andric     if (!options.UseStdout) {
892e8d8bef9SDimitry Andric       std::error_code ec;
893fe6060f1SDimitry Andric       os.emplace(gcovName, ec, sys::fs::OF_TextWithCRLF);
894e8d8bef9SDimitry Andric       if (ec) {
895e8d8bef9SDimitry Andric         errs() << ec.message() << '\n';
896e8d8bef9SDimitry Andric         continue;
897e8d8bef9SDimitry Andric       }
898e8d8bef9SDimitry Andric     }
899e8d8bef9SDimitry Andric     annotateSource(si, file, gcno, gcda,
900e8d8bef9SDimitry Andric                    options.UseStdout ? llvm::outs() : *os);
901e8d8bef9SDimitry Andric   }
902e8d8bef9SDimitry Andric 
903e8d8bef9SDimitry Andric   if (options.Intermediate && !options.NoOutput) {
904e8d8bef9SDimitry Andric     // gcov 7.* unexpectedly create multiple .gcov files, which was fixed in 8.0
905e8d8bef9SDimitry Andric     // (PR GCC/82702). We create just one file.
906e8d8bef9SDimitry Andric     std::string outputPath(sys::path::filename(filename));
907e8d8bef9SDimitry Andric     std::error_code ec;
908fe6060f1SDimitry Andric     raw_fd_ostream os(outputPath + ".gcov", ec, sys::fs::OF_TextWithCRLF);
909e8d8bef9SDimitry Andric     if (ec) {
910e8d8bef9SDimitry Andric       errs() << ec.message() << '\n';
911e8d8bef9SDimitry Andric       return;
912e8d8bef9SDimitry Andric     }
913e8d8bef9SDimitry Andric 
914e8d8bef9SDimitry Andric     for (const SourceInfo &si : sources)
915e8d8bef9SDimitry Andric       printSourceToIntermediate(si, os);
916e8d8bef9SDimitry Andric   }
917e8d8bef9SDimitry Andric }
918e8d8bef9SDimitry Andric 
919e8d8bef9SDimitry Andric void Context::printFunctionDetails(const GCOVFunction &f,
920e8d8bef9SDimitry Andric                                    raw_ostream &os) const {
921e8d8bef9SDimitry Andric   const uint64_t entryCount = f.getEntryCount();
922e8d8bef9SDimitry Andric   uint32_t blocksExec = 0;
923e8d8bef9SDimitry Andric   const GCOVBlock &exitBlock = f.getExitBlock();
924e8d8bef9SDimitry Andric   uint64_t exitCount = 0;
925e8d8bef9SDimitry Andric   for (const GCOVArc *arc : exitBlock.pred)
926e8d8bef9SDimitry Andric     exitCount += arc->count;
927e8d8bef9SDimitry Andric   for (const GCOVBlock &b : f.blocksRange())
928e8d8bef9SDimitry Andric     if (b.number != 0 && &b != &exitBlock && b.getCount())
929e8d8bef9SDimitry Andric       ++blocksExec;
930e8d8bef9SDimitry Andric 
931e8d8bef9SDimitry Andric   os << "function " << f.getName(options.Demangle) << " called " << entryCount
932e8d8bef9SDimitry Andric      << " returned " << formatPercentage(exitCount, entryCount)
933e8d8bef9SDimitry Andric      << "% blocks executed "
934e8d8bef9SDimitry Andric      << formatPercentage(blocksExec, f.blocks.size() - 2) << "%\n";
9350b57cec5SDimitry Andric }
9360b57cec5SDimitry Andric 
9370b57cec5SDimitry Andric /// printBranchInfo - Print conditional branch probabilities.
938e8d8bef9SDimitry Andric void Context::printBranchInfo(const GCOVBlock &Block, uint32_t &edgeIdx,
939e8d8bef9SDimitry Andric                               raw_ostream &os) const {
940e8d8bef9SDimitry Andric   uint64_t total = 0;
941e8d8bef9SDimitry Andric   for (const GCOVArc *arc : Block.dsts())
942e8d8bef9SDimitry Andric     total += arc->count;
943e8d8bef9SDimitry Andric   for (const GCOVArc *arc : Block.dsts())
944e8d8bef9SDimitry Andric     os << format("branch %2u ", edgeIdx++)
945e8d8bef9SDimitry Andric        << formatBranchInfo(options, arc->count, total) << '\n';
9460b57cec5SDimitry Andric }
9470b57cec5SDimitry Andric 
948e8d8bef9SDimitry Andric void Context::printSummary(const Summary &summary, raw_ostream &os) const {
949e8d8bef9SDimitry Andric   os << format("Lines executed:%.2f%% of %" PRIu64 "\n",
950e8d8bef9SDimitry Andric                double(summary.linesExec) * 100 / summary.lines, summary.lines);
951e8d8bef9SDimitry Andric   if (options.BranchInfo) {
952e8d8bef9SDimitry Andric     if (summary.branches == 0) {
953e8d8bef9SDimitry Andric       os << "No branches\n";
9540b57cec5SDimitry Andric     } else {
955e8d8bef9SDimitry Andric       os << format("Branches executed:%.2f%% of %" PRIu64 "\n",
956e8d8bef9SDimitry Andric                    double(summary.branchesExec) * 100 / summary.branches,
957e8d8bef9SDimitry Andric                    summary.branches);
958e8d8bef9SDimitry Andric       os << format("Taken at least once:%.2f%% of %" PRIu64 "\n",
959e8d8bef9SDimitry Andric                    double(summary.branchesTaken) * 100 / summary.branches,
960e8d8bef9SDimitry Andric                    summary.branches);
9610b57cec5SDimitry Andric     }
962e8d8bef9SDimitry Andric     os << "No calls\n";
9630b57cec5SDimitry Andric   }
9640b57cec5SDimitry Andric }
9650b57cec5SDimitry Andric 
966e8d8bef9SDimitry Andric void llvm::gcovOneInput(const GCOV::Options &options, StringRef filename,
967e8d8bef9SDimitry Andric                         StringRef gcno, StringRef gcda, GCOVFile &file) {
968e8d8bef9SDimitry Andric   Context fi(options);
969e8d8bef9SDimitry Andric   fi.print(filename, gcno, gcda, file);
9700b57cec5SDimitry Andric }
971