Go to the documentation of this file.
17 #include "llvm/Config/llvm-config.h"
26 #include <system_error>
65 std::vector<std::vector<const GCOVFunction *>> startLineToFunctions;
66 std::vector<LineInfo> lines;
82 void printSummary(
const Summary &summary,
raw_ostream &os)
const;
85 void collectSourceLine(SourceInfo &si, Summary *summary, LineInfo &line,
86 size_t lineNum)
const;
87 void collectSource(SourceInfo &si, Summary &summary)
const;
90 void printSourceToIntermediate(
const SourceInfo &si,
raw_ostream &os)
const;
93 std::vector<SourceInfo> sources;
115 while ((tag = buf.
getWord())) {
120 functions.push_back(std::make_unique<GCOVFunction>(*
this));
145 fn->
srcIdx = r.first->second;
151 fn->
blocks.push_back(std::make_unique<GCOVBlock>(
i));
156 fn->
blocks.push_back(std::make_unique<GCOVBlock>(
i));
160 if (srcNo >= fn->
blocks.size()) {
161 errs() <<
"unexpected block number: " << srcNo <<
" (in "
162 << fn->
blocks.size() <<
")\n";
171 auto arc = std::make_unique<GCOVArc>(*src, *dst, flags);
181 if (srcNo >= fn->
blocks.size()) {
182 errs() <<
"unexpected block number: " << srcNo <<
" (in "
183 << fn->
blocks.size() <<
")\n";
220 errs() <<
"GCOV versions do not match.\n";
225 if (!buf.
readInt(GCDAChecksum))
229 <<
" != " << GCDAChecksum <<
"\n";
235 while ((tag = buf.
getWord())) {
259 if (length < 2 || !buf.
readInt(ident))
262 uint32_t linenoChecksum, cfgChecksum = 0;
271 <<
format(
": checksum mismatch, (%u, %u) != (%u, %u)\n",
281 if (length != expected) {
284 ": GCOV_TAG_COUNTER_ARCS mismatch, got %u, expected %u\n",
288 for (std::unique_ptr<GCOVArc> &
arc : fn->
arcs) {
291 arc->src.count +=
arc->count;
294 if (fn->
blocks.size() >= 2) {
323 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
358 return blocks.front()->getCount();
372 if (!
visited.insert(&v).second)
382 if (int64_t(excess) < 0)
385 pred->count = excess;
392 for (
const auto &Block :
blocks)
396 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
408 OS <<
"Block : " <<
number <<
" Counter : " <<
count <<
"\n";
410 OS <<
"\tSource Edges : ";
412 OS << Edge->src.number <<
" (" << Edge->count <<
"), ";
416 OS <<
"\tDestination Edges : ";
420 OS << Edge->dst.number <<
" (" << Edge->count <<
"), ";
424 if (!
lines.empty()) {
432 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
439 std::vector<std::pair<GCOVBlock *, size_t>> &
stack) {
443 stack.emplace_back(src, 0);
446 std::tie(u,
i) =
stack.back();
447 if (
i == u->
succ.size()) {
454 ++
stack.back().second;
459 if (
succ->cycleCount == 0 || !
succ->dst.traversable || &
succ->dst == u)
461 if (
succ->dst.incoming ==
nullptr) {
468 minCount =
std::min(minCount, v->incoming->cycleCount);
469 v = &v->incoming->src;
473 succ->cycleCount -= minCount;
475 v->incoming->cycleCount -= minCount;
476 v = &v->incoming->src;
490 std::vector<std::pair<GCOVBlock *, size_t>>
stack;
494 for (
auto b : blocks) {
499 for (
auto block : blocks) {
510 for (
auto b : blocks) {
523 if (!dividend || !divisor)
526 return dividend < divisor ? 1 : dividend / divisor;
535 if (Numerator == Divisor)
538 uint8_t Res = (Numerator * 100 + Divisor / 2) / Divisor;
547 struct formatBranchInfo {
553 OS <<
"never executed";
555 OS <<
"taken " << Count;
557 OS <<
"taken " <<
branchDiv(Count, Total) <<
"%";
571 std::unique_ptr<MemoryBuffer> Buffer;
575 LineConsumer() =
default;
582 if (std::error_code EC = BufferOrErr.
getError()) {
583 errs() << Filename <<
": " <<
EC.message() <<
"\n";
587 Remaining = Buffer->getBuffer();
596 std::tie(Line, Remaining) = Remaining.
split(
"\n");
597 OS <<
format(
"%5u:", LineNum) << Line <<
"\n";
617 if (
I -
S == 1 && *
S ==
'.') {
619 }
else if (
I -
S == 2 && *
S ==
'.' && *(
S + 1) ==
'.') {
627 Result.push_back(
'#');
634 return std::string(Result.str());
645 std::string CoveragePath;
654 Hasher.
final(Result);
655 CoveragePath +=
"##" + std::string(
Result.digest());
657 CoveragePath +=
".gcov";
661 void 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);
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);
675 LineInfo &line = si.lines[lineNum];
676 if (lines.
insert(lineNum).second)
678 if (
b.count && linesExec.
insert(lineNum).second)
681 line.count +=
b.count;
682 line.blocks.push_back(&
b);
687 void Context::collectSourceLine(SourceInfo &si, Summary *summary,
688 LineInfo &line,
size_t lineNum)
const {
691 if (
b->number == 0) {
705 arc->cycleCount =
arc->count;
713 ++summary->linesExec;
718 if (
b->getLastLine() != lineNum)
720 int branches = 0, execBranches = 0, takenBranches = 0;
730 summary->branchesExec += execBranches;
731 summary->branchesTaken += takenBranches;
736 void Context::collectSource(SourceInfo &si, Summary &summary)
const {
738 for (LineInfo &line : si.lines) {
739 collectSourceLine(si, &summary, line, lineNum);
744 void Context::annotateSource(SourceInfo &si,
const GCOVFile &
file,
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';
755 os <<
" -: 0:Programs:" <<
file.programCount <<
'\n';
757 for (
size_t lineNum = 1; !source.empty(); ++lineNum) {
758 if (lineNum >= si.lines.size()) {
760 source.printNext(os, lineNum);
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);
770 else if (line.count == 0)
773 os <<
format(
"%9" PRIu64
":", line.count);
774 source.printNext(os, lineNum);
778 if (
b->getLastLine() != lineNum)
781 if (
b->getCount() == 0)
784 os <<
format(
"%9" PRIu64
":",
b->count);
785 os <<
format(
"%5u-block %2u\n", lineNum, blockIdx++);
788 size_t NumEdges =
b->succ.size();
790 printBranchInfo(*
b, edgeIdx, os);
791 else if (
options.UncondBranch && NumEdges == 1) {
793 os <<
format(
"unconditional %2u ", edgeIdx++)
801 void Context::printSourceToIntermediate(
const SourceInfo &si,
803 os <<
"file:" << si.filename <<
'\n';
804 for (
const auto &fs : si.startLineToFunctions)
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())
815 os <<
"lcount:" << lineNum <<
',' << line.count <<
'\n';
820 if (
b->succ.size() < 2 ||
b->getLastLine() != lineNum)
824 b->getCount() ?
arc->count ?
"taken" :
"nottaken" :
"notexec";
825 os <<
"branch:" << lineNum <<
',' <<
type <<
'\n';
835 SourceInfo &si = sources.back();
836 si.displayName = si.filename;
837 if (!
options.SourcePrefix.empty() &&
840 !si.displayName.empty()) {
844 si.displayName.erase(si.displayName.begin());
846 si.displayName = si.filename;
854 Summary summary(
f.getName(
options.Demangle));
855 collectFunction(
f, summary);
857 os <<
"Function '" << summary.Name <<
"'\n";
858 printSummary(summary, os);
863 for (SourceInfo &si : sources) {
866 Summary summary(si.displayName);
867 collectSource(si, summary);
870 std::string gcovName = getCoveragePath(si.filename,
filename);
872 os <<
"File '" << summary.Name <<
"'\n";
873 printSummary(summary, os);
875 os <<
"Creating '" << gcovName <<
"'\n";
886 errs() << ec.message() <<
'\n';
890 annotateSource(si,
file, gcno, gcda,
901 errs() << ec.message() <<
'\n';
905 for (
const SourceInfo &si : sources)
906 printSourceToIntermediate(si, os);
912 const uint64_t entryCount =
f.getEntryCount();
914 const GCOVBlock &exitBlock =
f.getExitBlock();
917 exitCount +=
arc->count;
919 if (
b.number != 0 && &
b != &exitBlock &&
b.getCount())
922 os <<
"function " <<
f.getName(
options.Demangle) <<
" called " << entryCount
924 <<
"% blocks executed "
935 os <<
format(
"branch %2u ", edgeIdx++)
936 << formatBranchInfo(
options,
arc->count, total) <<
'\n';
939 void 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);
943 if (summary.branches == 0) {
944 os <<
"No branches\n";
946 os <<
format(
"Branches executed:%.2f%% of %" PRIu64
"\n",
947 double(summary.branchesExec) * 100 / summary.branches,
949 os <<
format(
"Taken at least once:%.2f%% of %" PRIu64
"\n",
950 double(summary.branchesTaken) * 100 / summary.branches,
SmallVector< std::unique_ptr< GCOVFunction >, 16 > functions
we get the following basic block
LLVM_NODISCARD bool startswith(StringRef Prefix) const
Check if this string starts with the given Prefix.
DataExtractor::Cursor cursor
iterator_range< EdgeIterator > srcs() const
bool readGCOVVersion(GCOV::GCOVVersion &version)
readGCOVVersion - Read GCOV version.
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
This is an optimization pass for GlobalISel generic memory operations.
uint64_t getEntryCount() const
getEntryCount - Get the number of times the function was called by retrieving the entry block's count...
bool replace_path_prefix(SmallVectorImpl< char > &Path, StringRef OldPrefix, StringRef NewPrefix, Style style=Style::native)
Replace matching path prefix with another path.
SmallVector< GCOVArc *, 2 > pred
void update(ArrayRef< uint8_t > Data)
Updates the hash for the byte stream provided.
SmallString< 0 > demangled
static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val)
GCOVBlock - Collects block information.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
bool is_absolute(const Twine &path, Style style=Style::native)
Is path absolute?
DenseSet< const GCOVBlock * > visited
static uint32_t branchDiv(uint64_t Numerator, uint64_t Divisor)
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
std::map< uint32_t, GCOVFunction * > identToFunction
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
StringRef getName(bool demangle) const
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
StringMap< unsigned > filenameToIdx
void dump() const
dump - Dump GCOVFile content to dbgs() for debugging purposes.
void addDstEdge(GCOVArc *Edge)
void final(MD5Result &Result)
Finishes off the hash and puts the result in result.
raw_fd_ostream & outs()
This returns a reference to a raw_fd_ostream for standard output.
iterator_range< BlockIterator > blocksRange() const
Itanium Name Demangler i e convert the string _Z1fv into f()". You can also use the CRTP base ManglingParser to perform some simple analysis on the mangled name
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
LLVM_NODISCARD std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
bool readGCDAFormat()
readGCDAFormat - Check GCDA signature is valid at the beginning of buffer.
the resulting code requires compare and branches when and if the revised code is with conditional branches instead of More there is a byte word extend before each where there should be only and the condition codes are not remembered when the same two values are compared twice More LSR enhancements i8 and i32 load store addressing modes are identical int b
SmallVector< uint32_t, 4 > lines
SmallVector< GCOVArc *, 2 > succ
std::error_code getError() const
static uint64_t getCyclesCount(const BlockVector &blocks)
StringRef getFilename() const
@ GCOV_TAG_PROGRAM_SUMMARY
const char LLVMTargetMachineRef LLVMPassBuilderOptionsRef Options
This class implements an extremely fast bulk output stream that can only output to a stream.
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
static uint32_t formatPercentage(uint64_t dividend, uint64_t divisor)
LLVM_NODISCARD std::string str() const
str - Get the contents as an std::string.
std::string demangle(const std::string &MangledName)
Attempt to demangle a string using different demangling schemes.
LLVM_NODISCARD bool equals(StringRef RHS) const
equals - Check for string equality, this is more efficient than compare() when the relative ordering ...
@ OF_TextWithCRLF
The file should be opened in text mode and use a carriage linefeed '\r '.
static uint64_t augmentOneCycle(GCOVBlock *src, std::vector< std::pair< GCOVBlock *, size_t >> &stack)
GCOV::GCOVVersion getVersion() const
GCOVBlock & getExitBlock() const
dot regions Print regions of function to dot file(with no function bodies)"
bool exists(const basic_file_status &status)
Does file exist?
constexpr LLVM_NODISCARD bool empty() const
empty - Check if the string is empty.
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...
void emplace(ArgTypes &&... Args)
Create a new object by constructing it in place with the given arguments.
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFileOrSTDIN(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true)
Open the specified file as a MemoryBuffer, or open stdin if the Filename is "-".
bool is_contained(R &&Range, const E &Element)
Wrapper function around std::find to detect if an element exists in a container.
SmallVector< std::unique_ptr< GCOVArc >, 0 > arcs
iterator_range< pointee_iterator< WrappedIteratorT > > make_pointee_range(RangeT &&Range)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
bool readInt(uint32_t &Val)
void gcovOneInput(const GCOV::Options &options, StringRef filename, StringRef gcno, StringRef gcda, GCOVFile &file)
bool readInt64(uint64_t &Val)
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
gvn sink
When an instruction is found to only be used outside of the loop, this function moves it to the exit ...
Expected< ExpressionValue > min(const ExpressionValue &Lhs, const ExpressionValue &Rhs)
StringRef - Represent a constant reference to a string, i.e.
add sub stmia L5 ldr r0 bl L_printf $stub Instead of a and a wouldn t it be better to do three moves *Return an aggregate type is even return S
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
std::pair< NoneType, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
static std::string mangleCoveragePath(StringRef Filename, bool PreservePaths)
Convert a path to a gcov filename.
A raw_ostream that writes to a file descriptor.
void dump() const
dump - Dump GCOVFunction content to dbgs() for debugging purposes.
void print(raw_ostream &OS) const
@ GCOV_TAG_OBJECT_SUMMARY
constexpr bool empty(const T &RangeOrContainer)
Test whether RangeOrContainer is empty. Similar to C++17 std::empty.
A struct for passing gcov options between functions.
GCOV::GCOVVersion version
The object format emitted by the WebAssembly backed is documented see the home and packaging for producing WebAssembly applications that can run in browsers and other environments wasi sdk provides a more minimal C C SDK based on llvm and a libc based on for producing WebAssemmbly applictions that use the WASI ABI Rust provides WebAssembly support integrated into Cargo There are two main options
void print(raw_ostream &OS) const
collectLineCounts - Collect line counts.
void print(raw_ostream &OS) const
bool readGCNOFormat()
readGCNOFormat - Check GCNO signature is valid at the beginning of buffer.
iterator_range< EdgeIterator > dsts() const
std::vector< std::string > filenames
bool readGCDA(GCOVBuffer &Buffer)
readGCDA - Read GCDA buffer.
bool is_separator(char value, Style style=Style::native)
Check whether the given char is a path separator on the host OS.
StringRef filename(StringRef path, Style style=Style::native)
Get filename.
GCOVFile - Collects coverage information for one pair of coverage file (.gcno and ....
std::error_code status(const Twine &path, file_status &result, bool follow=true)
Get file status as if by POSIX stat().
void addSrcEdge(GCOVArc *Edge)
Represents either an error or a value T.
void dump() const
dump - Dump GCOVBlock content to dbgs() for debugging purposes.
SmallVector< std::unique_ptr< GCOVArc >, 0 > treeArcs
S is passed via registers r2 But gcc stores them to the stack
const LLVM_NODISCARD char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
bool readString(StringRef &str)
char * itaniumDemangle(const char *mangled_name, char *buf, size_t *n, int *status)
SmallVector< std::unique_ptr< GCOVBlock >, 0 > blocks
GCOVFunction - Collects function information.
GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific read operations.
the resulting code requires compare and branches when and if the revised code is with conditional branches instead of More there is a byte word extend before each where there should be only and the condition codes are not remembered when the same two values are compared twice More LSR enhancements i8 and i32 load store addressing modes are identical int int int d
arc branch ARC finalize branches
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.
uint64_t propagateCounts(const GCOVBlock &v, GCOVArc *pred)
bool readGCNO(GCOVBuffer &Buffer)
readGCNO - Read GCNO buffer.