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 @@ -273,71 +273,76 @@ class SegmentBuilder { std::vector Segments; - SmallVector ActiveRegions; + /// Each entry corresponds to the area of code covered by one or more regions + /// with the same bounds. It consists of the first region found for that area + /// and the combined counter. + SmallVector>, 8> + ActiveRegions; - /// 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); - } - - /// Start a segment with the given Region's count. + /// Start a segment at the given position with the given 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(); + const Optional &Count) { // 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); - } + if (Count.hasValue()) { + DEBUG(dbgs() << " with count " << Count.getValue()); + Segments.emplace_back(Line, Col, Count.getValue(), IsRegionEntry); + } else + Segments.emplace_back(Line, Col, IsRegionEntry); DEBUG(dbgs() << "\n"); } - /// Start a segment for the given region. - void startSegment(const CountedRegion &Region) { - startSegment(Region.LineStart, Region.ColumnStart, true, Region); + /// Add the region to the top of the active stack and start + /// a new segment with the given count. + void pushRegion(const CountedRegion *Region, + const Optional &Count) { + startSegment(Region->LineStart, Region->ColumnStart, true, Count); + ActiveRegions.emplace_back(Region, Count); } /// Pop the top region off of the active stack, starting a new segment with /// the containing Region's count. void popRegion() { - const CountedRegion *Active = ActiveRegions.back(); - unsigned Line = Active->LineEnd, Col = Active->ColumnEnd; + const CountedRegion *Active = ActiveRegions.back().first; ActiveRegions.pop_back(); - if (ActiveRegions.empty()) - startSegment(Line, Col); - else - startSegment(Line, Col, false, *ActiveRegions.back()); + Optional Count = None; + if (!ActiveRegions.empty()) + Count = ActiveRegions.back().second; + startSegment(Active->LineEnd, Active->ColumnEnd, false, Count); } public: /// Build a list of CoverageSegments from a sorted list of Regions. std::vector buildSegments(ArrayRef Regions) { - const CountedRegion *PrevRegion = nullptr; + const CountedRegion *ReferenceRegion = nullptr; + Optional Count = None; for (const auto &Region : Regions) { + // Combine counters of the regions which cover the same area. + if (ReferenceRegion && ReferenceRegion->startLoc() == Region.startLoc() && + ReferenceRegion->endLoc() == Region.endLoc()) { + if (Region.Kind == coverage::CounterMappingRegion::CodeRegion) + Count = Count.getValueOr(0) + Region.ExecutionCount; + continue; + } + // Add the previous region with the combined counter to the stack. + if (ReferenceRegion) + pushRegion(ReferenceRegion, Count); // Pop any regions that end before this one starts. while (!ActiveRegions.empty() && - ActiveRegions.back()->endLoc() <= Region.startLoc()) + ActiveRegions.back().first->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; + ReferenceRegion = &Region; + if (Region.Kind != coverage::CounterMappingRegion::SkippedRegion) + Count = Region.ExecutionCount; + else + Count = None; } + // Add the last region to the stack. + if (ReferenceRegion) + pushRegion(ReferenceRegion, Count); // Pop any regions that are left in the stack. while (!ActiveRegions.empty()) popRegion(); 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,25 @@ 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});