diff --git a/include/llvm/Support/GCOV.h b/include/llvm/Support/GCOV.h index a0468bd8152..eb536f50dc3 100644 --- a/include/llvm/Support/GCOV.h +++ b/include/llvm/Support/GCOV.h @@ -350,6 +350,19 @@ class FileInfo { BlockLines Blocks; FunctionLines Functions; }; + + struct GCOVCoverage { + GCOVCoverage() : + LogicalLines(0), LinesExec(0), Branches(0), BranchesExec(0), + BranchesTaken(0) {} + + uint32_t LogicalLines; + uint32_t LinesExec; + + uint32_t Branches; + uint32_t BranchesExec; + uint32_t BranchesTaken; + }; public: FileInfo(const GCOVOptions &Options) : Options(Options), LineInfo(), RunCount(0), ProgramCount(0) {} @@ -370,9 +383,10 @@ private: void printBlockInfo(raw_fd_ostream &OS, const GCOVBlock &Block, uint32_t LineIndex, uint32_t &BlockNo) const; void printBranchInfo(raw_fd_ostream &OS, const GCOVBlock &Block, - uint32_t &EdgeNo) const; + GCOVCoverage &Coverage, uint32_t &EdgeNo) const; void printUncondBranchInfo(raw_fd_ostream &OS, uint32_t &EdgeNo, uint64_t Count) const; + void printFileCoverage(StringRef Filename, GCOVCoverage &Coverage) const; const GCOVOptions &Options; StringMap LineInfo; diff --git a/lib/IR/GCOV.cpp b/lib/IR/GCOV.cpp index 62cbc5ef03e..b33eee6692b 100644 --- a/lib/IR/GCOV.cpp +++ b/lib/IR/GCOV.cpp @@ -454,6 +454,7 @@ void FileInfo::print(StringRef GCNOFile, StringRef GCDAFile) const { OS << " -: 0:Programs:" << ProgramCount << "\n"; const LineData &Line = I->second; + GCOVCoverage Coverage; for (uint32_t LineIndex = 0; !AllLines.empty(); ++LineIndex) { if (Options.BranchInfo) { FunctionLines::const_iterator FuncsIt = Line.Functions.find(LineIndex); @@ -485,10 +486,14 @@ void FileInfo::print(StringRef GCNOFile, StringRef GCDAFile) const { LineCount += Block->getCount(); } } + if (LineCount == 0) OS << " #####:"; - else + else { OS << format("%9" PRIu64 ":", LineCount); + ++Coverage.LinesExec; + } + ++Coverage.LogicalLines; std::pair P = AllLines.split('\n'); OS << format("%5u:", LineIndex+1) << P.first << "\n"; @@ -508,13 +513,16 @@ void FileInfo::print(StringRef GCNOFile, StringRef GCDAFile) const { if (Options.BranchInfo) { size_t NumEdges = Block->getNumDstEdges(); if (NumEdges > 1) - printBranchInfo(OS, *Block, EdgeNo); + printBranchInfo(OS, *Block, Coverage, EdgeNo); else if (Options.UncondBranch && NumEdges == 1) printUncondBranchInfo(OS, EdgeNo, (*Block->dst_begin())->Count); } } } } + + // FIXME: There is no way to detect calls given current instrumentation. + printFileCoverage(Filename, Coverage); } } @@ -552,7 +560,7 @@ void FileInfo::printBlockInfo(raw_fd_ostream &OS, const GCOVBlock &Block, /// printBranchInfo - Print conditional branch probabilities. void FileInfo::printBranchInfo(raw_fd_ostream &OS, const GCOVBlock &Block, - uint32_t &EdgeNo) const { + GCOVCoverage &Coverage, uint32_t &EdgeNo) const { SmallVector BranchCounts; uint64_t TotalCounts = 0; for (GCOVBlock::EdgeIterator I = Block.dst_begin(), E = Block.dst_end(); @@ -560,6 +568,9 @@ void FileInfo::printBranchInfo(raw_fd_ostream &OS, const GCOVBlock &Block, const GCOVEdge *Edge = *I; BranchCounts.push_back(Edge->Count); TotalCounts += Edge->Count; + if (Block.getCount()) ++Coverage.BranchesExec; + if (Edge->Count) ++Coverage.BranchesTaken; + ++Coverage.Branches; } for (SmallVectorImpl::const_iterator I = BranchCounts.begin(), @@ -575,3 +586,27 @@ void FileInfo::printUncondBranchInfo(raw_fd_ostream &OS, uint32_t &EdgeNo, OS << format("unconditional %2u ", EdgeNo++) << formatBranchInfo(Options, Count, Count) << "\n"; } + +/// printFileCoverage - Print per-file coverage info. +void FileInfo::printFileCoverage(StringRef Filename, + GCOVCoverage &Coverage) const { + outs() << "File '" << Filename << "'\n"; + outs() << format("Lines executed:%.2lf%% of %u\n", + double(Coverage.LinesExec)*100/Coverage.LogicalLines, + Coverage.LogicalLines); + if (Options.BranchInfo) { + if (Coverage.Branches) { + outs() << format("Branches executed:%.2lf%% of %u\n", + double(Coverage.BranchesExec)*100/Coverage.Branches, + Coverage.Branches); + outs() << format("Taken at least once:%.2lf%% of %u\n", + double(Coverage.BranchesTaken)*100/Coverage.Branches, + Coverage.Branches); + } else { + outs() << "No branches\n"; + } + outs() << "No calls\n"; // to be consistent with gcov + } + outs() << Filename << ":creating '" << Filename << ".gcov'\n"; + outs() << "\n"; +} diff --git a/test/tools/llvm-cov/Inputs/test_-b.output b/test/tools/llvm-cov/Inputs/test_-b.output new file mode 100644 index 00000000000..4003ce8e692 --- /dev/null +++ b/test/tools/llvm-cov/Inputs/test_-b.output @@ -0,0 +1,13 @@ +File 'test.cpp' +Lines executed:84.21% of 38 +Branches executed:100.00% of 15 +Taken at least once:86.67% of 15 +No calls +test.cpp:creating 'test.cpp.gcov' + +File './test.h' +Lines executed:100.00% of 1 +No branches +No calls +./test.h:creating './test.h.gcov' + diff --git a/test/tools/llvm-cov/Inputs/test_no_options.output b/test/tools/llvm-cov/Inputs/test_no_options.output new file mode 100644 index 00000000000..93ea726720a --- /dev/null +++ b/test/tools/llvm-cov/Inputs/test_no_options.output @@ -0,0 +1,8 @@ +File 'test.cpp' +Lines executed:84.21% of 38 +test.cpp:creating 'test.cpp.gcov' + +File './test.h' +Lines executed:100.00% of 1 +./test.h:creating './test.h.gcov' + diff --git a/test/tools/llvm-cov/llvm-cov.test b/test/tools/llvm-cov/llvm-cov.test index 02b8a3db9a5..da393071689 100644 --- a/test/tools/llvm-cov/llvm-cov.test +++ b/test/tools/llvm-cov/llvm-cov.test @@ -5,7 +5,7 @@ RUN: mkdir %t RUN: cd %t RUN: cp %p/Inputs/test* . -RUN: llvm-cov -gcno=test.gcno -gcda=test.gcda +RUN: llvm-cov -gcno=test.gcno -gcda=test.gcda | diff test_no_options.output - RUN: diff -aub test_no_options.cpp.gcov test.cpp.gcov RUN: diff -aub test_no_options.h.gcov test.h.gcov @@ -13,7 +13,7 @@ RUN: llvm-cov -gcno=test.gcno -gcda=test.gcda -a RUN: diff -aub test_-a.cpp.gcov test.cpp.gcov RUN: diff -aub test_-a.h.gcov test.h.gcov -RUN: llvm-cov -gcno=test.gcno -gcda=test.gcda -a -b +RUN: llvm-cov -gcno=test.gcno -gcda=test.gcda -a -b | diff test_-b.output - RUN: diff -aub test_-a_-b.cpp.gcov test.cpp.gcov RUN: diff -aub test_-a_-b.h.gcov test.h.gcov