[compiler-rt] [llvm] [llvm-cov][gcov] Support multi-files coverage in one basic block (PR #144504)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Jun 18 23:08:07 PDT 2025
https://github.com/int-zjt updated https://github.com/llvm/llvm-project/pull/144504
>From d46859be121c1107f246cfeca5cbb74673eb8147 Mon Sep 17 00:00:00 2001
From: int-zjt <zhangjiatong.0 at bytedance.com>
Date: Sun, 15 Jun 2025 23:13:59 +0800
Subject: [PATCH 1/2] [llvm-cov][gcov] Support multi-files in one block
---
.../profile/Posix/gcov-file-change-line.cpp | 15 +++++++
.../test/profile/Posix/gcov-file-change.cpp | 12 +++--
llvm/include/llvm/ProfileData/GCOV.h | 22 +++++++--
llvm/lib/ProfileData/GCOV.cpp | 45 +++++++++++--------
.../Instrumentation/GCOVProfiling.cpp | 37 +++++++--------
5 files changed, 82 insertions(+), 49 deletions(-)
create mode 100644 compiler-rt/test/profile/Posix/gcov-file-change-line.cpp
diff --git a/compiler-rt/test/profile/Posix/gcov-file-change-line.cpp b/compiler-rt/test/profile/Posix/gcov-file-change-line.cpp
new file mode 100644
index 0000000000000..a750befb47e50
--- /dev/null
+++ b/compiler-rt/test/profile/Posix/gcov-file-change-line.cpp
@@ -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]+:}}
diff --git a/compiler-rt/test/profile/Posix/gcov-file-change.cpp b/compiler-rt/test/profile/Posix/gcov-file-change.cpp
index 9d3bc79591f27..963f8c873d957 100644
--- a/compiler-rt/test/profile/Posix/gcov-file-change.cpp
+++ b/compiler-rt/test/profile/Posix/gcov-file-change.cpp
@@ -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
@@ -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: 1: [[#]]:
+ new A; // CHECK: 1: [[#]]:
//--- a.inc
-puts("");
+puts(""); // CHECK: 1: [[#]]:puts
diff --git a/llvm/include/llvm/ProfileData/GCOV.h b/llvm/include/llvm/ProfileData/GCOV.h
index 0dc33d062e4f8..899b9cf6c44f3 100644
--- a/llvm/include/llvm/ProfileData/GCOV.h
+++ b/llvm/include/llvm/ProfileData/GCOV.h
@@ -271,6 +271,16 @@ class GCOVFunction {
DenseSet<const GCOVBlock *> visited;
};
+/// GCOVLocation - Represent file of lines same with block_location_info in gcc.
+class GCOVLocation {
+public:
+ GCOVLocation(unsigned idx) : srcIdx(idx) {}
+
+public:
+ unsigned srcIdx;
+ SmallVector<uint32_t, 4> lines;
+};
+
/// GCOVBlock - Collects block information.
class GCOVBlock {
public:
@@ -281,8 +291,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); }
@@ -311,7 +326,8 @@ class GCOVBlock {
uint64_t count = 0;
SmallVector<GCOVArc *, 2> pred;
SmallVector<GCOVArc *, 2> succ;
- SmallVector<uint32_t, 4> lines;
+ SmallVector<GCOVLocation, 4> locations;
+ uint32_t lastLine;
bool traversable = false;
GCOVArc *incoming = nullptr;
};
diff --git a/llvm/lib/ProfileData/GCOV.cpp b/llvm/lib/ProfileData/GCOV.cpp
index ecb12c045b5b1..b586ee585eb8e 100644
--- a/llvm/lib/ProfileData/GCOV.cpp
+++ b/llvm/lib/ProfileData/GCOV.cpp
@@ -191,7 +191,7 @@ bool GCOVFile::readGCNO(GCOVBuffer &buf) {
buf.readString(filename);
if (filename.empty())
break;
- // TODO Unhandled
+ Block.addFile(addNormalizedPathToMap(filename));
}
}
}
@@ -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 GCOVLocation &loc : locations) {
+ OS << "\tFile: " << loc.srcIdx << ": ";
+ for (uint32_t N : loc.lines)
+ OS << (N) << ",";
+ OS << "\n";
+ }
}
}
@@ -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 GCOVLocation &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;
+ }
+ }
}
}
}
diff --git a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
index 9351a42581ba0..7ac3503a90473 100644
--- a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
+++ b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
@@ -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))
@@ -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);
@@ -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) {
@@ -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);
}
@@ -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());
}
@@ -322,7 +320,7 @@ namespace {
GCOVBlock(GCOVProfiler *P, uint32_t Number)
: GCOVRecord(P), Number(Number) {}
- StringMap<GCOVLines> LinesByFile;
+ SmallVector<GCOVLines, 4> Lines;
};
// A function has a unique identifier, a checksum (we leave as zero) and a
@@ -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;
>From 38357ade18e0e5d2174a194ffaf95440a75bc70d Mon Sep 17 00:00:00 2001
From: int-zjt <zhangjiatong.0 at bytedance.com>
Date: Thu, 19 Jun 2025 14:03:32 +0800
Subject: [PATCH 2/2] Address comments
---
compiler-rt/test/profile/Posix/gcov-file-change.cpp | 4 ++--
llvm/include/llvm/ProfileData/GCOV.h | 10 ++++------
llvm/lib/ProfileData/GCOV.cpp | 4 ++--
llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp | 2 +-
4 files changed, 9 insertions(+), 11 deletions(-)
diff --git a/compiler-rt/test/profile/Posix/gcov-file-change.cpp b/compiler-rt/test/profile/Posix/gcov-file-change.cpp
index 963f8c873d957..0cef1c3512f88 100644
--- a/compiler-rt/test/profile/Posix/gcov-file-change.cpp
+++ b/compiler-rt/test/profile/Posix/gcov-file-change.cpp
@@ -32,8 +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 = // CHECK: 1: [[#]]:
- new A; // CHECK: 1: [[#]]:
+inline auto *const inl_var_a = // CHECK-NEXT: 1: [[#]]:
+ new A; // CHECK-NEXT: 1: [[#]]:
//--- a.inc
puts(""); // CHECK: 1: [[#]]:puts
diff --git a/llvm/include/llvm/ProfileData/GCOV.h b/llvm/include/llvm/ProfileData/GCOV.h
index 899b9cf6c44f3..0186b79759612 100644
--- a/llvm/include/llvm/ProfileData/GCOV.h
+++ b/llvm/include/llvm/ProfileData/GCOV.h
@@ -271,12 +271,10 @@ class GCOVFunction {
DenseSet<const GCOVBlock *> visited;
};
-/// GCOVLocation - Represent file of lines same with block_location_info in gcc.
-class GCOVLocation {
-public:
- GCOVLocation(unsigned idx) : srcIdx(idx) {}
+/// Represent file of lines same with block_location_info in gcc.
+struct GCOVBlockLocation {
+ GCOVBlockLocation(unsigned idx) : srcIdx(idx) {}
-public:
unsigned srcIdx;
SmallVector<uint32_t, 4> lines;
};
@@ -326,7 +324,7 @@ class GCOVBlock {
uint64_t count = 0;
SmallVector<GCOVArc *, 2> pred;
SmallVector<GCOVArc *, 2> succ;
- SmallVector<GCOVLocation, 4> locations;
+ SmallVector<GCOVBlockLocation> locations;
uint32_t lastLine;
bool traversable = false;
GCOVArc *incoming = nullptr;
diff --git a/llvm/lib/ProfileData/GCOV.cpp b/llvm/lib/ProfileData/GCOV.cpp
index b586ee585eb8e..7d0a243d02388 100644
--- a/llvm/lib/ProfileData/GCOV.cpp
+++ b/llvm/lib/ProfileData/GCOV.cpp
@@ -457,7 +457,7 @@ void GCOVBlock::print(raw_ostream &OS) const {
OS << "\n";
}
if (!locations.empty()) {
- for (const GCOVLocation &loc : locations) {
+ for (const GCOVBlockLocation &loc : locations) {
OS << "\tFile: " << loc.srcIdx << ": ";
for (uint32_t N : loc.lines)
OS << (N) << ",";
@@ -705,7 +705,7 @@ void Context::collectFunction(GCOVFunction &f, Summary &summary) {
for (const GCOVBlock &b : f.blocksRange()) {
if (b.locations.empty())
continue;
- for (const GCOVLocation &loc : b.locations) {
+ for (const GCOVBlockLocation &loc : b.locations) {
SourceInfo &locSource = sources[loc.srcIdx];
uint32_t maxLineNum = *llvm::max_element(loc.lines);
if (maxLineNum >= locSource.lines.size())
diff --git a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
index 7ac3503a90473..7812cd08b36ad 100644
--- a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
+++ b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
@@ -320,7 +320,7 @@ namespace {
GCOVBlock(GCOVProfiler *P, uint32_t Number)
: GCOVRecord(P), Number(Number) {}
- SmallVector<GCOVLines, 4> Lines;
+ SmallVector<GCOVLines> Lines;
};
// A function has a unique identifier, a checksum (we leave as zero) and a
More information about the llvm-commits
mailing list