Skip to content

[llvm-cov][gcov] Support multi-files coverage in one basic block #144504

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions compiler-rt/test/profile/Posix/gcov-file-change-line.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// RUN: rm -rf %t && split-file %s %t && cd %t
// RUN: %clangxx --coverage main.cpp -o t
// RUN: %run ./t
// RUN: llvm-cov gcov -t t-main. | FileCheck %s

//--- main.cpp
#include <stdio.h>

int main(int argc, char *argv[]) { // CHECK: 2: [[#]]:int main
puts(""); // CHECK-NEXT: 2: [[#]]:
#line 3
puts(""); // line 3
return 0; // line 4
}
// CHECK-NOT: {{^ +[0-9]+:}}
12 changes: 5 additions & 7 deletions compiler-rt/test/profile/Posix/gcov-file-change.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ inline auto *const inl_var_main = // CHECK: 1: [[#]]:inline auto
void foo(int x) { // CHECK-NEXT: 1: [[#]]:
if (x) { // CHECK-NEXT: 1: [[#]]:
#include "a.inc"
}
}
} // CHECK: 1: [[#]]:
} // CHECK-NEXT: 1: [[#]]:
// CHECK-NOT: {{^ +[0-9]+:}}

int main(int argc, char *argv[]) { // CHECK: 1: [[#]]:int main
Expand All @@ -32,10 +32,8 @@ int main(int argc, char *argv[]) { // CHECK: 1: [[#]]:int main
//--- a.h
/// Apple targets doesn't enable -mconstructor-aliases by default and the count may be 4.
struct A { A() { } }; // CHECK: {{[24]}}: [[#]]:struct A
inline auto *const inl_var_a =
new A;
/// TODO a.inc:1 should have line execution.
// CHECK-NOT: {{^ +[0-9]+:}}
inline auto *const inl_var_a = // CHECK-NEXT: 1: [[#]]:
new A; // CHECK-NEXT: 1: [[#]]:

//--- a.inc
puts("");
puts(""); // CHECK: 1: [[#]]:puts
20 changes: 17 additions & 3 deletions llvm/include/llvm/ProfileData/GCOV.h
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,14 @@ class GCOVFunction {
DenseSet<const GCOVBlock *> visited;
};

/// Represent file of lines same with block_location_info in gcc.
struct GCOVBlockLocation {
GCOVBlockLocation(unsigned idx) : srcIdx(idx) {}

unsigned srcIdx;
SmallVector<uint32_t, 4> lines;
};

/// GCOVBlock - Collects block information.
class GCOVBlock {
public:
Expand All @@ -281,8 +289,13 @@ class GCOVBlock {

GCOVBlock(uint32_t N) : number(N) {}

void addLine(uint32_t N) { lines.push_back(N); }
uint32_t getLastLine() const { return lines.back(); }
void addLine(uint32_t N) {
locations.back().lines.push_back(N);
lastLine = N;
}
void addFile(unsigned fileIdx) { locations.emplace_back(fileIdx); }

uint32_t getLastLine() const { return lastLine; }
uint64_t getCount() const { return count; }

void addSrcEdge(GCOVArc *Edge) { pred.push_back(Edge); }
Expand Down Expand Up @@ -311,7 +324,8 @@ class GCOVBlock {
uint64_t count = 0;
SmallVector<GCOVArc *, 2> pred;
SmallVector<GCOVArc *, 2> succ;
SmallVector<uint32_t, 4> lines;
SmallVector<GCOVBlockLocation> locations;
uint32_t lastLine = 0;
bool traversable = false;
GCOVArc *incoming = nullptr;
};
Expand Down
45 changes: 26 additions & 19 deletions llvm/lib/ProfileData/GCOV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ bool GCOVFile::readGCNO(GCOVBuffer &buf) {
buf.readString(filename);
if (filename.empty())
break;
// TODO Unhandled
Block.addFile(addNormalizedPathToMap(filename));
}
}
}
Expand Down Expand Up @@ -456,11 +456,13 @@ void GCOVBlock::print(raw_ostream &OS) const {
}
OS << "\n";
}
if (!lines.empty()) {
OS << "\tLines : ";
for (uint32_t N : lines)
OS << (N) << ",";
OS << "\n";
if (!locations.empty()) {
for (const GCOVBlockLocation &loc : locations) {
OS << "\tFile: " << loc.srcIdx << ": ";
for (uint32_t N : loc.lines)
OS << (N) << ",";
OS << "\n";
}
}
}

Expand Down Expand Up @@ -701,20 +703,25 @@ void Context::collectFunction(GCOVFunction &f, Summary &summary) {
SmallSet<uint32_t, 16> lines;
SmallSet<uint32_t, 16> linesExec;
for (const GCOVBlock &b : f.blocksRange()) {
if (b.lines.empty())
if (b.locations.empty())
continue;
uint32_t maxLineNum = *llvm::max_element(b.lines);
if (maxLineNum >= si.lines.size())
si.lines.resize(maxLineNum + 1);
for (uint32_t lineNum : b.lines) {
LineInfo &line = si.lines[lineNum];
if (lines.insert(lineNum).second)
++summary.lines;
if (b.count && linesExec.insert(lineNum).second)
++summary.linesExec;
line.exists = true;
line.count += b.count;
line.blocks.push_back(&b);
for (const GCOVBlockLocation &loc : b.locations) {
SourceInfo &locSource = sources[loc.srcIdx];
uint32_t maxLineNum = *llvm::max_element(loc.lines);
if (maxLineNum >= locSource.lines.size())
locSource.lines.resize(maxLineNum + 1);
for (uint32_t lineNum : loc.lines) {
LineInfo &line = locSource.lines[lineNum];
line.exists = true;
line.count += b.count;
line.blocks.push_back(&b);
if (f.srcIdx == loc.srcIdx) {
if (lines.insert(lineNum).second)
++summary.lines;
if (b.count && linesExec.insert(lineNum).second)
++summary.linesExec;
}
}
}
}
}
Expand Down
37 changes: 17 additions & 20 deletions llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,12 +210,12 @@ static StringRef getFunctionName(const DISubprogram *SP) {
return SP->getName();
}

/// Extract a filename for a DISubprogram.
/// Extract a filename for a DIScope.
///
/// Prefer relative paths in the coverage notes. Clang also may split
/// up absolute paths into a directory and filename component. When
/// the relative path doesn't exist, reconstruct the absolute path.
static SmallString<128> getFilename(const DISubprogram *SP) {
static SmallString<128> getFilename(const DIScope *SP) {
SmallString<128> Path;
StringRef RelPath = SP->getFilename();
if (sys::fs::exists(RelPath))
Expand Down Expand Up @@ -244,7 +244,9 @@ namespace {
// list of line numbers and a single filename, representing lines that belong
// to the block.
class GCOVLines : public GCOVRecord {
public:
public:
const StringRef getFilename() { return Filename; }

void addLine(uint32_t Line) {
assert(Line != 0 && "Line zero is not a valid real line number.");
Lines.push_back(Line);
Expand Down Expand Up @@ -276,7 +278,9 @@ namespace {
class GCOVBlock : public GCOVRecord {
public:
GCOVLines &getFile(StringRef Filename) {
return LinesByFile.try_emplace(Filename, P, Filename).first->second;
if (Lines.empty() || Lines.back().getFilename() != Filename)
Lines.emplace_back(P, Filename);
return Lines.back();
}

void addEdge(GCOVBlock &Successor, uint32_t Flags) {
Expand All @@ -285,22 +289,16 @@ namespace {

void writeOut() {
uint32_t Len = 3;
SmallVector<StringMapEntry<GCOVLines> *, 32> SortedLinesByFile;
for (auto &I : LinesByFile) {
Len += I.second.length();
SortedLinesByFile.push_back(&I);
}

for (auto &L : Lines)
Len += L.length();

write(GCOV_TAG_LINES);
write(Len);
write(Number);

llvm::sort(SortedLinesByFile, [](StringMapEntry<GCOVLines> *LHS,
StringMapEntry<GCOVLines> *RHS) {
return LHS->getKey() < RHS->getKey();
});
for (auto &I : SortedLinesByFile)
I->getValue().writeOut();
for (auto &L : Lines)
L.writeOut();
write(0);
write(0);
}
Expand All @@ -309,7 +307,7 @@ namespace {
// Only allow copy before edges and lines have been added. After that,
// there are inter-block pointers (eg: edges) that won't take kindly to
// blocks being copied or moved around.
assert(LinesByFile.empty());
assert(Lines.empty());
assert(OutEdges.empty());
}

Expand All @@ -322,7 +320,7 @@ namespace {
GCOVBlock(GCOVProfiler *P, uint32_t Number)
: GCOVRecord(P), Number(Number) {}

StringMap<GCOVLines> LinesByFile;
SmallVector<GCOVLines> Lines;
};

// A function has a unique identifier, a checksum (we leave as zero) and a
Expand Down Expand Up @@ -889,11 +887,10 @@ bool GCOVProfiler::emitProfileNotes(
if (Line == Loc.getLine()) continue;
Line = Loc.getLine();
MDNode *Scope = Loc.getScope();
// TODO: Handle blocks from another file due to #line, #include, etc.
if (isa<DILexicalBlockFile>(Scope) || SP != getDISubprogram(Scope))
if (SP != getDISubprogram(Scope))
continue;

GCOVLines &Lines = Block.getFile(Filename);
GCOVLines &Lines = Block.getFile(getFilename(Loc->getScope()));
Lines.addLine(Loc.getLine());
}
Line = 0;
Expand Down
Loading