GCOV: Make the exit block placement from r223193 optional
authorJustin Bogner <mail@justinbogner.com>
Mon, 16 Mar 2015 23:52:03 +0000 (23:52 +0000)
committerJustin Bogner <mail@justinbogner.com>
Mon, 16 Mar 2015 23:52:03 +0000 (23:52 +0000)
By default we want our gcov emission to stay 4.2 compatible, which
means we need to continue emit the exit block last by default. We add
an option to emit it before the body for users that need it.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@232438 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Transforms/Instrumentation.h
lib/Transforms/Instrumentation/GCOVProfiling.cpp
test/Transforms/GCOVProfiling/return-block.ll

index 8fac6ca83ace6acf354215f64ed963d118120960..a1477930ed62debdb1b137a82b44e30257c483d9 100644 (file)
@@ -60,6 +60,10 @@ struct GCOVOptions {
   // Emit the name of the function in the .gcda files. This is redundant, as
   // the function identifier can be used to find the name from the .gcno file.
   bool FunctionNamesInData;
+
+  // Emit the exit block immediately after the start block, rather than after
+  // all of the function body's blocks.
+  bool ExitBlockBeforeBody;
 };
 ModulePass *createGCOVProfilerPass(const GCOVOptions &Options =
                                    GCOVOptions::getDefault());
index e50ef1e0cd230df2f1ad21f7738a12b7308b0b55..a793e69ce3d6be563dcd2f8c5b54db07cea17d7a 100644 (file)
@@ -47,6 +47,8 @@ using namespace llvm;
 static cl::opt<std::string>
 DefaultGCOVVersion("default-gcov-version", cl::init("402*"), cl::Hidden,
                    cl::ValueRequired);
+static cl::opt<bool> DefaultExitBlockBeforeBody("gcov-exit-block-before-body",
+                                                cl::init(false), cl::Hidden);
 
 GCOVOptions GCOVOptions::getDefault() {
   GCOVOptions Options;
@@ -55,6 +57,7 @@ GCOVOptions GCOVOptions::getDefault() {
   Options.UseCfgChecksum = false;
   Options.NoRedZone = false;
   Options.FunctionNamesInData = true;
+  Options.ExitBlockBeforeBody = DefaultExitBlockBeforeBody;
 
   if (DefaultGCOVVersion.size() != 4) {
     llvm::report_fatal_error(std::string("Invalid -default-gcov-version: ") +
@@ -307,7 +310,7 @@ namespace {
   class GCOVFunction : public GCOVRecord {
    public:
      GCOVFunction(DISubprogram SP, raw_ostream *os, uint32_t Ident,
-                  bool UseCfgChecksum)
+                  bool UseCfgChecksum, bool ExitBlockBeforeBody)
          : SP(SP), Ident(Ident), UseCfgChecksum(UseCfgChecksum), CfgChecksum(0),
            ReturnBlock(1, os) {
       this->os = os;
@@ -317,11 +320,13 @@ namespace {
 
       uint32_t i = 0;
       for (auto &BB : *F) {
-        // Skip index 1 (0, 2, 3, 4, ...) because that's assigned to the
-        // ReturnBlock.
-        bool first = i == 0;
-        Blocks.insert(std::make_pair(&BB, GCOVBlock(i++ + !first, os)));
+        // Skip index 1 if it's assigned to the ReturnBlock.
+        if (i == 1 && ExitBlockBeforeBody)
+          ++i;
+        Blocks.insert(std::make_pair(&BB, GCOVBlock(i++, os)));
       }
+      if (!ExitBlockBeforeBody)
+        ReturnBlock.Number = i;
 
       std::string FunctionNameAndLine;
       raw_string_ostream FNLOS(FunctionNameAndLine);
@@ -464,7 +469,7 @@ static bool functionHasLines(Function *F) {
       if (Loc.isUnknown()) continue;
 
       // Artificial lines such as calls to the global constructors.
-      if (Loc.getLine() == 0) continue; 
+      if (Loc.getLine() == 0) continue;
 
       return true;
     }
@@ -508,7 +513,8 @@ void GCOVProfiler::emitProfileNotes() {
       EntryBlock.splitBasicBlock(It);
 
       Funcs.push_back(make_unique<GCOVFunction>(SP, &out, FunctionIdent++,
-                                                Options.UseCfgChecksum));
+                                                Options.UseCfgChecksum,
+                                                Options.ExitBlockBeforeBody));
       GCOVFunction &Func = *Funcs.back();
 
       for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) {
index 8954157f54820caa99bca3f0799710b29d6a8706..0fafc559f5d9714b1c3385b25ba225af02e0fa31 100644 (file)
@@ -1,8 +1,14 @@
 ; Inject metadata to set the .gcno file location
 ; RUN: echo '!19 = !{!"%/T/return-block.ll", !0}' > %t1
 ; RUN: cat %s %t1 > %t2
+
+; By default, the return block is last.
 ; RUN: opt -insert-gcov-profiling -disable-output %t2
-; RUN: llvm-cov gcov -n -dump %T/return-block.gcno 2>&1 | FileCheck %s
+; RUN: llvm-cov gcov -n -dump %T/return-block.gcno 2>&1 | FileCheck -check-prefix=CHECK -check-prefix=RETURN-LAST %s
+
+; But we can optionally emit it second, to match newer gcc versions.
+; RUN: opt -insert-gcov-profiling -gcov-exit-block-before-body -disable-output %t2
+; RUN: llvm-cov gcov -n -dump %T/return-block.gcno 2>&1 | FileCheck -check-prefix=CHECK -check-prefix=RETURN-SECOND %s
 
 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-unknown-linux-gnu"
@@ -58,9 +64,12 @@ attributes #2 = { nounwind }
 !17 = distinct !MDLexicalBlock(line: 7, column: 7, file: !1, scope: !4)
 !18 = !MDLocation(line: 9, column: 1, scope: !4)
 
-; There should be no destination edges for block 1.
-; CHECK: Block : 0 Counter : 0
-; CHECK-NEXT:         Destination Edges : 2 (0), 
-; CHECK-NEXT: Block : 1 Counter : 0
-; CHECK-NEXT:         Source Edges : 4 (0), 
-; CHECK-NEXT: Block : 2 Counter : 0
+; There should be no destination edges for the exit block.
+; CHECK: Block : 1 Counter : 0
+; RETURN-LAST:       Destination Edges
+; RETURN-SECOND-NOT: Destination Edges
+; CHECK: Block : 2 Counter : 0
+; CHECK: Block : 4 Counter : 0
+; RETURN-LAST-NOT: Destination Edges
+; RETURN-SECOND:   Destination Edges
+; CHECK-NOT: Block :