diff --git a/clang/test/CodeGen/code-coverage.c b/clang/test/CodeGen/code-coverage.c index 2b3e90fac5cd0..3a11cb2c7df7e 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 ccbd180fff36e..cea7eb8ec954b 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 0a83155007cf3..d24a6ddfbb694 100644 --- a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp +++ b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp @@ -45,10 +45,19 @@ #include #include #include + 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 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 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 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(&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( - SP, &F, &out, FunctionIdent++, UseCfgChecksum, ExitBlockBeforeBody)); + Funcs.push_back( + std::make_unique(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(&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 EmitFunctionCallArgsArray; SmallVector EmitArcsCallArgsArray; diff --git a/llvm/test/Transforms/GCOVProfiling/function-numbering.ll b/llvm/test/Transforms/GCOVProfiling/function-numbering.ll index 533bb0a38f7c6..a6b974f2934dd 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 b7ce1ab93e078..91331dc11e22f 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 }