[clang] cdd683b - [gcov] Support big-endian .gcno and simplify version handling in .gcda
Fangrui Song via cfe-commits
cfe-commits at lists.llvm.org
Sat Jun 6 11:10:58 PDT 2020
Author: Fangrui Song
Date: 2020-06-06T11:01:47-07:00
New Revision: cdd683b516d147925212724b09ec6fb792a40041
URL: https://github.com/llvm/llvm-project/commit/cdd683b516d147925212724b09ec6fb792a40041
DIFF: https://github.com/llvm/llvm-project/commit/cdd683b516d147925212724b09ec6fb792a40041.diff
LOG: [gcov] Support big-endian .gcno and simplify version handling in .gcda
Added:
Modified:
clang/test/CodeGen/code-coverage.c
compiler-rt/lib/profile/GCDAProfiling.c
llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
llvm/test/Transforms/GCOVProfiling/function-numbering.ll
llvm/test/Transforms/GCOVProfiling/version.ll
Removed:
################################################################################
diff --git a/clang/test/CodeGen/code-coverage.c b/clang/test/CodeGen/code-coverage.c
index 2b3e90fac5cd..3a11cb2c7df7 100644
--- a/clang/test/CodeGen/code-coverage.c
+++ b/clang/test/CodeGen/code-coverage.c
@@ -35,13 +35,18 @@ int test2(int b) {
return b * 2;
}
-// 402: private unnamed_addr constant [5 x i8] c"*204\00"
-// 407: private unnamed_addr constant [5 x i8] c"*704\00"
-// 408: private unnamed_addr constant [5 x i8] c"*804\00"
// CHECK: @__llvm_internal_gcov_emit_function_args.0 = internal unnamed_addr constant [2 x %0]
// CHECK-SAME: [%0 zeroinitializer, %0 { i32 1, i32 0, i32 0 }]
+// CHECK: @__llvm_internal_gcov_emit_file_info = internal unnamed_addr constant [1 x %2]
+/// 0x3430322a '4' '0' '2' '*'
+// 402-SAME: i32 875573802
+/// 0x3430372a '4' '0' '7' '*'
+// 407-SAME: i32 875575082
+/// 0x3430382a '4' '0' '8' '*'
+// 408-SAME: i32 875575338
+
// Check that the noredzone flag is set on the generated functions.
// CHECK: void @__llvm_gcov_writeout() unnamed_addr [[NRZ:#[0-9]+]]
diff --git a/compiler-rt/lib/profile/GCDAProfiling.c b/compiler-rt/lib/profile/GCDAProfiling.c
index ccbd180fff36..cea7eb8ec954 100644
--- a/compiler-rt/lib/profile/GCDAProfiling.c
+++ b/compiler-rt/lib/profile/GCDAProfiling.c
@@ -349,7 +349,7 @@ static void unmap_file() {
* started at a time.
*/
COMPILER_RT_VISIBILITY
-void llvm_gcda_start_file(const char *orig_filename, const char version[4],
+void llvm_gcda_start_file(const char *orig_filename, uint32_t version,
uint32_t checksum) {
const char *mode = "r+b";
filename = mangle_filename(orig_filename);
@@ -406,20 +406,15 @@ void llvm_gcda_start_file(const char *orig_filename, const char version[4],
}
/* gcda file, version, stamp checksum. */
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
- gcov_version = version[3] >= 'A'
- ? (version[3] - 'A') * 100 + (version[2] - '0') * 10 +
- version[1] - '0'
- : (version[3] - '0') * 10 + version[1] - '0';
-#else
- gcov_version = version[0] >= 'A'
- ? (version[0] - 'A') * 100 + (version[1] - '0') * 10 +
- version[2] - '0'
- : (version[0] - '0') * 10 + version[2] - '0';
-#endif
-
+ {
+ uint8_t c3 = version >> 24;
+ uint8_t c2 = (version >> 16) & 255;
+ uint8_t c1 = (version >> 8) & 255;
+ gcov_version = c3 >= 'A' ? (c3 - 'A') * 100 + (c2 - '0') * 10 + c1 - '0'
+ : (c3 - '0') * 10 + c1 - '0';
+ }
write_32bit_value(GCOV_DATA_MAGIC);
- write_bytes(version, 4);
+ write_32bit_value(version);
write_32bit_value(checksum);
#ifdef DEBUG_GCDAPROFILING
diff --git a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
index 0a83155007cf..d24a6ddfbb69 100644
--- a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
+++ b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
@@ -45,10 +45,19 @@
#include <memory>
#include <string>
#include <utility>
+
using namespace llvm;
+namespace endian = llvm::support::endian;
#define DEBUG_TYPE "insert-gcov-profiling"
+enum : uint32_t {
+ GCOV_TAG_FUNCTION = 0x01000000,
+ GCOV_TAG_BLOCKS = 0x01410000,
+ GCOV_TAG_ARCS = 0x01430000,
+ GCOV_TAG_LINES = 0x01450000,
+};
+
static cl::opt<std::string> DefaultGCOVVersion("default-gcov-version",
cl::init("408*"), cl::Hidden,
cl::ValueRequired);
@@ -73,15 +82,7 @@ class GCOVFunction;
class GCOVProfiler {
public:
GCOVProfiler() : GCOVProfiler(GCOVOptions::getDefault()) {}
- GCOVProfiler(const GCOVOptions &Opts) : Options(Opts) {
- assert((Options.EmitNotes || Options.EmitData) &&
- "GCOVProfiler asked to do nothing?");
- ReversedVersion[0] = Options.Version[3];
- ReversedVersion[1] = Options.Version[2];
- ReversedVersion[2] = Options.Version[1];
- ReversedVersion[3] = Options.Version[0];
- ReversedVersion[4] = '\0';
- }
+ GCOVProfiler(const GCOVOptions &Opts) : Options(Opts) {}
bool
runOnModule(Module &M,
std::function<const TargetLibraryInfo &(Function &F)> GetTLI);
@@ -120,8 +121,6 @@ class GCOVProfiler {
GCOVOptions Options;
- // Reversed, NUL-terminated copy of Options.Version.
- char ReversedVersion[5];
// Checksum, produced by hash of EdgeDestinations
SmallVector<uint32_t, 4> FileChecksums;
@@ -196,20 +195,17 @@ static SmallString<128> getFilename(const DISubprogram *SP) {
namespace {
class GCOVRecord {
- protected:
- static const char *const LinesTag;
- static const char *const FunctionTag;
- static const char *const BlockTag;
- static const char *const EdgeTag;
+ protected:
+ support::endianness Endian;
- GCOVRecord() = default;
+ GCOVRecord(support::endianness Endian) : Endian(Endian) {}
- void writeBytes(const char *Bytes, int Size) {
- os->write(Bytes, Size);
- }
+ void writeBytes(const char *Bytes, int Size) { os->write(Bytes, Size); }
void write(uint32_t i) {
- writeBytes(reinterpret_cast<char*>(&i), 4);
+ char Bytes[4];
+ endian::write32(Bytes, i, Endian);
+ os->write(Bytes, 4);
}
// Returns the length measured in 4-byte blocks that will be used to
@@ -234,10 +230,6 @@ namespace {
raw_ostream *os;
};
- const char *const GCOVRecord::LinesTag = "\0\0\x45\x01";
- const char *const GCOVRecord::FunctionTag = "\0\0\0\1";
- const char *const GCOVRecord::BlockTag = "\0\0\x41\x01";
- const char *const GCOVRecord::EdgeTag = "\0\0\x43\x01";
class GCOVFunction;
class GCOVBlock;
@@ -264,7 +256,8 @@ namespace {
write(Lines[i]);
}
- GCOVLines(StringRef F, raw_ostream *os) : Filename(std::string(F)) {
+ GCOVLines(StringRef F, raw_ostream *os, support::endianness Endian)
+ : GCOVRecord(Endian), Filename(std::string(F)) {
this->os = os;
}
@@ -280,7 +273,8 @@ namespace {
class GCOVBlock : public GCOVRecord {
public:
GCOVLines &getFile(StringRef Filename) {
- return LinesByFile.try_emplace(Filename, Filename, os).first->second;
+ return LinesByFile.try_emplace(Filename, Filename, os, Endian)
+ .first->second;
}
void addEdge(GCOVBlock &Successor) {
@@ -295,7 +289,7 @@ namespace {
SortedLinesByFile.push_back(&I);
}
- writeBytes(LinesTag, 4);
+ write(GCOV_TAG_LINES);
write(Len);
write(Number);
@@ -320,8 +314,8 @@ namespace {
private:
friend class GCOVFunction;
- GCOVBlock(uint32_t Number, raw_ostream *os)
- : Number(Number) {
+ GCOVBlock(uint32_t Number, raw_ostream *os, support::endianness Endian)
+ : GCOVRecord(Endian), Number(Number) {
this->os = os;
}
@@ -334,11 +328,13 @@ namespace {
// set of blocks and a map of edges between blocks. This is the only GCOV
// object users can construct, the blocks and lines will be rooted here.
class GCOVFunction : public GCOVRecord {
- public:
- GCOVFunction(const DISubprogram *SP, Function *F, raw_ostream *os,
- uint32_t Ident, bool UseCfgChecksum, bool ExitBlockBeforeBody)
- : SP(SP), Ident(Ident), UseCfgChecksum(UseCfgChecksum), CfgChecksum(0),
- ReturnBlock(1, os) {
+ public:
+ GCOVFunction(const DISubprogram *SP, Function *F, raw_ostream *os,
+ support::endianness Endian, uint32_t Ident,
+ bool UseCfgChecksum, bool ExitBlockBeforeBody)
+ : GCOVRecord(Endian), SP(SP), Ident(Ident),
+ UseCfgChecksum(UseCfgChecksum), CfgChecksum(0),
+ ReturnBlock(1, os, Endian) {
this->os = os;
LLVM_DEBUG(dbgs() << "Function: " << getFunctionName(SP) << "\n");
@@ -348,7 +344,7 @@ namespace {
// Skip index 1 if it's assigned to the ReturnBlock.
if (i == 1 && ExitBlockBeforeBody)
++i;
- Blocks.insert(std::make_pair(&BB, GCOVBlock(i++, os)));
+ Blocks.insert(std::make_pair(&BB, GCOVBlock(i++, os, Endian)));
}
if (!ExitBlockBeforeBody)
ReturnBlock.Number = i;
@@ -389,7 +385,7 @@ namespace {
}
void writeOut() {
- writeBytes(FunctionTag, 4);
+ write(GCOV_TAG_FUNCTION);
SmallString<128> Filename = getFilename(SP);
uint32_t BlockLen = 1 + 1 + 1 + lengthOfGCOVString(getFunctionName(SP)) +
1 + lengthOfGCOVString(Filename) + 1;
@@ -405,7 +401,7 @@ namespace {
write(SP->getLine());
// Emit count of blocks.
- writeBytes(BlockTag, 4);
+ write(GCOV_TAG_BLOCKS);
write(Blocks.size() + 1);
for (int i = 0, e = Blocks.size() + 1; i != e; ++i) {
write(0); // No flags on our blocks.
@@ -419,7 +415,7 @@ namespace {
GCOVBlock &Block = getBlock(&I);
if (Block.OutEdges.empty()) continue;
- writeBytes(EdgeTag, 4);
+ write(GCOV_TAG_ARCS);
write(Block.OutEdges.size() * 2 + 1);
write(Block.Number);
for (int i = 0, e = Block.OutEdges.size(); i != e; ++i) {
@@ -435,8 +431,8 @@ namespace {
getBlock(&I).writeOut();
}
- private:
- const DISubprogram *SP;
+ private:
+ const DISubprogram *SP;
uint32_t Ident;
uint32_t FuncChecksum;
bool UseCfgChecksum;
@@ -726,6 +722,9 @@ void GCOVProfiler::emitProfileNotes() {
std::string EdgeDestinations;
+ auto Endian = M->getDataLayout().isLittleEndian()
+ ? support::endianness::little
+ : support::endianness::big;
unsigned FunctionIdent = 0;
for (auto &F : M->functions()) {
DISubprogram *SP = F.getSubprogram();
@@ -745,8 +744,9 @@ void GCOVProfiler::emitProfileNotes() {
bool UseCfgChecksum = strncmp(Options.Version, "407", 3) >= 0;
bool ExitBlockBeforeBody = strncmp(Options.Version, "408", 3) >= 0;
- Funcs.push_back(std::make_unique<GCOVFunction>(
- SP, &F, &out, FunctionIdent++, UseCfgChecksum, ExitBlockBeforeBody));
+ Funcs.push_back(
+ std::make_unique<GCOVFunction>(SP, &F, &out, Endian, FunctionIdent++,
+ UseCfgChecksum, ExitBlockBeforeBody));
GCOVFunction &Func = *Funcs.back();
// Add the function line number to the lines of the entry block
@@ -795,10 +795,18 @@ void GCOVProfiler::emitProfileNotes() {
EdgeDestinations += Func.getEdgeDestinations();
}
+ char Tmp[4];
FileChecksums.push_back(hash_value(EdgeDestinations));
- out.write("oncg", 4);
- out.write(ReversedVersion, 4);
- out.write(reinterpret_cast<char*>(&FileChecksums.back()), 4);
+ if (Endian == support::endianness::big) {
+ out.write("gcno", 4);
+ out.write(Options.Version, 4);
+ } else {
+ out.write("oncg", 4);
+ std::reverse_copy(Options.Version, Options.Version + 4, Tmp);
+ out.write(Tmp, 4);
+ }
+ endian::write32(Tmp, FileChecksums.back(), Endian);
+ out.write(Tmp, 4);
for (auto &Func : Funcs) {
Func->setCfgChecksum(FileChecksums.back());
@@ -926,9 +934,9 @@ bool GCOVProfiler::emitProfileArcs() {
FunctionCallee GCOVProfiler::getStartFileFunc(const TargetLibraryInfo *TLI) {
Type *Args[] = {
- Type::getInt8PtrTy(*Ctx), // const char *orig_filename
- Type::getInt8PtrTy(*Ctx), // const char version[4]
- Type::getInt32Ty(*Ctx), // uint32_t checksum
+ Type::getInt8PtrTy(*Ctx), // const char *orig_filename
+ Type::getInt32Ty(*Ctx), // uint32_t version
+ Type::getInt32Ty(*Ctx), // uint32_t checksum
};
FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), Args, false);
AttributeList AL;
@@ -1008,7 +1016,7 @@ Function *GCOVProfiler::insertCounterWriteout(
// Collect the relevant data into a large constant data structure that we can
// walk to write out everything.
StructType *StartFileCallArgsTy = StructType::create(
- {Builder.getInt8PtrTy(), Builder.getInt8PtrTy(), Builder.getInt32Ty()});
+ {Builder.getInt8PtrTy(), Builder.getInt32Ty(), Builder.getInt32Ty()});
StructType *EmitFunctionCallArgsTy = StructType::create(
{Builder.getInt32Ty(), Builder.getInt32Ty(), Builder.getInt32Ty()});
StructType *EmitArcsCallArgsTy = StructType::create(
@@ -1033,9 +1041,10 @@ Function *GCOVProfiler::insertCounterWriteout(
std::string FilenameGcda = mangleName(CU, GCovFileType::GCDA);
uint32_t CfgChecksum = FileChecksums.empty() ? 0 : FileChecksums[i];
auto *StartFileCallArgs = ConstantStruct::get(
- StartFileCallArgsTy, {Builder.CreateGlobalStringPtr(FilenameGcda),
- Builder.CreateGlobalStringPtr(ReversedVersion),
- Builder.getInt32(CfgChecksum)});
+ StartFileCallArgsTy,
+ {Builder.CreateGlobalStringPtr(FilenameGcda),
+ Builder.getInt32(endian::read32be(Options.Version)),
+ Builder.getInt32(CfgChecksum)});
SmallVector<Constant *, 8> EmitFunctionCallArgsArray;
SmallVector<Constant *, 8> EmitArcsCallArgsArray;
diff --git a/llvm/test/Transforms/GCOVProfiling/function-numbering.ll b/llvm/test/Transforms/GCOVProfiling/function-numbering.ll
index 533bb0a38f7c..a6b974f2934d 100644
--- a/llvm/test/Transforms/GCOVProfiling/function-numbering.ll
+++ b/llvm/test/Transforms/GCOVProfiling/function-numbering.ll
@@ -32,10 +32,10 @@ target triple = "x86_64-apple-macosx10.10.0"
; GCDA-NEXT: %[[START_FILE_ARG_0_PTR:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %[[START_FILE_ARGS]], i32 0, i32 0
; GCDA-NEXT: %[[START_FILE_ARG_0:.*]] = load i8*, i8** %[[START_FILE_ARG_0_PTR]]
; GCDA-NEXT: %[[START_FILE_ARG_1_PTR:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %[[START_FILE_ARGS]], i32 0, i32 1
-; GCDA-NEXT: %[[START_FILE_ARG_1:.*]] = load i8*, i8** %[[START_FILE_ARG_1_PTR]]
+; GCDA-NEXT: %[[START_FILE_ARG_1:.*]] = load i32, i32* %[[START_FILE_ARG_1_PTR]]
; GCDA-NEXT: %[[START_FILE_ARG_2_PTR:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %[[START_FILE_ARGS]], i32 0, i32 2
; GCDA-NEXT: %[[START_FILE_ARG_2:.*]] = load i32, i32* %[[START_FILE_ARG_2_PTR]]
-; GCDA-NEXT: call void @llvm_gcda_start_file(i8* %[[START_FILE_ARG_0]], i8* %[[START_FILE_ARG_1]], i32 %[[START_FILE_ARG_2]])
+; GCDA-NEXT: call void @llvm_gcda_start_file(i8* %[[START_FILE_ARG_0]], i32 %[[START_FILE_ARG_1]], i32 %[[START_FILE_ARG_2]])
; GCDA-NEXT: %[[NUM_COUNTERS_PTR:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %[[FILE_INFO]], i32 0, i32 1
; GCDA-NEXT: %[[NUM_COUNTERS:.*]] = load i32, i32* %[[NUM_COUNTERS_PTR]]
; GCDA-NEXT: %[[EMIT_FUN_ARGS_ARRAY_PTR:.*]] = getelementptr inbounds {{.*}}, {{.*}}* %[[FILE_INFO]], i32 0, i32 2
diff --git a/llvm/test/Transforms/GCOVProfiling/version.ll b/llvm/test/Transforms/GCOVProfiling/version.ll
index b7ce1ab93e07..91331dc11e22 100644
--- a/llvm/test/Transforms/GCOVProfiling/version.ll
+++ b/llvm/test/Transforms/GCOVProfiling/version.ll
@@ -1,6 +1,9 @@
; RUN: rm -rf %t && mkdir -p %t
-; RUN: echo '!9 = !{!"%/t/version.ll", !0}' > %t/1
-; RUN: cat %s %t/1 > %t/2
+; RUN: echo 'target datalayout = "e"' > %t/little.txt
+; RUN: echo 'target datalayout = "E"' > %t/big.txt
+; RUN: echo '!9 = !{!"%/t/version.ll", !0}' > %t/version.txt
+; RUN: cat %t/little.txt %s %t/version.txt > %t/2
+
; RUN: opt -insert-gcov-profiling -disable-output < %t/2
; RUN: head -c8 %t/version.gcno | grep '^oncg.804'
; RUN: rm %t/version.gcno
@@ -17,6 +20,10 @@
; RUN: head -c8 %t/version.gcno | grep '^oncg.204'
; RUN: rm %t/version.gcno
+; RUN: cat %t/big.txt %s %t/version.txt > %t/big.ll
+; RUN: opt -insert-gcov-profiling -disable-output < %t/big.ll
+; RUN: head -c8 %t/version.gcno | grep '^gcno408.'
+
define void @test() !dbg !5 {
ret void, !dbg !8
}
More information about the cfe-commits
mailing list