From aacc919bfd62dd0503f394326f458dfbe39218f8 Mon Sep 17 00:00:00 2001
From: Justin Bogner <mail@justinbogner.com>
Date: Thu, 25 Sep 2014 00:34:18 +0000
Subject: [PATCH] llvm-cov: Combine segments that cover the same location

If we have multiple coverage counts for the same segment, we need to
add them up rather than arbitrarily choosing one. This fixes that and
adds a test with template instantiations to exercise it.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@218432 91177308-0d34-0410-b5e6-96231b3b80d8
---
 include/llvm/ProfileData/CoverageMapping.h    |   1 +
 lib/ProfileData/CoverageMapping.cpp           |  22 +++++++--
 .../Inputs/templateInstantiations.covmapping  | Bin 0 -> 244 bytes
 .../Inputs/templateInstantiations.profdata    | Bin 0 -> 768 bytes
 .../llvm-cov/showTemplateInstantiations.cpp   |  43 ++++++++++++++++++
 5 files changed, 62 insertions(+), 4 deletions(-)
 create mode 100644 test/tools/llvm-cov/Inputs/templateInstantiations.covmapping
 create mode 100644 test/tools/llvm-cov/Inputs/templateInstantiations.profdata
 create mode 100644 test/tools/llvm-cov/showTemplateInstantiations.cpp

diff --git a/include/llvm/ProfileData/CoverageMapping.h b/include/llvm/ProfileData/CoverageMapping.h
index a7c124adf33..15445b59963 100644
--- a/include/llvm/ProfileData/CoverageMapping.h
+++ b/include/llvm/ProfileData/CoverageMapping.h
@@ -274,6 +274,7 @@ struct CoverageSegment {
     Count = NewCount;
     HasCount = true;
   }
+  void addCount(uint64_t NewCount) { setCount(Count + NewCount); }
 };
 
 /// \brief Coverage information to be processed or displayed.
diff --git a/lib/ProfileData/CoverageMapping.cpp b/lib/ProfileData/CoverageMapping.cpp
index 540e6433322..06a950c2e40 100644
--- a/lib/ProfileData/CoverageMapping.cpp
+++ b/lib/ProfileData/CoverageMapping.cpp
@@ -19,11 +19,14 @@
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/ProfileData/CoverageMappingReader.h"
 #include "llvm/ProfileData/InstrProfReader.h"
+#include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorHandling.h"
 
 using namespace llvm;
 using namespace coverage;
 
+#define DEBUG_TYPE "coverage-mapping"
+
 CounterExpressionBuilder::CounterExpressionBuilder(unsigned NumCounterValues) {
   Terms.resize(NumCounterValues);
 }
@@ -228,6 +231,7 @@ class SegmentBuilder {
 
   /// Start a segment with no count specified.
   void startSegment(unsigned Line, unsigned Col) {
+    DEBUG(dbgs() << "Top level segment at " << Line << ":" << Col << "\n");
     Segments.emplace_back(Line, Col, /*IsRegionEntry=*/false);
   }
 
@@ -242,9 +246,13 @@ class SegmentBuilder {
       Segments.emplace_back(Line, Col, IsRegionEntry);
       S = Segments.back();
     }
+    DEBUG(dbgs() << "Segment at " << Line << ":" << Col);
     // Set this region's count.
-    if (Region.Kind != coverage::CounterMappingRegion::SkippedRegion)
+    if (Region.Kind != coverage::CounterMappingRegion::SkippedRegion) {
+      DEBUG(dbgs() << " with count " << Region.ExecutionCount);
       Segments.back().setCount(Region.ExecutionCount);
+    }
+    DEBUG(dbgs() << "\n");
   }
 
   /// Start a segment for the given region.
@@ -272,9 +280,15 @@ public:
       while (!ActiveRegions.empty() &&
              ActiveRegions.back()->endLoc() <= Region.startLoc())
         popRegion();
-      // Add this region to the stack.
-      ActiveRegions.push_back(&Region);
-      startSegment(Region);
+      if (Segments.size() && Segments.back().Line == Region.LineStart &&
+          Segments.back().Col == Region.ColumnStart) {
+        if (Region.Kind != coverage::CounterMappingRegion::SkippedRegion)
+          Segments.back().addCount(Region.ExecutionCount);
+      } else {
+        // Add this region to the stack.
+        ActiveRegions.push_back(&Region);
+        startSegment(Region);
+      }
     }
     // Pop any regions that are left in the stack.
     while (!ActiveRegions.empty())
