[llvm] 0873016 - [llvm-cov gcov] Support GCC 12 format
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Sat Jun 19 22:51:34 PDT 2021
Author: Fangrui Song
Date: 2021-06-19T22:51:20-07:00
New Revision: 0873016ceff3ded84bfeaa37b39be675fa178f7d
URL: https://github.com/llvm/llvm-project/commit/0873016ceff3ded84bfeaa37b39be675fa178f7d
DIFF: https://github.com/llvm/llvm-project/commit/0873016ceff3ded84bfeaa37b39be675fa178f7d.diff
LOG: [llvm-cov gcov] Support GCC 12 format
GCC 12 will change the length field to represent the number of bytes instead of
32-bit words. This avoids padding for strings.
Added:
llvm/test/tools/llvm-cov/gcov/Inputs/gcov-12.gcda
llvm/test/tools/llvm-cov/gcov/Inputs/gcov-12.gcno
llvm/test/tools/llvm-cov/gcov/gcov-12.c
Modified:
llvm/include/llvm/ProfileData/GCOV.h
llvm/lib/ProfileData/GCOV.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/ProfileData/GCOV.h b/llvm/include/llvm/ProfileData/GCOV.h
index 01db686819d7b..ef6515d391440 100644
--- a/llvm/include/llvm/ProfileData/GCOV.h
+++ b/llvm/include/llvm/ProfileData/GCOV.h
@@ -42,7 +42,7 @@ class GCOVBlock;
namespace GCOV {
-enum GCOVVersion { V304, V407, V408, V800, V900 };
+enum GCOVVersion { V304, V407, V408, V800, V900, V1200 };
/// A struct for passing gcov options between functions.
struct Options {
@@ -108,7 +108,7 @@ class GCOVBuffer {
}
/// readGCOVVersion - Read GCOV version.
- bool readGCOVVersion(GCOV::GCOVVersion &Version) {
+ bool readGCOVVersion(GCOV::GCOVVersion &version) {
std::string str(de.getBytes(cursor, 4));
if (str.size() != 4)
return false;
@@ -117,24 +117,27 @@ class GCOVBuffer {
int ver = str[0] >= 'A'
? (str[0] - 'A') * 100 + (str[1] - '0') * 10 + str[2] - '0'
: (str[0] - '0') * 10 + str[2] - '0';
- if (ver >= 90) {
+ if (ver >= 120) {
+ this->version = version = GCOV::V1200;
+ return true;
+ } else if (ver >= 90) {
// PR gcov-profile/84846, r269678
- Version = GCOV::V900;
+ this->version = version = GCOV::V900;
return true;
} else if (ver >= 80) {
// PR gcov-profile/48463
- Version = GCOV::V800;
+ this->version = version = GCOV::V800;
return true;
} else if (ver >= 48) {
// r189778: the exit block moved from the last to the second.
- Version = GCOV::V408;
+ this->version = version = GCOV::V408;
return true;
} else if (ver >= 47) {
// r173147: split checksum into cfg checksum and line checksum.
- Version = GCOV::V407;
+ this->version = version = GCOV::V407;
return true;
} else if (ver >= 34) {
- Version = GCOV::V304;
+ this->version = version = GCOV::V304;
return true;
}
errs() << "unexpected version: " << str << "\n";
@@ -167,11 +170,14 @@ class GCOVBuffer {
return true;
}
- bool readString(StringRef &Str) {
+ bool readString(StringRef &str) {
uint32_t len;
if (!readInt(len) || len == 0)
return false;
- Str = de.getBytes(cursor, len * 4).split('\0').first;
+ if (version >= GCOV::V1200)
+ str = de.getBytes(cursor, len).drop_back();
+ else
+ str = de.getBytes(cursor, len * 4).split('\0').first;
return bool(cursor);
}
@@ -180,6 +186,7 @@ class GCOVBuffer {
private:
MemoryBuffer *Buffer;
+ GCOV::GCOVVersion version{};
};
/// GCOVFile - Collects coverage information for one pair of coverage file
@@ -199,7 +206,7 @@ class GCOVFile {
public:
bool GCNOInitialized = false;
- GCOV::GCOVVersion version;
+ GCOV::GCOVVersion version{};
uint32_t checksum = 0;
StringRef cwd;
SmallVector<std::unique_ptr<GCOVFunction>, 16> functions;
diff --git a/llvm/lib/ProfileData/GCOV.cpp b/llvm/lib/ProfileData/GCOV.cpp
index f3095cf7fcca9..afef71f5b5ad0 100644
--- a/llvm/lib/ProfileData/GCOV.cpp
+++ b/llvm/lib/ProfileData/GCOV.cpp
@@ -115,6 +115,7 @@ bool GCOVFile::readGCNO(GCOVBuffer &buf) {
while ((tag = buf.getWord())) {
if (!buf.readInt(length))
return false;
+ uint32_t pos = buf.cursor.tell();
if (tag == GCOV_TAG_FUNCTION) {
functions.push_back(std::make_unique<GCOVFunction>(*this));
fn = functions.back().get();
@@ -162,7 +163,9 @@ bool GCOVFile::readGCNO(GCOVBuffer &buf) {
return false;
}
GCOVBlock *src = fn->blocks[srcNo].get();
- for (uint32_t i = 0, e = (length - 1) / 2; i != e; ++i) {
+ const uint32_t e =
+ version >= GCOV::V1200 ? (length / 4 - 1) / 2 : (length - 1) / 2;
+ for (uint32_t i = 0; i != e; ++i) {
uint32_t dstNo = buf.getWord(), flags = buf.getWord();
GCOVBlock *dst = fn->blocks[dstNo].get();
auto arc = std::make_unique<GCOVArc>(*src, *dst, flags);
@@ -194,6 +197,10 @@ bool GCOVFile::readGCNO(GCOVBuffer &buf) {
}
}
}
+ pos += version >= GCOV::V1200 ? length : 4 * length;
+ if (pos < buf.cursor.tell())
+ return false;
+ buf.de.skip(buf.cursor, pos - buf.cursor.tell());
}
GCNOInitialized = true;
@@ -268,11 +275,14 @@ bool GCOVFile::readGCDA(GCOVBuffer &buf) {
}
}
} else if (tag == GCOV_TAG_COUNTER_ARCS && fn) {
- if (length != 2 * fn->arcs.size()) {
+ uint32_t expected = 2 * fn->arcs.size();
+ if (version >= GCOV::V1200)
+ expected *= 4;
+ if (length != expected) {
errs() << fn->Name
<< format(
": GCOV_TAG_COUNTER_ARCS mismatch, got %u, expected %u\n",
- length, unsigned(2 * fn->arcs.size()));
+ length, expected);
return false;
}
for (std::unique_ptr<GCOVArc> &arc : fn->arcs) {
@@ -296,7 +306,7 @@ bool GCOVFile::readGCDA(GCOVBuffer &buf) {
fn->treeArcs[i - 1]->src.count += fn->treeArcs[i - 1]->count;
}
}
- pos += 4 * length;
+ pos += version >= GCOV::V1200 ? length : 4 * length;
if (pos < buf.cursor.tell())
return false;
buf.de.skip(buf.cursor, pos - buf.cursor.tell());
diff --git a/llvm/test/tools/llvm-cov/gcov/Inputs/gcov-12.gcda b/llvm/test/tools/llvm-cov/gcov/Inputs/gcov-12.gcda
new file mode 100644
index 0000000000000..8ceec1db53a47
Binary files /dev/null and b/llvm/test/tools/llvm-cov/gcov/Inputs/gcov-12.gcda
diff er
diff --git a/llvm/test/tools/llvm-cov/gcov/Inputs/gcov-12.gcno b/llvm/test/tools/llvm-cov/gcov/Inputs/gcov-12.gcno
new file mode 100644
index 0000000000000..f91e6258c8b68
Binary files /dev/null and b/llvm/test/tools/llvm-cov/gcov/Inputs/gcov-12.gcno
diff er
diff --git a/llvm/test/tools/llvm-cov/gcov/gcov-12.c b/llvm/test/tools/llvm-cov/gcov/gcov-12.c
new file mode 100644
index 0000000000000..5e754f5b9cccb
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/gcov/gcov-12.c
@@ -0,0 +1,32 @@
+/// Test that llvm-cov supports gcov 12 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: 12: [[@LINE]]:
+ result = sqrt(fabs(a[i])) + 5 * pow(a[i], 3); // GCOV-NEXT: 11: [[@LINE]]:
+ printf("\nf(%d) = ", i); // GCOV-NEXT: 11: [[@LINE]]:
+ if (result > 400) printf("Overflow!"); // GCOV-NEXT: 11: [[@LINE]]:
+ else printf("%lf", result); // GCOV-NEXT: 4: [[@LINE]]:
+ } // GCOV-NEXT: -: [[@LINE]]:
+ return 0; // GCOV-NEXT: 1: [[@LINE]]:
+} // GCOV-NEXT: -: [[@LINE]]:
+
+// RUN: rm -rf %t && mkdir %t && cd %t
+// RUN: cp %s %p/Inputs/gcov-12.gc* .
+
+// RUN: llvm-cov gcov gcov-12.c | FileCheck %s
+// CHECK: File 'gcov-12.c'
+// CHECK-NEXT: Lines executed:100.00% of 9
+// CHECK-NEXT: Creating 'gcov-12.c.gcov'
+
+// RUN: FileCheck --input-file=%t/gcov-12.c.gcov --check-prefix=HEADER %s
+// RUN: FileCheck --input-file=%t/gcov-12.c.gcov --check-prefix=GCOV %s
+
+// HEADER: {{^}} -: 0:Source:gcov-12.c
+// HEADER-NEXT: -: 0:Graph:gcov-12.gcno
+// HEADER-NEXT: -: 0:Data:gcov-12.gcda
+// HEADER-NEXT: -: 0:Runs:1{{$}}
+// HEADER-NEXT: -: 1:/// Test that llvm-cov
More information about the llvm-commits
mailing list