Index: llvm/trunk/include/llvm/ProfileData/CoverageMapping.h =================================================================== --- llvm/trunk/include/llvm/ProfileData/CoverageMapping.h +++ llvm/trunk/include/llvm/ProfileData/CoverageMapping.h @@ -370,13 +370,6 @@ return std::tie(L.Line, L.Col, L.Count, L.HasCount, L.IsRegionEntry) == std::tie(R.Line, R.Col, R.Count, R.HasCount, R.IsRegionEntry); } - - void setCount(uint64_t NewCount) { - Count = NewCount; - HasCount = true; - } - - void addCount(uint64_t NewCount) { setCount(Count + NewCount); } }; /// \brief Coverage information to be processed or displayed. Index: llvm/trunk/lib/ProfileData/CoverageMapping.cpp =================================================================== --- llvm/trunk/lib/ProfileData/CoverageMapping.cpp +++ llvm/trunk/lib/ProfileData/CoverageMapping.cpp @@ -284,20 +284,17 @@ /// Start a segment with the given Region's count. void startSegment(unsigned Line, unsigned Col, bool IsRegionEntry, const CountedRegion &Region) { - if (Segments.empty()) - Segments.emplace_back(Line, Col, IsRegionEntry); - CoverageSegment S = Segments.back(); // Avoid creating empty regions. - if (S.Line != Line || S.Col != Col) { - Segments.emplace_back(Line, Col, IsRegionEntry); - S = Segments.back(); - } + if (!Segments.empty() && Segments.back().Line == Line && + Segments.back().Col == Col) + Segments.pop_back(); DEBUG(dbgs() << "Segment at " << Line << ":" << Col); // Set this region's count. if (Region.Kind != coverage::CounterMappingRegion::SkippedRegion) { DEBUG(dbgs() << " with count " << Region.ExecutionCount); - Segments.back().setCount(Region.ExecutionCount); - } + Segments.emplace_back(Line, Col, Region.ExecutionCount, IsRegionEntry); + } else + Segments.emplace_back(Line, Col, IsRegionEntry); DEBUG(dbgs() << "\n"); } @@ -319,24 +316,17 @@ } public: - /// Build a list of CoverageSegments from a sorted list of Regions. + /// Build a list of CoverageSegments from a sorted and combined + /// list of Regions. std::vector buildSegments(ArrayRef Regions) { - const CountedRegion *PrevRegion = nullptr; for (const auto &Region : Regions) { // Pop any regions that end before this one starts. while (!ActiveRegions.empty() && ActiveRegions.back()->endLoc() <= Region.startLoc()) popRegion(); - if (PrevRegion && PrevRegion->startLoc() == Region.startLoc() && - PrevRegion->endLoc() == Region.endLoc()) { - if (Region.Kind == coverage::CounterMappingRegion::CodeRegion) - Segments.back().addCount(Region.ExecutionCount); - } else { - // Add this region to the stack. - ActiveRegions.push_back(&Region); - startSegment(Region); - } - PrevRegion = &Region; + // Add this region to the stack. + ActiveRegions.push_back(&Region); + startSegment(Region); } // Pop any regions that are left in the stack. while (!ActiveRegions.empty()) @@ -403,6 +393,31 @@ }); } +/// Combine counts of regions which cover the same area. +template static It combineRegionCounts(It First, It Last) { + if (First == Last) + return Last; + It Active = First; + It I = First; + for (++I; I != Last; ++I) { + if (Active->startLoc() != I->startLoc() || + Active->endLoc() != I->endLoc()) { + // Shift to the next region. + ++Active; + if (Active != I) + *Active = *I; + continue; + } + if (I->Kind != coverage::CounterMappingRegion::CodeRegion) + continue; + if (Active->Kind == coverage::CounterMappingRegion::SkippedRegion) + *Active = *I; + else + Active->ExecutionCount += I->ExecutionCount; + } + return ++Active; +} + static bool isExpansion(const CountedRegion &R, unsigned FileID) { return R.Kind == CounterMappingRegion::ExpansionRegion && R.FileID == FileID; } @@ -425,6 +440,8 @@ } sortNestedRegions(Regions.begin(), Regions.end()); + Regions.erase(combineRegionCounts(Regions.begin(), Regions.end()), + Regions.end()); DEBUG(dbgs() << "Emitting segments for file: " << Filename << "\n"); FileCoverage.Segments = SegmentBuilder().buildSegments(Regions); @@ -467,6 +484,8 @@ } sortNestedRegions(Regions.begin(), Regions.end()); + Regions.erase(combineRegionCounts(Regions.begin(), Regions.end()), + Regions.end()); DEBUG(dbgs() << "Emitting segments for function: " << Function.Name << "\n"); FunctionCoverage.Segments = SegmentBuilder().buildSegments(Regions); @@ -486,6 +505,8 @@ } sortNestedRegions(Regions.begin(), Regions.end()); + Regions.erase(combineRegionCounts(Regions.begin(), Regions.end()), + Regions.end()); DEBUG(dbgs() << "Emitting segments for expansion of file " << Expansion.FileID << "\n"); ExpansionCoverage.Segments = SegmentBuilder().buildSegments(Regions); Index: llvm/trunk/test/tools/llvm-cov/showTemplateInstantiations.cpp =================================================================== --- llvm/trunk/test/tools/llvm-cov/showTemplateInstantiations.cpp +++ llvm/trunk/test/tools/llvm-cov/showTemplateInstantiations.cpp @@ -7,10 +7,10 @@ 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 + else // ALL-NEXT: 2| [[@LINE]]| else return 1; // ALL-NEXT: 1| [[@LINE]]| return 1; int j = 1; // ALL-NEXT: 0| [[@LINE]]| int j = 1; -} // ALL-NEXT: 1| [[@LINE]]|} +} // ALL-NEXT: 2| [[@LINE]]|} // CHECK: {{^ *(\| )?}}_Z4funcIbEiT_: // CHECK-NEXT: 1| [[@LINE-9]]|int func(T x) { Index: llvm/trunk/unittests/ProfileData/CoverageMappingTest.cpp =================================================================== --- llvm/trunk/unittests/ProfileData/CoverageMappingTest.cpp +++ llvm/trunk/unittests/ProfileData/CoverageMappingTest.cpp @@ -269,6 +269,26 @@ ASSERT_EQ(CoverageSegment(9, 9, false), Segments[3]); } +TEST_P(MaybeSparseCoverageMappingTest, + restore_combined_counter_after_nested_region) { + InstrProfRecord Record("func", 0x1234, {10, 20, 40}); + ProfileWriter.addRecord(std::move(Record)); + readProfCounts(); + + addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); + addCMR(Counter::getCounter(1), "file1", 1, 1, 9, 9); + addCMR(Counter::getCounter(2), "file1", 3, 3, 5, 5); + loadCoverageMapping("func", 0x1234); + + CoverageData Data = LoadedCoverage->getCoverageForFile("file1"); + std::vector Segments(Data.begin(), Data.end()); + ASSERT_EQ(4U, Segments.size()); + ASSERT_EQ(CoverageSegment(1, 1, 30, true), Segments[0]); + ASSERT_EQ(CoverageSegment(3, 3, 40, true), Segments[1]); + ASSERT_EQ(CoverageSegment(5, 5, 30, false), Segments[2]); + ASSERT_EQ(CoverageSegment(9, 9, false), Segments[3]); +} + TEST_P(MaybeSparseCoverageMappingTest, dont_combine_expansions) { InstrProfRecord Record1("func", 0x1234, {10, 20}); InstrProfRecord Record2("func", 0x1234, {0, 0});