diff --git a/test/tools/llvm-cov/Inputs/templateInstantiations.covmapping b/test/tools/llvm-cov/Inputs/templateInstantiations.covmapping
new file mode 100644
index 0000000000000000000000000000000000000000..d243736045134e9ec618bf7a2a64c8f6eb2473e1
GIT binary patch
literal 244
zcmd1FDa%dHFUu`SEiOq(EJ>8RaIm34AU82HFFwj7tu!y$Gs!hGBp$}e1aX)d7#LK6
z*cpgH;DQ1J10#@T0b))dhJh;z5OH3hfD{mOK_wn4U>9dp)-TB|&@ax&FAqu0EyzhM
zN%hPtE=kNQ$xJNC%+D*<OD-q?TExhxB*DVO2&7qA7}@36m{^&(7<idL1Op=*0}pN)
Ghywt&b|<O;

literal 0
HcmV?d00001

diff --git a/test/tools/llvm-cov/Inputs/templateInstantiations.profdata b/test/tools/llvm-cov/Inputs/templateInstantiations.profdata
new file mode 100644
index 0000000000000000000000000000000000000000..6ccf526b5f3d1305a35de49d9da90c6a59848aba
GIT binary patch
literal 768
zcmeyLQ&5zjmf6U}00E3p8b*D9i+k58ap<!KuHuD?C_w4>D3i3(ykyTL*UXT3E~p^7
zaWG>U8A8+xiy|L9vBPCdCO%`JrZX@y{JPrv+$?44Z5F7I1eDHA%*;cmg0NtggLn=Q
ZAqHkBO)E-+N(Sds$()g5%r+7|3IP739Yg>C

literal 0
HcmV?d00001

diff --git a/test/tools/llvm-cov/showTemplateInstantiations.cpp b/test/tools/llvm-cov/showTemplateInstantiations.cpp
new file mode 100644
index 00000000000..2b72d83c013
--- /dev/null
+++ b/test/tools/llvm-cov/showTemplateInstantiations.cpp
@@ -0,0 +1,43 @@
+// RUN: llvm-cov show %S/Inputs/templateInstantiations.covmapping -instr-profile %S/Inputs/templateInstantiations.profdata -no-colors -filename-equivalence %s | FileCheck -check-prefix=CHECK -check-prefix=ALL %s
+// RUN: llvm-cov show %S/Inputs/templateInstantiations.covmapping -instr-profile %S/Inputs/templateInstantiations.profdata -no-colors -filename-equivalence -name=_Z4funcIbEiT_ %s | FileCheck -check-prefix=CHECK -check-prefix=FILTER %s
+
+// before coverage   // WHOLE-FILE:   | [[@LINE]]|// before
+                     // FILTER-NOT:   | [[@LINE-1]]|// before
+template<typename T> // ALL:          | [[@LINE]]|template<typename T>
+int func(T x) {      // ALL-NEXT:    2| [[@LINE]]|int func(T x) {
+  if(x)              // ALL-NEXT:    2| [[@LINE]]|  if(x)
+    return 0;        // ALL-NEXT:    1| [[@LINE]]|    return 0;
+  else               // ALL-NEXT:    1| [[@LINE]]|  else
+    return 1;        // ALL-NEXT:    1| [[@LINE]]|    return 1;
+  int j = 1;         // ALL-NEXT:    0| [[@LINE]]|  int j = 1;
+}                    // ALL-NEXT:    1| [[@LINE]]|}
+
+                     // CHECK:       {{^ *(\| )?}}_Z4funcIbEiT_:
+                     // CHECK-NEXT:  1| [[@LINE-9]]|int func(T x) {
+                     // CHECK-NEXT:  1| [[@LINE-9]]|  if(x)
+                     // CHECK-NEXT:  1| [[@LINE-9]]|    return 0;
+                     // CHECK-NEXT:  1| [[@LINE-9]]|  else
+                     // CHECK-NEXT:  0| [[@LINE-9]]|    return 1;
+                     // CHECK-NEXT:  0| [[@LINE-9]]|  int j = 1;
+                     // CHECK-NEXT:  1| [[@LINE-9]]|}
+
+                     // ALL:         {{^ *}}| _Z4funcIiEiT_:
+                     // FILTER-NOT:  {{^ *(\| )?}} _Z4funcIiEiT_:
+                     // ALL-NEXT:    1| [[@LINE-19]]|int func(T x) {
+                     // ALL-NEXT:    1| [[@LINE-19]]|  if(x)
+                     // ALL-NEXT:    0| [[@LINE-19]]|    return 0;
+                     // ALL-NEXT:    1| [[@LINE-19]]|  else
+                     // ALL-NEXT:    1| [[@LINE-19]]|    return 1;
+                     // ALL-NEXT:    0| [[@LINE-19]]|  int j = 1;
+                     // ALL-NEXT:    1| [[@LINE-19]]|}
+
+int main() {         // ALL:         1| [[@LINE]]|int main() {
+  func<int>(0);      // ALL-NEXT:    1| [[@LINE]]|  func<int>(0);
+  func<bool>(true);  // ALL-NEXT:    1| [[@LINE]]|  func<bool>(true);
+  return 0;          // ALL-NEXT:    1| [[@LINE]]|  return 0;
+}                    // ALL-NEXT:    1| [[@LINE]]|}
+// after coverage    // ALL-NEXT:     | [[@LINE]]|// after
+                     // FILTER-NOT:   | [[@LINE-1]]|// after
+
+// llvm-cov doesn't work on big endian yet
+// XFAIL: powerpc64-, s390x, mips-, mips64-, sparc