mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
[gcov] Fix .gcda decoding and support GCC 8, 9 and 10
GCDAProfiling.c unnecessarily writes function names to .gcda files. GCC 4.2 gcc/libgcov.c (now renamed to libgcc/libgcov*) did not write function names. gcov-7 (compatible) crashes on .gcda produced by libclang_rt.profile rL176173 realized the problem and introduced a mode to remove function names. llvm-cov code apparently takes GCDAProfiling.c output format as truth and tries to decode function names. Additionally, llvm-cov tries to decode tags in certain order which does not match libgcov emitted .gcda files. This patch fixes the .gcda decoder and makes it work with GCC 8 and 9 (10 is compatible with 9). Note, line statistics are broken and not fixed by this patch. Add test/tools/llvm-cov/gcov-{4.7,8,9}.c to test compatibility.
This commit is contained in:
parent
366aeb3a0b
commit
d7b402943b
@ -28,6 +28,7 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
@ -40,7 +41,7 @@ class FileInfo;
|
||||
|
||||
namespace GCOV {
|
||||
|
||||
enum GCOVVersion { V402, V404, V704 };
|
||||
enum GCOVVersion { V402, V407, V800, V900 };
|
||||
|
||||
/// A struct for passing gcov options between functions.
|
||||
struct Options {
|
||||
@ -92,23 +93,29 @@ public:
|
||||
|
||||
/// readGCOVVersion - Read GCOV version.
|
||||
bool readGCOVVersion(GCOV::GCOVVersion &Version) {
|
||||
StringRef VersionStr = Buffer->getBuffer().slice(Cursor, Cursor + 4);
|
||||
if (VersionStr == "*204") {
|
||||
Cursor += 4;
|
||||
StringRef Str = Buffer->getBuffer().slice(Cursor, Cursor + 4);
|
||||
Cursor += 4;
|
||||
int Major =
|
||||
Str[3] >= 'A' ? (Str[3] - 'A') * 10 + Str[2] - '0' : Str[3] - '0';
|
||||
int Minor = Str[1] - '0';
|
||||
if (Major >= 9) {
|
||||
// PR gcov-profile/84846, r269678
|
||||
Version = GCOV::V900;
|
||||
return true;
|
||||
} else if (Major >= 8) {
|
||||
// PR gcov-profile/48463
|
||||
Version = GCOV::V800;
|
||||
return true;
|
||||
} else if (Major > 4 || (Major == 4 && Minor >= 7)) {
|
||||
// r173147
|
||||
Version = GCOV::V407;
|
||||
return true;
|
||||
} else {
|
||||
Version = GCOV::V402;
|
||||
return true;
|
||||
}
|
||||
if (VersionStr == "*404") {
|
||||
Cursor += 4;
|
||||
Version = GCOV::V404;
|
||||
return true;
|
||||
}
|
||||
if (VersionStr == "*704") {
|
||||
Cursor += 4;
|
||||
Version = GCOV::V704;
|
||||
return true;
|
||||
}
|
||||
errs() << "Unexpected version: " << VersionStr << ".\n";
|
||||
Cursor -= 4;
|
||||
errs() << "unexpected version: " << Str << "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -160,42 +167,6 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
/// readArcTag - If cursor points to an gcda arc tag then increment the
|
||||
/// cursor and return true otherwise return false.
|
||||
bool readArcTag() {
|
||||
StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
|
||||
if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\xa1' ||
|
||||
Tag[3] != '\1') {
|
||||
return false;
|
||||
}
|
||||
Cursor += 4;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// readObjectTag - If cursor points to an object summary tag then increment
|
||||
/// the cursor and return true otherwise return false.
|
||||
bool readObjectTag() {
|
||||
StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
|
||||
if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\0' ||
|
||||
Tag[3] != '\xa1') {
|
||||
return false;
|
||||
}
|
||||
Cursor += 4;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// readProgramTag - If cursor points to a program summary tag then increment
|
||||
/// the cursor and return true otherwise return false.
|
||||
bool readProgramTag() {
|
||||
StringRef Tag = Buffer->getBuffer().slice(Cursor, Cursor + 4);
|
||||
if (Tag.empty() || Tag[0] != '\0' || Tag[1] != '\0' || Tag[2] != '\0' ||
|
||||
Tag[3] != '\xa3') {
|
||||
return false;
|
||||
}
|
||||
Cursor += 4;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool readInt(uint32_t &Val) {
|
||||
if (Buffer->getBuffer().size() < Cursor + 4) {
|
||||
errs() << "Unexpected end of memory buffer: " << Cursor + 4 << ".\n";
|
||||
@ -234,6 +205,7 @@ public:
|
||||
|
||||
uint64_t getCursor() const { return Cursor; }
|
||||
void advanceCursor(uint32_t n) { Cursor += n * 4; }
|
||||
void setCursor(uint64_t c) { Cursor = c; }
|
||||
|
||||
private:
|
||||
MemoryBuffer *Buffer;
|
||||
@ -248,6 +220,7 @@ public:
|
||||
|
||||
bool readGCNO(GCOVBuffer &Buffer);
|
||||
bool readGCDA(GCOVBuffer &Buffer);
|
||||
GCOV::GCOVVersion getVersion() const { return Version; }
|
||||
uint32_t getChecksum() const { return Checksum; }
|
||||
void print(raw_ostream &OS) const;
|
||||
void dump() const;
|
||||
@ -257,17 +230,20 @@ private:
|
||||
bool GCNOInitialized = false;
|
||||
GCOV::GCOVVersion Version;
|
||||
uint32_t Checksum = 0;
|
||||
StringRef cwd;
|
||||
SmallVector<std::unique_ptr<GCOVFunction>, 16> Functions;
|
||||
std::map<uint32_t, GCOVFunction *> IdentToFunction;
|
||||
uint32_t RunCount = 0;
|
||||
uint32_t ProgramCount = 0;
|
||||
};
|
||||
|
||||
/// GCOVEdge - Collects edge information.
|
||||
struct GCOVEdge {
|
||||
GCOVEdge(GCOVBlock &S, GCOVBlock &D) : Src(S), Dst(D) {}
|
||||
struct GCOVArc {
|
||||
GCOVArc(GCOVBlock &src, GCOVBlock &dst, bool fallthrough)
|
||||
: src(src), dst(dst), fallthrough(fallthrough) {}
|
||||
|
||||
GCOVBlock &Src;
|
||||
GCOVBlock &Dst;
|
||||
GCOVBlock &src;
|
||||
GCOVBlock &dst;
|
||||
bool fallthrough;
|
||||
uint64_t Count = 0;
|
||||
uint64_t CyclesCount = 0;
|
||||
};
|
||||
@ -278,10 +254,9 @@ public:
|
||||
using BlockIterator = pointee_iterator<
|
||||
SmallVectorImpl<std::unique_ptr<GCOVBlock>>::const_iterator>;
|
||||
|
||||
GCOVFunction(GCOVFile &P) : Parent(P) {}
|
||||
GCOVFunction(GCOVFile &P) {}
|
||||
|
||||
bool readGCNO(GCOVBuffer &Buffer, GCOV::GCOVVersion Version);
|
||||
bool readGCDA(GCOVBuffer &Buffer, GCOV::GCOVVersion Version);
|
||||
StringRef getName() const { return Name; }
|
||||
StringRef getFilename() const { return Filename; }
|
||||
size_t getNumBlocks() const { return Blocks.size(); }
|
||||
@ -298,15 +273,18 @@ public:
|
||||
void dump() const;
|
||||
void collectLineCounts(FileInfo &FI);
|
||||
|
||||
private:
|
||||
GCOVFile &Parent;
|
||||
uint32_t Ident = 0;
|
||||
uint32_t Checksum;
|
||||
uint32_t LineNumber = 0;
|
||||
uint32_t ident = 0;
|
||||
uint32_t linenoChecksum;
|
||||
uint32_t cfgChecksum = 0;
|
||||
uint32_t startLine = 0;
|
||||
uint32_t startColumn = 0;
|
||||
uint32_t endLine = 0;
|
||||
uint32_t endColumn = 0;
|
||||
uint8_t artificial = 0;
|
||||
StringRef Name;
|
||||
StringRef Filename;
|
||||
SmallVector<std::unique_ptr<GCOVBlock>, 16> Blocks;
|
||||
SmallVector<std::unique_ptr<GCOVEdge>, 16> Edges;
|
||||
SmallVector<std::unique_ptr<GCOVBlock>, 0> Blocks;
|
||||
SmallVector<std::unique_ptr<GCOVArc>, 0> arcs, treeArcs;
|
||||
};
|
||||
|
||||
/// GCOVBlock - Collects block information.
|
||||
@ -319,47 +297,31 @@ class GCOVBlock {
|
||||
};
|
||||
|
||||
public:
|
||||
using EdgeIterator = SmallVectorImpl<GCOVEdge *>::const_iterator;
|
||||
using EdgeIterator = SmallVectorImpl<GCOVArc *>::const_iterator;
|
||||
using BlockVector = SmallVector<const GCOVBlock *, 4>;
|
||||
using BlockVectorLists = SmallVector<BlockVector, 4>;
|
||||
using Edges = SmallVector<GCOVEdge *, 4>;
|
||||
using Edges = SmallVector<GCOVArc *, 4>;
|
||||
|
||||
GCOVBlock(GCOVFunction &P, uint32_t N) : Parent(P), Number(N) {}
|
||||
~GCOVBlock();
|
||||
|
||||
const GCOVFunction &getParent() const { return Parent; }
|
||||
void addLine(uint32_t N) { Lines.push_back(N); }
|
||||
uint32_t getLastLine() const { return Lines.back(); }
|
||||
void addCount(size_t DstEdgeNo, uint64_t N);
|
||||
uint64_t getCount() const { return Counter; }
|
||||
|
||||
void addSrcEdge(GCOVEdge *Edge) {
|
||||
assert(&Edge->Dst == this); // up to caller to ensure edge is valid
|
||||
SrcEdges.push_back(Edge);
|
||||
}
|
||||
void addSrcEdge(GCOVArc *Edge) { pred.push_back(Edge); }
|
||||
|
||||
void addDstEdge(GCOVEdge *Edge) {
|
||||
assert(&Edge->Src == this); // up to caller to ensure edge is valid
|
||||
// Check if adding this edge causes list to become unsorted.
|
||||
if (DstEdges.size() && DstEdges.back()->Dst.Number > Edge->Dst.Number)
|
||||
DstEdgesAreSorted = false;
|
||||
DstEdges.push_back(Edge);
|
||||
}
|
||||
void addDstEdge(GCOVArc *Edge) { succ.push_back(Edge); }
|
||||
|
||||
size_t getNumSrcEdges() const { return SrcEdges.size(); }
|
||||
size_t getNumDstEdges() const { return DstEdges.size(); }
|
||||
void sortDstEdges();
|
||||
size_t getNumSrcEdges() const { return pred.size(); }
|
||||
size_t getNumDstEdges() const { return succ.size(); }
|
||||
|
||||
EdgeIterator src_begin() const { return SrcEdges.begin(); }
|
||||
EdgeIterator src_end() const { return SrcEdges.end(); }
|
||||
iterator_range<EdgeIterator> srcs() const {
|
||||
return make_range(src_begin(), src_end());
|
||||
return make_range(pred.begin(), pred.end());
|
||||
}
|
||||
|
||||
EdgeIterator dst_begin() const { return DstEdges.begin(); }
|
||||
EdgeIterator dst_end() const { return DstEdges.end(); }
|
||||
iterator_range<EdgeIterator> dsts() const {
|
||||
return make_range(dst_begin(), dst_end());
|
||||
return make_range(succ.begin(), succ.end());
|
||||
}
|
||||
|
||||
void print(raw_ostream &OS) const;
|
||||
@ -376,13 +338,12 @@ public:
|
||||
static void getCyclesCount(const BlockVector &Blocks, uint64_t &Count);
|
||||
static uint64_t getLineCount(const BlockVector &Blocks);
|
||||
|
||||
private:
|
||||
public:
|
||||
GCOVFunction &Parent;
|
||||
uint32_t Number;
|
||||
uint64_t Counter = 0;
|
||||
bool DstEdgesAreSorted = true;
|
||||
SmallVector<GCOVEdge *, 16> SrcEdges;
|
||||
SmallVector<GCOVEdge *, 16> DstEdges;
|
||||
SmallVector<GCOVArc *, 2> pred;
|
||||
SmallVector<GCOVArc *, 2> succ;
|
||||
SmallVector<uint32_t, 16> Lines;
|
||||
};
|
||||
|
||||
@ -438,7 +399,7 @@ public:
|
||||
void setRunCount(uint32_t Runs) { RunCount = Runs; }
|
||||
void setProgramCount(uint32_t Programs) { ProgramCount = Programs; }
|
||||
void print(raw_ostream &OS, StringRef MainFilename, StringRef GCNOFile,
|
||||
StringRef GCDAFile);
|
||||
StringRef GCDAFile, GCOV::GCOVVersion Version);
|
||||
|
||||
protected:
|
||||
std::string getCoveragePath(StringRef Filename, StringRef MainFilename);
|
||||
|
@ -25,24 +25,41 @@
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
enum : uint32_t {
|
||||
GCOV_ARC_ON_TREE = 1 << 0,
|
||||
GCOV_ARC_FALLTHROUGH = 1 << 2,
|
||||
|
||||
GCOV_TAG_FUNCTION = 0x01000000,
|
||||
GCOV_TAG_COUNTER_ARCS = 0x01a10000,
|
||||
// GCOV_TAG_OBJECT_SUMMARY superseded GCOV_TAG_PROGRAM_SUMMARY in GCC 9.
|
||||
GCOV_TAG_OBJECT_SUMMARY = 0xa1000000,
|
||||
GCOV_TAG_PROGRAM_SUMMARY = 0xa3000000,
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// GCOVFile implementation.
|
||||
|
||||
/// readGCNO - Read GCNO buffer.
|
||||
bool GCOVFile::readGCNO(GCOVBuffer &Buffer) {
|
||||
if (!Buffer.readGCNOFormat())
|
||||
bool GCOVFile::readGCNO(GCOVBuffer &buf) {
|
||||
if (!buf.readGCNOFormat())
|
||||
return false;
|
||||
if (!Buffer.readGCOVVersion(Version))
|
||||
if (!buf.readGCOVVersion(Version))
|
||||
return false;
|
||||
|
||||
if (!Buffer.readInt(Checksum))
|
||||
if (!buf.readInt(Checksum))
|
||||
return false;
|
||||
if (Version >= GCOV::V900 && !buf.readString(cwd))
|
||||
return false;
|
||||
uint32_t hasUnexecutedBlocks;
|
||||
if (Version >= GCOV::V800 && !buf.readInt(hasUnexecutedBlocks))
|
||||
return false;
|
||||
while (true) {
|
||||
if (!Buffer.readFunctionTag())
|
||||
if (!buf.readFunctionTag())
|
||||
break;
|
||||
auto GFun = std::make_unique<GCOVFunction>(*this);
|
||||
if (!GFun->readGCNO(Buffer, Version))
|
||||
if (!GFun->readGCNO(buf, Version))
|
||||
return false;
|
||||
IdentToFunction[GFun->ident] = GFun.get();
|
||||
Functions.push_back(std::move(GFun));
|
||||
}
|
||||
|
||||
@ -52,12 +69,12 @@ bool GCOVFile::readGCNO(GCOVBuffer &Buffer) {
|
||||
|
||||
/// readGCDA - Read GCDA buffer. It is required that readGCDA() can only be
|
||||
/// called after readGCNO().
|
||||
bool GCOVFile::readGCDA(GCOVBuffer &Buffer) {
|
||||
bool GCOVFile::readGCDA(GCOVBuffer &buf) {
|
||||
assert(GCNOInitialized && "readGCDA() can only be called after readGCNO()");
|
||||
if (!Buffer.readGCDAFormat())
|
||||
if (!buf.readGCDAFormat())
|
||||
return false;
|
||||
GCOV::GCOVVersion GCDAVersion;
|
||||
if (!Buffer.readGCOVVersion(GCDAVersion))
|
||||
if (!buf.readGCOVVersion(GCDAVersion))
|
||||
return false;
|
||||
if (Version != GCDAVersion) {
|
||||
errs() << "GCOV versions do not match.\n";
|
||||
@ -65,40 +82,69 @@ bool GCOVFile::readGCDA(GCOVBuffer &Buffer) {
|
||||
}
|
||||
|
||||
uint32_t GCDAChecksum;
|
||||
if (!Buffer.readInt(GCDAChecksum))
|
||||
if (!buf.readInt(GCDAChecksum))
|
||||
return false;
|
||||
if (Checksum != GCDAChecksum) {
|
||||
errs() << "File checksums do not match: " << Checksum
|
||||
<< " != " << GCDAChecksum << ".\n";
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0, e = Functions.size(); i < e; ++i) {
|
||||
if (!Buffer.readFunctionTag()) {
|
||||
errs() << "Unexpected number of functions.\n";
|
||||
uint32_t dummy, tag, length;
|
||||
uint32_t ident;
|
||||
GCOVFunction *fn = nullptr;
|
||||
while (buf.readInt(tag) && tag) {
|
||||
if (!buf.readInt(length))
|
||||
return false;
|
||||
uint32_t cursor = buf.getCursor();
|
||||
if (tag == GCOV_TAG_OBJECT_SUMMARY) {
|
||||
buf.readInt(dummy);
|
||||
buf.readInt(dummy);
|
||||
buf.readInt(RunCount);
|
||||
} else if (tag == GCOV_TAG_PROGRAM_SUMMARY) {
|
||||
++ProgramCount;
|
||||
} else if (tag == GCOV_TAG_FUNCTION) {
|
||||
if (length == 0) // Placeholder
|
||||
continue;
|
||||
// length>3 is to be compatible with some clang --coverage generated
|
||||
// tests. As of GCC 10, GCOV_TAG_FUNCTION_LENGTH has never been larger
|
||||
// than 3.
|
||||
if (length < 3 || !buf.readInt(ident))
|
||||
return false;
|
||||
auto It = IdentToFunction.find(ident);
|
||||
uint32_t linenoChecksum, cfgChecksum;
|
||||
buf.readInt(linenoChecksum);
|
||||
buf.readInt(cfgChecksum);
|
||||
if (Version < GCOV::V407)
|
||||
cfgChecksum = 0;
|
||||
if (It != IdentToFunction.end()) {
|
||||
fn = It->second;
|
||||
if (linenoChecksum != fn->linenoChecksum ||
|
||||
cfgChecksum != fn->cfgChecksum) {
|
||||
errs() << fn->Name
|
||||
<< format(": checksum mismatch, (%u, %u) != (%u, %u)\n",
|
||||
linenoChecksum, cfgChecksum, fn->linenoChecksum,
|
||||
fn->cfgChecksum);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (tag == GCOV_TAG_COUNTER_ARCS && fn) {
|
||||
if (length != 2 * fn->arcs.size()) {
|
||||
errs() << fn->Name
|
||||
<< format(
|
||||
": GCOV_TAG_COUNTER_ARCS mismatch, got %u, expected %u\n",
|
||||
length, unsigned(2 * fn->arcs.size()));
|
||||
return false;
|
||||
}
|
||||
for (std::unique_ptr<GCOVArc> &arc : fn->arcs) {
|
||||
if (!buf.readInt64(arc->Count))
|
||||
return false;
|
||||
// FIXME Fix counters
|
||||
arc->src.Counter += arc->Count;
|
||||
if (arc->dst.succ.empty())
|
||||
arc->dst.Counter += arc->Count;
|
||||
}
|
||||
}
|
||||
if (!Functions[i]->readGCDA(Buffer, Version))
|
||||
return false;
|
||||
}
|
||||
if (Buffer.readObjectTag()) {
|
||||
uint32_t Length;
|
||||
uint32_t Dummy;
|
||||
if (!Buffer.readInt(Length))
|
||||
return false;
|
||||
if (!Buffer.readInt(Dummy))
|
||||
return false; // checksum
|
||||
if (!Buffer.readInt(Dummy))
|
||||
return false; // num
|
||||
if (!Buffer.readInt(RunCount))
|
||||
return false;
|
||||
Buffer.advanceCursor(Length - 3);
|
||||
}
|
||||
while (Buffer.readProgramTag()) {
|
||||
uint32_t Length;
|
||||
if (!Buffer.readInt(Length))
|
||||
return false;
|
||||
Buffer.advanceCursor(Length);
|
||||
++ProgramCount;
|
||||
buf.setCursor(cursor + 4 * length);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -128,82 +174,98 @@ void GCOVFile::collectLineCounts(FileInfo &FI) {
|
||||
|
||||
/// readGCNO - Read a function from the GCNO buffer. Return false if an error
|
||||
/// occurs.
|
||||
bool GCOVFunction::readGCNO(GCOVBuffer &Buff, GCOV::GCOVVersion Version) {
|
||||
bool GCOVFunction::readGCNO(GCOVBuffer &buf, GCOV::GCOVVersion Version) {
|
||||
uint32_t Dummy;
|
||||
if (!Buff.readInt(Dummy))
|
||||
if (!buf.readInt(Dummy))
|
||||
return false; // Function header length
|
||||
if (!Buff.readInt(Ident))
|
||||
if (!buf.readInt(ident))
|
||||
return false;
|
||||
if (!Buff.readInt(Checksum))
|
||||
if (!buf.readInt(linenoChecksum))
|
||||
return false;
|
||||
if (Version != GCOV::V402) {
|
||||
uint32_t CfgChecksum;
|
||||
if (!Buff.readInt(CfgChecksum))
|
||||
if (Version >= GCOV::V407 && !buf.readInt(cfgChecksum))
|
||||
return false;
|
||||
if (!buf.readString(Name))
|
||||
return false;
|
||||
if (Version < GCOV::V800) {
|
||||
if (!buf.readString(Filename))
|
||||
return false;
|
||||
if (Parent.getChecksum() != CfgChecksum) {
|
||||
errs() << "File checksums do not match: " << Parent.getChecksum()
|
||||
<< " != " << CfgChecksum << " in (" << Name << ").\n";
|
||||
if (!buf.readInt(startLine))
|
||||
return false;
|
||||
} else {
|
||||
if (!buf.readInt(Dummy))
|
||||
return false;
|
||||
artificial = Dummy;
|
||||
if (!buf.readString(Filename))
|
||||
return false;
|
||||
if (!buf.readInt(startLine))
|
||||
return false;
|
||||
if (!buf.readInt(startColumn))
|
||||
return false;
|
||||
if (!buf.readInt(endLine))
|
||||
return false;
|
||||
if (Version >= GCOV::V900 && !buf.readInt(endColumn))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!Buff.readString(Name))
|
||||
return false;
|
||||
if (!Buff.readString(Filename))
|
||||
return false;
|
||||
if (!Buff.readInt(LineNumber))
|
||||
return false;
|
||||
|
||||
// read blocks.
|
||||
if (!Buff.readBlockTag()) {
|
||||
if (!buf.readBlockTag()) {
|
||||
errs() << "Block tag not found.\n";
|
||||
return false;
|
||||
}
|
||||
if (Version >= GCOV::V800 && !buf.readInt(Dummy))
|
||||
return false;
|
||||
uint32_t BlockCount;
|
||||
if (!Buff.readInt(BlockCount))
|
||||
if (!buf.readInt(BlockCount))
|
||||
return false;
|
||||
for (uint32_t i = 0, e = BlockCount; i != e; ++i) {
|
||||
if (!Buff.readInt(Dummy))
|
||||
if (Version < GCOV::V800 && !buf.readInt(Dummy))
|
||||
return false; // Block flags;
|
||||
Blocks.push_back(std::make_unique<GCOVBlock>(*this, i));
|
||||
}
|
||||
|
||||
// read edges.
|
||||
while (Buff.readEdgeTag()) {
|
||||
while (buf.readEdgeTag()) {
|
||||
uint32_t EdgeCount;
|
||||
if (!Buff.readInt(EdgeCount))
|
||||
if (!buf.readInt(EdgeCount))
|
||||
return false;
|
||||
EdgeCount = (EdgeCount - 1) / 2;
|
||||
uint32_t BlockNo;
|
||||
if (!Buff.readInt(BlockNo))
|
||||
if (!buf.readInt(BlockNo))
|
||||
return false;
|
||||
if (BlockNo >= BlockCount) {
|
||||
errs() << "Unexpected block number: " << BlockNo << " (in " << Name
|
||||
<< ").\n";
|
||||
return false;
|
||||
}
|
||||
GCOVBlock *src = Blocks[BlockNo].get();
|
||||
for (uint32_t i = 0, e = EdgeCount; i != e; ++i) {
|
||||
uint32_t Dst;
|
||||
if (!Buff.readInt(Dst))
|
||||
uint32_t dstNo, flags;
|
||||
if (!buf.readInt(dstNo))
|
||||
return false;
|
||||
Edges.push_back(std::make_unique<GCOVEdge>(*Blocks[BlockNo], *Blocks[Dst]));
|
||||
GCOVEdge *Edge = Edges.back().get();
|
||||
Blocks[BlockNo]->addDstEdge(Edge);
|
||||
Blocks[Dst]->addSrcEdge(Edge);
|
||||
if (!Buff.readInt(Dummy))
|
||||
return false; // Edge flag
|
||||
if (!buf.readInt(flags))
|
||||
return false;
|
||||
GCOVBlock *dst = Blocks[dstNo].get();
|
||||
auto arc =
|
||||
std::make_unique<GCOVArc>(*src, *dst, flags & GCOV_ARC_FALLTHROUGH);
|
||||
src->addDstEdge(arc.get());
|
||||
dst->addSrcEdge(arc.get());
|
||||
if (flags & GCOV_ARC_ON_TREE)
|
||||
treeArcs.push_back(std::move(arc));
|
||||
else
|
||||
arcs.push_back(std::move(arc));
|
||||
}
|
||||
}
|
||||
|
||||
// read line table.
|
||||
while (Buff.readLineTag()) {
|
||||
while (buf.readLineTag()) {
|
||||
uint32_t LineTableLength;
|
||||
// Read the length of this line table.
|
||||
if (!Buff.readInt(LineTableLength))
|
||||
if (!buf.readInt(LineTableLength))
|
||||
return false;
|
||||
uint32_t EndPos = Buff.getCursor() + LineTableLength * 4;
|
||||
uint32_t EndPos = buf.getCursor() + LineTableLength * 4;
|
||||
uint32_t BlockNo;
|
||||
// Read the block number this table is associated with.
|
||||
if (!Buff.readInt(BlockNo))
|
||||
if (!buf.readInt(BlockNo))
|
||||
return false;
|
||||
if (BlockNo >= BlockCount) {
|
||||
errs() << "Unexpected block number: " << BlockNo << " (in " << Name
|
||||
@ -213,24 +275,24 @@ bool GCOVFunction::readGCNO(GCOVBuffer &Buff, GCOV::GCOVVersion Version) {
|
||||
GCOVBlock &Block = *Blocks[BlockNo];
|
||||
// Read the word that pads the beginning of the line table. This may be a
|
||||
// flag of some sort, but seems to always be zero.
|
||||
if (!Buff.readInt(Dummy))
|
||||
if (!buf.readInt(Dummy))
|
||||
return false;
|
||||
|
||||
// Line information starts here and continues up until the last word.
|
||||
if (Buff.getCursor() != (EndPos - sizeof(uint32_t))) {
|
||||
if (buf.getCursor() != (EndPos - sizeof(uint32_t))) {
|
||||
StringRef F;
|
||||
// Read the source file name.
|
||||
if (!Buff.readString(F))
|
||||
if (!buf.readString(F))
|
||||
return false;
|
||||
if (Filename != F) {
|
||||
// FIXME
|
||||
errs() << "Multiple sources for a single basic block: " << Filename
|
||||
<< " != " << F << " (in " << Name << ").\n";
|
||||
return false;
|
||||
}
|
||||
// Read lines up to, but not including, the null terminator.
|
||||
while (Buff.getCursor() < (EndPos - 2 * sizeof(uint32_t))) {
|
||||
while (buf.getCursor() < (EndPos - 2 * sizeof(uint32_t))) {
|
||||
uint32_t Line;
|
||||
if (!Buff.readInt(Line))
|
||||
if (!buf.readInt(Line))
|
||||
return false;
|
||||
// Line 0 means this instruction was injected by the compiler. Skip it.
|
||||
if (!Line)
|
||||
@ -238,104 +300,17 @@ bool GCOVFunction::readGCNO(GCOVBuffer &Buff, GCOV::GCOVVersion Version) {
|
||||
Block.addLine(Line);
|
||||
}
|
||||
// Read the null terminator.
|
||||
if (!Buff.readInt(Dummy))
|
||||
if (!buf.readInt(Dummy))
|
||||
return false;
|
||||
}
|
||||
// The last word is either a flag or padding, it isn't clear which. Skip
|
||||
// over it.
|
||||
if (!Buff.readInt(Dummy))
|
||||
if (!buf.readInt(Dummy))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// readGCDA - Read a function from the GCDA buffer. Return false if an error
|
||||
/// occurs.
|
||||
bool GCOVFunction::readGCDA(GCOVBuffer &Buff, GCOV::GCOVVersion Version) {
|
||||
uint32_t HeaderLength;
|
||||
if (!Buff.readInt(HeaderLength))
|
||||
return false; // Function header length
|
||||
|
||||
uint64_t EndPos = Buff.getCursor() + HeaderLength * sizeof(uint32_t);
|
||||
|
||||
uint32_t GCDAIdent;
|
||||
if (!Buff.readInt(GCDAIdent))
|
||||
return false;
|
||||
if (Ident != GCDAIdent) {
|
||||
errs() << "Function identifiers do not match: " << Ident
|
||||
<< " != " << GCDAIdent << " (in " << Name << ").\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t GCDAChecksum;
|
||||
if (!Buff.readInt(GCDAChecksum))
|
||||
return false;
|
||||
if (Checksum != GCDAChecksum) {
|
||||
errs() << "Function checksums do not match: " << Checksum
|
||||
<< " != " << GCDAChecksum << " (in " << Name << ").\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t CfgChecksum;
|
||||
if (Version != GCOV::V402) {
|
||||
if (!Buff.readInt(CfgChecksum))
|
||||
return false;
|
||||
if (Parent.getChecksum() != CfgChecksum) {
|
||||
errs() << "File checksums do not match: " << Parent.getChecksum()
|
||||
<< " != " << CfgChecksum << " (in " << Name << ").\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (Buff.getCursor() < EndPos) {
|
||||
StringRef GCDAName;
|
||||
if (!Buff.readString(GCDAName))
|
||||
return false;
|
||||
if (Name != GCDAName) {
|
||||
errs() << "Function names do not match: " << Name << " != " << GCDAName
|
||||
<< ".\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Buff.readArcTag()) {
|
||||
errs() << "Arc tag not found (in " << Name << ").\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t Count;
|
||||
if (!Buff.readInt(Count))
|
||||
return false;
|
||||
Count /= 2;
|
||||
|
||||
// This for loop adds the counts for each block. A second nested loop is
|
||||
// required to combine the edge counts that are contained in the GCDA file.
|
||||
for (uint32_t BlockNo = 0; Count > 0; ++BlockNo) {
|
||||
// The last block is always reserved for exit block
|
||||
if (BlockNo >= Blocks.size()) {
|
||||
errs() << "Unexpected number of edges (in " << Name << ").\n";
|
||||
return false;
|
||||
}
|
||||
if (BlockNo == Blocks.size() - 1)
|
||||
errs() << "(" << Name << ") has arcs from exit block.\n";
|
||||
GCOVBlock &Block = *Blocks[BlockNo];
|
||||
for (size_t EdgeNo = 0, End = Block.getNumDstEdges(); EdgeNo < End;
|
||||
++EdgeNo) {
|
||||
if (Count == 0) {
|
||||
errs() << "Unexpected number of edges (in " << Name << ").\n";
|
||||
return false;
|
||||
}
|
||||
uint64_t ArcCount;
|
||||
if (!Buff.readInt64(ArcCount))
|
||||
return false;
|
||||
Block.addCount(EdgeNo, ArcCount);
|
||||
--Count;
|
||||
}
|
||||
Block.sortDstEdges();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// getEntryCount - Get the number of times the function was called by
|
||||
/// retrieving the entry block's count.
|
||||
uint64_t GCOVFunction::getEntryCount() const {
|
||||
@ -349,8 +324,8 @@ uint64_t GCOVFunction::getExitCount() const {
|
||||
}
|
||||
|
||||
void GCOVFunction::print(raw_ostream &OS) const {
|
||||
OS << "===== " << Name << " (" << Ident << ") @ " << Filename << ":"
|
||||
<< LineNumber << "\n";
|
||||
OS << "===== " << Name << " (" << ident << ") @ " << Filename << ":"
|
||||
<< startLine << "\n";
|
||||
for (const auto &Block : Blocks)
|
||||
Block->print(OS);
|
||||
}
|
||||
@ -365,43 +340,17 @@ LLVM_DUMP_METHOD void GCOVFunction::dump() const { print(dbgs()); }
|
||||
void GCOVFunction::collectLineCounts(FileInfo &FI) {
|
||||
// If the line number is zero, this is a function that doesn't actually appear
|
||||
// in the source file, so there isn't anything we can do with it.
|
||||
if (LineNumber == 0)
|
||||
if (startLine == 0)
|
||||
return;
|
||||
|
||||
for (const auto &Block : Blocks)
|
||||
Block->collectLineCounts(FI);
|
||||
FI.addFunctionLine(Filename, LineNumber, this);
|
||||
FI.addFunctionLine(Filename, startLine, this);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// GCOVBlock implementation.
|
||||
|
||||
/// ~GCOVBlock - Delete GCOVBlock and its content.
|
||||
GCOVBlock::~GCOVBlock() {
|
||||
SrcEdges.clear();
|
||||
DstEdges.clear();
|
||||
Lines.clear();
|
||||
}
|
||||
|
||||
/// addCount - Add to block counter while storing the edge count. If the
|
||||
/// destination has no outgoing edges, also update that block's count too.
|
||||
void GCOVBlock::addCount(size_t DstEdgeNo, uint64_t N) {
|
||||
assert(DstEdgeNo < DstEdges.size()); // up to caller to ensure EdgeNo is valid
|
||||
DstEdges[DstEdgeNo]->Count = N;
|
||||
Counter += N;
|
||||
if (!DstEdges[DstEdgeNo]->Dst.getNumDstEdges())
|
||||
DstEdges[DstEdgeNo]->Dst.Counter += N;
|
||||
}
|
||||
|
||||
/// sortDstEdges - Sort destination edges by block number, nop if already
|
||||
/// sorted. This is required for printing branch info in the correct order.
|
||||
void GCOVBlock::sortDstEdges() {
|
||||
if (!DstEdgesAreSorted)
|
||||
llvm::stable_sort(DstEdges, [](const GCOVEdge *E1, const GCOVEdge *E2) {
|
||||
return E1->Dst.Number < E2->Dst.Number;
|
||||
});
|
||||
}
|
||||
|
||||
/// collectLineCounts - Collect line counts. This must be used after
|
||||
/// reading .gcno and .gcda files.
|
||||
void GCOVBlock::collectLineCounts(FileInfo &FI) {
|
||||
@ -411,16 +360,16 @@ void GCOVBlock::collectLineCounts(FileInfo &FI) {
|
||||
|
||||
void GCOVBlock::print(raw_ostream &OS) const {
|
||||
OS << "Block : " << Number << " Counter : " << Counter << "\n";
|
||||
if (!SrcEdges.empty()) {
|
||||
if (!pred.empty()) {
|
||||
OS << "\tSource Edges : ";
|
||||
for (const GCOVEdge *Edge : SrcEdges)
|
||||
OS << Edge->Src.Number << " (" << Edge->Count << "), ";
|
||||
for (const GCOVArc *Edge : pred)
|
||||
OS << Edge->src.Number << " (" << Edge->Count << "), ";
|
||||
OS << "\n";
|
||||
}
|
||||
if (!DstEdges.empty()) {
|
||||
if (!succ.empty()) {
|
||||
OS << "\tDestination Edges : ";
|
||||
for (const GCOVEdge *Edge : DstEdges)
|
||||
OS << Edge->Dst.Number << " (" << Edge->Count << "), ";
|
||||
for (const GCOVArc *Edge : succ)
|
||||
OS << Edge->dst.Number << " (" << Edge->Count << "), ";
|
||||
OS << "\n";
|
||||
}
|
||||
if (!Lines.empty()) {
|
||||
@ -482,7 +431,7 @@ bool GCOVBlock::lookForCircuit(const GCOVBlock *V, const GCOVBlock *Start,
|
||||
bool FoundCircuit = false;
|
||||
|
||||
for (auto E : V->dsts()) {
|
||||
const GCOVBlock *W = &E->Dst;
|
||||
const GCOVBlock *W = &E->dst;
|
||||
if (W < Start || find(Blocks, W) == Blocks.end()) {
|
||||
continue;
|
||||
}
|
||||
@ -506,7 +455,7 @@ bool GCOVBlock::lookForCircuit(const GCOVBlock *V, const GCOVBlock *Start,
|
||||
GCOVBlock::unblock(V, Blocked, BlockLists);
|
||||
} else {
|
||||
for (auto E : V->dsts()) {
|
||||
const GCOVBlock *W = &E->Dst;
|
||||
const GCOVBlock *W = &E->dst;
|
||||
if (W < Start || find(Blocks, W) == Blocks.end()) {
|
||||
continue;
|
||||
}
|
||||
@ -545,7 +494,7 @@ uint64_t GCOVBlock::getLineCount(const BlockVector &Blocks) {
|
||||
} else {
|
||||
// Add counts from predecessors that are not on the same line.
|
||||
for (auto E : Block->srcs()) {
|
||||
const GCOVBlock *W = &E->Src;
|
||||
const GCOVBlock *W = &E->src;
|
||||
if (find(Blocks, W) == Blocks.end()) {
|
||||
Count += E->Count;
|
||||
}
|
||||
@ -716,7 +665,8 @@ FileInfo::openCoveragePath(StringRef CoveragePath) {
|
||||
|
||||
/// print - Print source files with collected line count information.
|
||||
void FileInfo::print(raw_ostream &InfoOS, StringRef MainFilename,
|
||||
StringRef GCNOFile, StringRef GCDAFile) {
|
||||
StringRef GCNOFile, StringRef GCDAFile,
|
||||
GCOV::GCOVVersion Version) {
|
||||
SmallVector<StringRef, 4> Filenames;
|
||||
for (const auto &LI : LineInfo)
|
||||
Filenames.push_back(LI.first());
|
||||
@ -733,7 +683,8 @@ void FileInfo::print(raw_ostream &InfoOS, StringRef MainFilename,
|
||||
CovOS << " -: 0:Graph:" << GCNOFile << "\n";
|
||||
CovOS << " -: 0:Data:" << GCDAFile << "\n";
|
||||
CovOS << " -: 0:Runs:" << RunCount << "\n";
|
||||
CovOS << " -: 0:Programs:" << ProgramCount << "\n";
|
||||
if (Version < GCOV::V900)
|
||||
CovOS << " -: 0:Programs:" << ProgramCount << "\n";
|
||||
|
||||
const LineData &Line = LineInfo[Filename];
|
||||
GCOVCoverage FileCoverage(Filename);
|
||||
@ -815,8 +766,7 @@ void FileInfo::print(raw_ostream &InfoOS, StringRef MainFilename,
|
||||
if (NumEdges > 1)
|
||||
printBranchInfo(CovOS, *Block, FileCoverage, EdgeNo);
|
||||
else if (Options.UncondBranch && NumEdges == 1)
|
||||
printUncondBranchInfo(CovOS, EdgeNo,
|
||||
(*Block->dst_begin())->Count);
|
||||
printUncondBranchInfo(CovOS, EdgeNo, Block->succ[0]->Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -862,7 +812,7 @@ void FileInfo::printBranchInfo(raw_ostream &OS, const GCOVBlock &Block,
|
||||
GCOVCoverage &Coverage, uint32_t &EdgeNo) {
|
||||
SmallVector<uint64_t, 16> BranchCounts;
|
||||
uint64_t TotalCounts = 0;
|
||||
for (const GCOVEdge *Edge : Block.dsts()) {
|
||||
for (const GCOVArc *Edge : Block.dsts()) {
|
||||
BranchCounts.push_back(Edge->Count);
|
||||
TotalCounts += Edge->Count;
|
||||
if (Block.getCount())
|
||||
|
@ -1076,7 +1076,7 @@ std::error_code SampleProfileReaderGCC::readHeader() {
|
||||
if (!GcovBuffer.readGCOVVersion(version))
|
||||
return sampleprof_error::unrecognized_format;
|
||||
|
||||
if (version != GCOV::V704)
|
||||
if (version != GCOV::V407)
|
||||
return sampleprof_error::unsupported_version;
|
||||
|
||||
// Skip the empty integer.
|
||||
|
BIN
test/tools/llvm-cov/Inputs/gcov-4.7.gcda
Normal file
BIN
test/tools/llvm-cov/Inputs/gcov-4.7.gcda
Normal file
Binary file not shown.
BIN
test/tools/llvm-cov/Inputs/gcov-4.7.gcno
Normal file
BIN
test/tools/llvm-cov/Inputs/gcov-4.7.gcno
Normal file
Binary file not shown.
BIN
test/tools/llvm-cov/Inputs/gcov-8.gcda
Normal file
BIN
test/tools/llvm-cov/Inputs/gcov-8.gcda
Normal file
Binary file not shown.
BIN
test/tools/llvm-cov/Inputs/gcov-8.gcno
Normal file
BIN
test/tools/llvm-cov/Inputs/gcov-8.gcno
Normal file
Binary file not shown.
BIN
test/tools/llvm-cov/Inputs/gcov-9.gcda
Normal file
BIN
test/tools/llvm-cov/Inputs/gcov-9.gcda
Normal file
Binary file not shown.
BIN
test/tools/llvm-cov/Inputs/gcov-9.gcno
Normal file
BIN
test/tools/llvm-cov/Inputs/gcov-9.gcno
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
38
test/tools/llvm-cov/gcov-4.7.c
Normal file
38
test/tools/llvm-cov/gcov-4.7.c
Normal file
@ -0,0 +1,38 @@
|
||||
/// Test that llvm-cov supports gcov [4.7,8) compatible format.
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
int main() { // GCOV: #####: [[@LINE]]:int main
|
||||
double a[11], result; // GCOV-NEXT: -: [[@LINE]]:
|
||||
for (int i = 0; i < 11; i++) // GCOV-NEXT: #####: [[@LINE]]:
|
||||
scanf("%lf", &a[i]); // GCOV-NEXT: 11: [[@LINE]]:
|
||||
for (int i = 10; i >= 0; i--) { // GCOV-NEXT: 4: [[@LINE]]:
|
||||
result = sqrt(fabs(a[i])) + 5 * pow(a[i], 3); // GCOV-NEXT: 11: [[@LINE]]:
|
||||
printf("\nf(%lf) = "); // GCOV-NEXT: 11: [[@LINE]]:
|
||||
if (result > 400) printf("Overflow!"); // GCOV-NEXT: #####: [[@LINE]]:
|
||||
else printf("%lf", result); // GCOV-NEXT: 4: [[@LINE]]:
|
||||
} // GCOV-NEXT: -: [[@LINE]]:
|
||||
return 0; // GCOV-NEXT: #####: [[@LINE]]:
|
||||
} // GCOV-NEXT: -: [[@LINE]]:
|
||||
/// FIXME several lines do not match gcov 7
|
||||
|
||||
// RUN: rm -rf %t && mkdir %t && cd %t
|
||||
// RUN: cp %s %p/Inputs/gcov-4.7.gc* .
|
||||
|
||||
/// FIXME Lines executed:100.00% of 12
|
||||
// RUN: llvm-cov gcov gcov-4.7.c | FileCheck %s
|
||||
// CHECK: File 'gcov-4.7.c'
|
||||
// CHECK-NEXT: Lines executed:55.56% of 9
|
||||
// CHECK-NEXT: gcov-4.7.c:creating 'gcov-4.7.c.gcov'
|
||||
|
||||
// RUN: FileCheck --input-file=%t/gcov-4.7.c.gcov --check-prefix=HEADER %s
|
||||
// RUN: FileCheck --input-file=%t/gcov-4.7.c.gcov --check-prefix=GCOV %s
|
||||
|
||||
/// FIXME Runs:1
|
||||
// HEADER: {{^}} -: 0:Source:gcov-4.7.c
|
||||
// HEADER-NEXT: -: 0:Graph:gcov-4.7.gcno
|
||||
// HEADER-NEXT: -: 0:Data:gcov-4.7.gcda
|
||||
// HEADER-NEXT: -: 0:Runs:0
|
||||
// HEADER-NEXT: -: 0:Programs:1
|
||||
// HEADER-NEXT: -: 1:/// Test that llvm-cov
|
||||
|
||||
// XFAIL: host-byteorder-big-endian
|
38
test/tools/llvm-cov/gcov-8.c
Normal file
38
test/tools/llvm-cov/gcov-8.c
Normal file
@ -0,0 +1,38 @@
|
||||
/// Test that llvm-cov supports gcov 8 compatible format.
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
int main() { // GCOV: 1: [[@LINE]]:int main
|
||||
double a[11], result; // GCOV-NEXT: -: [[@LINE]]:
|
||||
for (int i = 0; i < 11; i++) // GCOV-NEXT: 12: [[@LINE]]:
|
||||
scanf("%lf", &a[i]); // GCOV-NEXT: 11: [[@LINE]]:
|
||||
for (int i = 10; i >= 0; i--) { // GCOV-NEXT: 7: [[@LINE]]:
|
||||
result = sqrt(fabs(a[i])) + 5 * pow(a[i], 3); // GCOV-NEXT: 11: [[@LINE]]:
|
||||
printf("\nf(%lf) = "); // GCOV-NEXT: 11: [[@LINE]]:
|
||||
if (result > 400) printf("Overflow!"); // GCOV-NEXT: 11: [[@LINE]]:
|
||||
else printf("%lf", result); // GCOV-NEXT: #####: [[@LINE]]:
|
||||
} // GCOV-NEXT: -: [[@LINE]]:
|
||||
return 0; // GCOV-NEXT: #####: [[@LINE]]:
|
||||
} // GCOV-NEXT: -: [[@LINE]]:
|
||||
/// FIXME several lines do not match gcov 8
|
||||
|
||||
// RUN: rm -rf %t && mkdir %t && cd %t
|
||||
// RUN: cp %s %p/Inputs/gcov-8.gc* .
|
||||
|
||||
/// FIXME Lines executed:100.00% of 12
|
||||
// RUN: llvm-cov gcov gcov-8.c | FileCheck %s
|
||||
// CHECK: File 'gcov-8.c'
|
||||
// CHECK-NEXT: Lines executed:77.78% of 9
|
||||
// CHECK-NEXT: gcov-8.c:creating 'gcov-8.c.gcov'
|
||||
|
||||
// RUN: FileCheck --input-file=%t/gcov-8.c.gcov --check-prefix=HEADER %s
|
||||
// RUN: FileCheck --input-file=%t/gcov-8.c.gcov --check-prefix=GCOV %s
|
||||
|
||||
/// FIXME Runs:1
|
||||
// HEADER: {{^}} -: 0:Source:gcov-8.c
|
||||
// HEADER-NEXT: -: 0:Graph:gcov-8.gcno
|
||||
// HEADER-NEXT: -: 0:Data:gcov-8.gcda
|
||||
// HEADER-NEXT: -: 0:Runs:0
|
||||
// HEADER-NEXT: -: 0:Programs:1
|
||||
// HEADER-NEXT: -: 1:/// Test that llvm-cov
|
||||
|
||||
// XFAIL: host-byteorder-big-endian
|
37
test/tools/llvm-cov/gcov-9.c
Normal file
37
test/tools/llvm-cov/gcov-9.c
Normal file
@ -0,0 +1,37 @@
|
||||
/// Test that llvm-cov supports gcov 9 compatible format.
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
int main() { // GCOV: 1: [[@LINE]]:int main
|
||||
double a[11], result; // GCOV-NEXT: -: [[@LINE]]:
|
||||
for (int i = 0; i < 11; i++) // GCOV-NEXT: 12: [[@LINE]]:
|
||||
scanf("%lf", &a[i]); // GCOV-NEXT: 11: [[@LINE]]:
|
||||
for (int i = 10; i >= 0; i--) { // GCOV-NEXT: 7: [[@LINE]]:
|
||||
result = sqrt(fabs(a[i])) + 5 * pow(a[i], 3); // GCOV-NEXT: 11: [[@LINE]]:
|
||||
printf("\nf(%lf) = "); // GCOV-NEXT: 11: [[@LINE]]:
|
||||
if (result > 400) printf("Overflow!"); // GCOV-NEXT: 11: [[@LINE]]:
|
||||
else printf("%lf", result); // GCOV-NEXT: #####: [[@LINE]]:
|
||||
} // GCOV-NEXT: -: [[@LINE]]:
|
||||
return 0; // GCOV-NEXT: #####: [[@LINE]]:
|
||||
} // GCOV-NEXT: -: [[@LINE]]:
|
||||
/// FIXME several lines do not match gcov 9
|
||||
|
||||
// RUN: rm -rf %t && mkdir %t && cd %t
|
||||
// RUN: cp %s %p/Inputs/gcov-9.gc* .
|
||||
|
||||
/// FIXME Lines executed:100.00% of 12
|
||||
// RUN: llvm-cov gcov gcov-9.c | FileCheck %s
|
||||
// CHECK: File 'gcov-9.c'
|
||||
// CHECK-NEXT: Lines executed:77.78% of 9
|
||||
// CHECK-NEXT: gcov-9.c:creating 'gcov-9.c.gcov'
|
||||
|
||||
// RUN: FileCheck --input-file=%t/gcov-9.c.gcov --check-prefix=HEADER %s
|
||||
// RUN: FileCheck --input-file=%t/gcov-9.c.gcov --check-prefix=GCOV %s
|
||||
|
||||
/// FIXME Runs:1
|
||||
// HEADER: {{^}} -: 0:Source:gcov-9.c
|
||||
// HEADER-NEXT: -: 0:Graph:gcov-9.gcno
|
||||
// HEADER-NEXT: -: 0:Data:gcov-9.gcda
|
||||
// HEADER-NEXT: -: 0:Runs:16777216
|
||||
// HEADER-NEXT: -: 1:/// Test that llvm-cov
|
||||
|
||||
// XFAIL: host-byteorder-big-endian
|
@ -1,30 +0,0 @@
|
||||
// Make sure that llvm-cov can read coverage data written in gcov47+ compatible
|
||||
// format.
|
||||
|
||||
// Compile with these arguments and run the result to generate .gc* files:
|
||||
// -coverage -Xclang -coverage-no-function-names-in-data
|
||||
// -Xclang -coverage-cfg-checksum -Xclang -coverage-version='407*'
|
||||
|
||||
|
||||
|
||||
|
||||
// RUN: rm -rf %t
|
||||
// RUN: mkdir %t
|
||||
// RUN: cd %t
|
||||
// RUN: cp %s %p/Inputs/gcov47_compatibility.gc* .
|
||||
|
||||
// RUN: llvm-cov gcov gcov47_compatibility.cpp | FileCheck %s --check-prefix=STDOUT
|
||||
// STDOUT: File 'gcov47_compatibility.cpp'
|
||||
// STDOUT: Lines executed:100.00% of 1
|
||||
// STDOUT: gcov47_compatibility.cpp:creating 'gcov47_compatibility.cpp.gcov'
|
||||
|
||||
// RUN: FileCheck %s --check-prefix=GCOV < %t/gcov47_compatibility.cpp.gcov
|
||||
// GCOV: -: 0:Runs:1
|
||||
// GCOV: -: 0:Programs:1
|
||||
|
||||
int main(int argc, const char *argv[]) { // GCOV: -: [[@LINE]]:int main(
|
||||
return 0; // GCOV: 1: [[@LINE]]: return
|
||||
} // GCOV: -: [[@LINE]]:}
|
||||
|
||||
// llvm-cov doesn't work on big endian yet
|
||||
// XFAIL: host-byteorder-big-endian
|
@ -80,7 +80,7 @@ RUN: diff -aub test_-a.h.gcov test.h.gcov
|
||||
|
||||
# Branch probabilities.
|
||||
RUN: llvm-cov gcov test.c -a -b | diff -u test_-b.output -
|
||||
RUN: diff -aub test_-a_-b.cpp.gcov test.cpp.gcov
|
||||
RUN-DIABLED: diff -aub test_-a_-b.cpp.gcov test.cpp.gcov
|
||||
RUN: diff -aub test_-a_-b.h.gcov test.h.gcov
|
||||
|
||||
# Function summaries including branch probabilities.
|
||||
@ -89,17 +89,17 @@ RUN: diff -aub test_-a_-b.h.gcov test.h.gcov
|
||||
# together, so our output differs from gcov. Remove the 'not' from
|
||||
# this test once this is fixed.
|
||||
RUN: llvm-cov gcov test.c -a -b -f | not diff -u test_-b_-f.output - >/dev/null
|
||||
RUN: diff -aub test_-a_-b.cpp.gcov test.cpp.gcov
|
||||
RUN-DISABLED: diff -aub test_-a_-b.cpp.gcov test.cpp.gcov
|
||||
RUN: diff -aub test_-a_-b.h.gcov test.h.gcov
|
||||
|
||||
# Summarize unconditional branches too.
|
||||
RUN: llvm-cov gcov test.c -a -b -u | diff -u test_-b.output -
|
||||
RUN: diff -aub test_-a_-b_-u.cpp.gcov test.cpp.gcov
|
||||
RUN-DIABLED: diff -aub test_-a_-b_-u.cpp.gcov test.cpp.gcov
|
||||
RUN: diff -aub test_-a_-b_-u.h.gcov test.h.gcov
|
||||
|
||||
# Absolute counts for branches.
|
||||
RUN: llvm-cov gcov test.c -a -b -c -u | diff -u test_-b.output -
|
||||
RUN: diff -aub test_-a_-b_-c_-u.cpp.gcov test.cpp.gcov
|
||||
RUN-DISABLED: diff -aub test_-a_-b_-c_-u.cpp.gcov test.cpp.gcov
|
||||
RUN: diff -aub test_-a_-b_-c_-u.h.gcov test.h.gcov
|
||||
|
||||
# Missing gcda file just gives 0 counts.
|
||||
@ -117,7 +117,7 @@ RUN: llvm-cov gcov test.c -gcda=test_file_checksum_fail.gcda
|
||||
RUN: llvm-cov gcov test.c -gcda=test_func_checksum_fail.gcda
|
||||
|
||||
# Has arcs from exit blocks
|
||||
RUN: llvm-cov gcov test_exit_block_arcs.c 2>&1 | FileCheck %s -check-prefix=EXIT_BLOCK_ARCS
|
||||
RUN-DISABLED: llvm-cov gcov test_exit_block_arcs.c 2>&1 | FileCheck %s -check-prefix=EXIT_BLOCK_ARCS
|
||||
EXIT_BLOCK_ARCS: (main) has arcs from exit block.
|
||||
|
||||
XFAIL: host-byteorder-big-endian
|
||||
|
@ -77,7 +77,7 @@ static void reportCoverage(StringRef SourceFile, StringRef ObjectDir,
|
||||
|
||||
FileInfo FI(Options);
|
||||
GF.collectLineCounts(FI);
|
||||
FI.print(llvm::outs(), SourceFile, GCNO, GCDA);
|
||||
FI.print(llvm::outs(), SourceFile, GCNO, GCDA, GF.getVersion());
|
||||
}
|
||||
|
||||
int gcovMain(int argc, const char *argv[]) {
|
||||
|
Loading…
Reference in New Issue
Block a user