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 00000000000..d2437360451 Binary files /dev/null and b/test/tools/llvm-cov/Inputs/templateInstantiations.covmapping differ diff --git a/test/tools/llvm-cov/Inputs/templateInstantiations.profdata b/test/tools/llvm-cov/Inputs/templateInstantiations.profdata new file mode 100644 index 00000000000..6ccf526b5f3 Binary files /dev/null and b/test/tools/llvm-cov/Inputs/templateInstantiations.profdata differ 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