17#include "llvm/Config/llvm-config.h"
27#include <system_error>
66 std::vector<std::vector<const GCOVFunction *>> startLineToFunctions;
67 std::vector<LineInfo> lines;
83 void printSummary(
const Summary &summary,
raw_ostream &os)
const;
86 void collectSourceLine(SourceInfo &si, Summary *summary, LineInfo &line,
87 size_t lineNum)
const;
88 void collectSource(SourceInfo &si, Summary &summary)
const;
91 void printSourceToIntermediate(
const SourceInfo &si,
raw_ostream &os)
const;
94 std::vector<SourceInfo> sources;
116 while ((tag = buf.
getWord())) {
121 functions.push_back(std::make_unique<GCOVFunction>(*
this));
143 fn->
srcIdx = addNormalizedPathToMap(filename);
147 for (
uint32_t i = 0; i != length; ++i) {
149 fn->
blocks.push_back(std::make_unique<GCOVBlock>(i));
154 fn->
blocks.push_back(std::make_unique<GCOVBlock>(i));
158 if (srcNo >= fn->
blocks.size()) {
159 errs() <<
"unexpected block number: " << srcNo <<
" (in "
160 << fn->
blocks.size() <<
")\n";
169 auto arc = std::make_unique<GCOVArc>(*src, *dst, flags);
173 fn->
treeArcs.push_back(std::move(arc));
175 fn->
arcs.push_back(std::move(arc));
179 if (srcNo >= fn->
blocks.size()) {
180 errs() <<
"unexpected block number: " << srcNo <<
" (in "
181 << fn->
blocks.size() <<
")\n";
192 if (filename.
empty())
194 Block.addFile(addNormalizedPathToMap(filename));
218 errs() <<
"GCOV versions do not match.\n";
223 if (!buf.
readInt(GCDAChecksum))
227 <<
" != " << GCDAChecksum <<
"\n";
233 while ((tag = buf.
getWord())) {
248 if (length < 2 || !buf.
readInt(ident))
251 uint32_t linenoChecksum, cfgChecksum = 0;
260 <<
format(
": checksum mismatch, (%u, %u) != (%u, %u)\n",
270 if (length != expected) {
273 ": GCOV_TAG_COUNTER_ARCS mismatch, got %u, expected %u\n",
277 for (std::unique_ptr<GCOVArc> &arc : fn->
arcs) {
280 arc->src.count += arc->count;
283 if (fn->
blocks.size() >= 2) {
288 sink.addDstEdge(arc.get());
290 fn->
treeArcs.push_back(std::move(arc));
294 for (
size_t i = fn->
treeArcs.size() - 1; i; --i)
312#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
317unsigned GCOVFile::addNormalizedPathToMap(
StringRef filename) {
327 return r.first->second;
358 return blocks.front()->getCount();
384 Elem &u = stack.
back();
387 if (u.i == 0 && !
visited.insert(&u.v).second) {
393 if (u.i < u.v.pred.size()) {
399 u.excess += e->count;
401 }
else if (u.i < u.v.pred.size() + u.v.succ.size()) {
402 GCOVArc *e = u.v.succ[u.i++ - u.v.pred.size()];
407 u.excess -= e->count;
411 if (
static_cast<int64_t
>(excess) < 0)
414 u.pred->count = excess;
415 bool inDst = u.inDst;
419 stack.
back().excess += inDst ? -excess : excess;
431#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
443 OS <<
"Block : " <<
number <<
" Counter : " <<
count <<
"\n";
445 OS <<
"\tSource Edges : ";
447 OS <<
Edge->src.number <<
" (" <<
Edge->count <<
"), ";
451 OS <<
"\tDestination Edges : ";
455 OS <<
Edge->dst.number <<
" (" <<
Edge->count <<
"), ";
461 OS <<
"\tFile: " << loc.srcIdx <<
": ";
469#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
476 std::vector<std::pair<GCOVBlock *, size_t>> &stack) {
480 stack.emplace_back(src, 0);
483 std::tie(u, i) = stack.back();
484 if (i == u->succ.size()) {
485 u->traversable =
false;
491 ++stack.back().second;
496 if (
succ->cycleCount == 0 || !
succ->dst.traversable || &
succ->dst == u)
498 if (
succ->dst.incoming ==
nullptr) {
500 stack.emplace_back(&
succ->dst, 0);
505 minCount = std::min(minCount, v->incoming->cycleCount);
506 v = &v->incoming->src;
510 succ->cycleCount -= minCount;
512 v->incoming->cycleCount -= minCount;
513 v = &v->incoming->src;
527 std::vector<std::pair<GCOVBlock *, size_t>> stack;
531 for (
const auto *b :
blocks) {
547 for (
const auto *b :
blocks) {
560 if (!dividend || !divisor)
563 return dividend < divisor ? 1 : dividend / divisor;
572 if (Numerator == Divisor)
575 uint8_t Res = (Numerator * 100 + Divisor / 2) / Divisor;
584struct formatBranchInfo {
590 OS <<
"never executed";
592 OS <<
"taken " << Count;
608 std::unique_ptr<MemoryBuffer> Buffer;
612 LineConsumer() =
default;
619 if (std::error_code EC = BufferOrErr.
getError()) {
623 Buffer = std::move(BufferOrErr.
get());
624 Remaining = Buffer->getBuffer();
627 bool empty() {
return Remaining.
empty(); }
633 std::tie(Line, Remaining) = Remaining.
split(
"\n");
650 for (
I = S = Filename.begin(), E = Filename.end();
I != E; ++
I) {
654 if (
I - S == 1 && *S ==
'.') {
656 }
else if (
I - S == 2 && *S ==
'.' && *(S + 1) ==
'.') {
664 Result.push_back(
'#');
671 return std::string(Result);
674std::string Context::getCoveragePath(
StringRef filename,
680 return std::string(filename);
682 std::string CoveragePath;
683 if (
options.LongFileNames && filename != mainFilename)
691 Hasher.
final(Result);
692 CoveragePath +=
"##" + std::string(
Result.digest());
694 CoveragePath +=
".gcov";
698void Context::collectFunction(
GCOVFunction &f, Summary &summary) {
699 SourceInfo &si = sources[
f.srcIdx];
700 if (
f.startLine >= si.startLineToFunctions.size())
701 si.startLineToFunctions.resize(
f.startLine + 1);
702 si.startLineToFunctions[
f.startLine].push_back(&f);
706 if (
b.locations.empty())
709 SourceInfo &locSource = sources[loc.
srcIdx];
711 if (maxLineNum >= locSource.lines.size())
712 locSource.lines.resize(maxLineNum + 1);
714 LineInfo &line = locSource.lines[lineNum];
716 line.count +=
b.count;
717 line.blocks.push_back(&b);
719 if (lines.
insert(lineNum).second)
721 if (
b.count && linesExec.
insert(lineNum).second)
729void Context::collectSourceLine(SourceInfo &si, Summary *summary,
730 LineInfo &line,
size_t lineNum)
const {
733 if (
b->number == 0) {
755 ++summary->linesExec;
760 if (
b->getLastLine() != lineNum)
762 int branches = 0, execBranches = 0, takenBranches = 0;
763 for (
const GCOVArc *arc :
b->succ) {
772 summary->branchesExec += execBranches;
773 summary->branchesTaken += takenBranches;
778void Context::collectSource(SourceInfo &si, Summary &summary)
const {
780 for (LineInfo &line : si.lines) {
781 collectSourceLine(si, &summary, line, lineNum);
786void Context::annotateSource(SourceInfo &si,
const GCOVFile &
file,
792 os <<
" -: 0:Source:" << si.displayName <<
'\n';
793 os <<
" -: 0:Graph:" << gcno <<
'\n';
794 os <<
" -: 0:Data:" << gcda <<
'\n';
795 os <<
" -: 0:Runs:" <<
file.runCount <<
'\n';
797 os <<
" -: 0:Programs:" <<
file.programCount <<
'\n';
799 for (
size_t lineNum = 1; !source.empty(); ++lineNum) {
800 if (lineNum >= si.lines.size()) {
802 source.printNext(os, lineNum);
806 const LineInfo &line = si.lines[lineNum];
807 if (
options.BranchInfo && lineNum < si.startLineToFunctions.size())
808 for (
const auto *f : si.startLineToFunctions[lineNum])
809 printFunctionDetails(*f, os);
812 else if (line.count == 0)
815 os <<
format(
"%9" PRIu64
":", line.count);
816 source.printNext(os, lineNum);
820 if (
b->getLastLine() != lineNum)
823 if (
b->getCount() == 0)
826 os <<
format(
"%9" PRIu64
":",
b->count);
827 os <<
format(
"%5u-block %2u\n", lineNum, blockIdx++);
830 size_t NumEdges =
b->succ.size();
832 printBranchInfo(*b, edgeIdx, os);
833 else if (
options.UncondBranch && NumEdges == 1) {
835 os <<
format(
"unconditional %2u ", edgeIdx++)
836 << formatBranchInfo(options,
count,
count) <<
'\n';
843void Context::printSourceToIntermediate(
const SourceInfo &si,
845 os <<
"file:" << si.filename <<
'\n';
846 for (
const auto &fs : si.startLineToFunctions)
848 os <<
"function:" <<
f->startLine <<
',' <<
f->getEntryCount() <<
','
849 <<
f->getName(
options.Demangle) <<
'\n';
850 for (
size_t lineNum = 1, size = si.lines.size(); lineNum < size; ++lineNum) {
851 const LineInfo &line = si.lines[lineNum];
852 if (line.blocks.empty())
857 os <<
"lcount:" << lineNum <<
',' << line.count <<
'\n';
862 if (
b->succ.size() < 2 ||
b->getLastLine() != lineNum)
864 for (
const GCOVArc *arc :
b->succ) {
866 b->getCount() ? arc->
count ?
"taken" :
"nottaken" :
"notexec";
867 os <<
"branch:" << lineNum <<
',' << type <<
'\n';
876 sources.emplace_back(filename);
877 SourceInfo &si = sources.back();
878 si.displayName = si.filename;
879 if (!
options.SourcePrefix.empty() &&
882 !si.displayName.empty()) {
886 si.displayName.erase(si.displayName.begin());
888 si.displayName = si.filename;
897 collectFunction(f, summary);
899 os <<
"Function '" << summary.Name <<
"'\n";
900 printSummary(summary, os);
905 for (SourceInfo &si : sources) {
908 Summary summary(si.displayName);
909 collectSource(si, summary);
912 std::string gcovName = getCoveragePath(si.filename, filename);
914 os <<
"File '" << summary.Name <<
"'\n";
915 printSummary(summary, os);
917 os <<
"Creating '" << gcovName <<
"'\n";
923 std::optional<raw_fd_ostream> os;
928 errs() << ec.message() <<
'\n';
932 annotateSource(si,
file, gcno, gcda,
943 errs() << ec.message() <<
'\n';
947 for (
const SourceInfo &si : sources)
948 printSourceToIntermediate(si, os);
952void Context::printFunctionDetails(
const GCOVFunction &f,
954 const uint64_t entryCount =
f.getEntryCount();
956 const GCOVBlock &exitBlock =
f.getExitBlock();
959 exitCount += arc->
count;
961 if (
b.number != 0 && &b != &exitBlock &&
b.getCount())
964 os <<
"function " <<
f.getName(
options.Demangle) <<
" called " << entryCount
966 <<
"% blocks executed "
977 os <<
format(
"branch %2u ", edgeIdx++)
978 << formatBranchInfo(options, arc->
count, total) <<
'\n';
981void Context::printSummary(
const Summary &summary,
raw_ostream &os)
const {
982 os <<
format(
"Lines executed:%.2f%% of %" PRIu64
"\n",
983 double(summary.linesExec) * 100 / summary.lines, summary.lines);
985 if (summary.branches == 0) {
986 os <<
"No branches\n";
988 os <<
format(
"Branches executed:%.2f%% of %" PRIu64
"\n",
989 double(summary.branchesExec) * 100 / summary.branches,
991 os <<
format(
"Taken at least once:%.2f%% of %" PRIu64
"\n",
992 double(summary.branchesTaken) * 100 / summary.branches,
1002 fi.print(filename, gcno, gcda,
file);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
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
static std::string mangleCoveragePath(StringRef Filename, bool PreservePaths)
Convert a path to a gcov filename.
static uint32_t formatPercentage(uint64_t dividend, uint64_t divisor)
static uint32_t branchDiv(uint64_t Numerator, uint64_t Divisor)
@ GCOV_TAG_PROGRAM_SUMMARY
@ GCOV_TAG_OBJECT_SUMMARY
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 ...
dot regions Print regions of function to dot file(with no function bodies)"
std::pair< BasicBlock *, BasicBlock * > Edge
This file defines the SmallSet class.
unify loop Fixup each natural loop to have a single exit block
Represents either an error or a value T.
std::error_code getError() const
GCOVBlock - Collects block information.
static LLVM_ABI uint64_t getCyclesCount(const BlockVector &blocks)
void addDstEdge(GCOVArc *Edge)
SmallVector< GCOVBlockLocation > locations
void addSrcEdge(GCOVArc *Edge)
LLVM_ABI void print(raw_ostream &OS) const
collectLineCounts - Collect line counts.
static LLVM_ABI uint64_t augmentOneCycle(GCOVBlock *src, std::vector< std::pair< GCOVBlock *, size_t > > &stack)
SmallVector< GCOVArc *, 2 > pred
LLVM_ABI void dump() const
dump - Dump GCOVBlock content to dbgs() for debugging purposes.
SmallVector< GCOVArc *, 2 > succ
GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific read operations.
bool readInt(uint32_t &Val)
DataExtractor::Cursor cursor
bool readInt64(uint64_t &Val)
bool readGCOVVersion(GCOV::GCOVVersion &version)
readGCOVVersion - Read GCOV version.
bool readString(StringRef &str)
bool readGCNOFormat()
readGCNOFormat - Check GCNO signature is valid at the beginning of buffer.
bool readGCDAFormat()
readGCDAFormat - Check GCDA signature is valid at the beginning of buffer.
GCOVFile - Collects coverage information for one pair of coverage file (.gcno and ....
SmallVector< std::unique_ptr< GCOVFunction >, 16 > functions
LLVM_ABI void print(raw_ostream &OS) const
GCOV::GCOVVersion version
std::vector< std::string > filenames
GCOV::GCOVVersion getVersion() const
LLVM_ABI void dump() const
dump - Dump GCOVFile content to dbgs() for debugging purposes.
std::map< uint32_t, GCOVFunction * > identToFunction
StringMap< unsigned > filenameToIdx
LLVM_ABI bool readGCNO(GCOVBuffer &Buffer)
readGCNO - Read GCNO buffer.
LLVM_ABI bool readGCDA(GCOVBuffer &Buffer)
readGCDA - Read GCDA buffer.
GCOVFunction - Collects function information.
LLVM_ABI uint64_t getEntryCount() const
getEntryCount - Get the number of times the function was called by retrieving the entry block's count...
SmallVector< std::unique_ptr< GCOVArc >, 0 > treeArcs
LLVM_ABI StringRef getName(bool demangle) const
LLVM_ABI void dump() const
dump - Dump GCOVFunction content to dbgs() for debugging purposes.
LLVM_ABI void propagateCounts(const GCOVBlock &v, GCOVArc *pred)
SmallVector< std::unique_ptr< GCOVBlock >, 0 > blocks
LLVM_ABI GCOVBlock & getExitBlock() const
LLVM_ABI StringRef getFilename() const
DenseSet< const GCOVBlock * > visited
SmallString< 0 > demangled
LLVM_ABI void print(raw_ostream &OS) const
iterator_range< BlockIterator > blocksRange() const
SmallVector< std::unique_ptr< GCOVArc >, 0 > arcs
LLVM_ABI void update(ArrayRef< uint8_t > Data)
Updates the hash for the byte stream provided.
LLVM_ABI void final(MD5Result &Result)
Finishes off the hash and puts the result in result.
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...
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
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.
StringRef - Represent a constant reference to a string, i.e.
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
std::string str() const
str - Get the contents as an std::string.
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
constexpr bool empty() const
empty - Check if the string is empty.
constexpr const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
A raw_ostream that writes to a file descriptor.
This class implements an extremely fast bulk output stream that can only output to a stream.
LLVM_ABI bool exists(const basic_file_status &status)
Does file exist?
@ OF_TextWithCRLF
The file should be opened in text mode and use a carriage linefeed '\r '.
LLVM_ABI bool remove_dots(SmallVectorImpl< char > &path, bool remove_dot_dot=false, Style style=Style::native)
In-place remove any '.
LLVM_ABI StringRef filename(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get filename.
LLVM_ABI bool is_absolute(const Twine &path, Style style=Style::native)
Is path absolute?
LLVM_ABI bool replace_path_prefix(SmallVectorImpl< char > &Path, StringRef OldPrefix, StringRef NewPrefix, Style style=Style::native)
Replace matching path prefix with another path.
LLVM_ABI bool is_separator(char value, Style style=Style::native)
Check whether the given char is a path separator on the host OS.
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI 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)
DEMANGLE_ABI char * itaniumDemangle(std::string_view mangled_name, bool ParseParams=true)
Returns a non-NULL pointer to a NUL-terminated C style string that should be explicitly freed,...
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
LLVM_ABI 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...
auto max_element(R &&Range)
Provide wrappers to std::max_element which take ranges instead of having to pass begin/end explicitly...
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
LLVM_ABI void gcovOneInput(const GCOV::Options &options, StringRef filename, StringRef gcno, StringRef gcda, GCOVFile &file)
DEMANGLE_ABI std::string demangle(std::string_view MangledName)
Attempt to demangle a string using different demangling schemes.
LLVM_ABI bool onTree() const
Represent file of lines same with block_location_info in gcc.
SmallVector< uint32_t, 4 > lines
A struct for passing gcov options between functions.