[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