[clang] [compiler-rt] [llvm] [MC/DC] Create dedicated MCDCCondBitmapAddr for each Decision (PR #125411)

NAKAMURA Takumi via cfe-commits cfe-commits at lists.llvm.org
Fri Jan 9 19:49:54 PST 2026


https://github.com/chapuni updated https://github.com/llvm/llvm-project/pull/125411

>From 178b57cbbcb2b21b7d13f90ffd75903417913438 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Wed, 2 Oct 2024 23:11:36 +0900
Subject: [PATCH 01/72] [Coverage] Move SingleByteCoverage out of CountedRegion

`SingleByteCoverage` is not per-region attribute at least.
At the moment, this change moves it into `FunctionRecord`.
---
 .../ProfileData/Coverage/CoverageMapping.h    | 27 +++++++-------
 .../ProfileData/Coverage/CoverageMapping.cpp  | 36 ++++++++++++-------
 2 files changed, 36 insertions(+), 27 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index fa07b3a9e8b14..77c447efe1a7c 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -359,19 +359,15 @@ struct CountedRegion : public CounterMappingRegion {
   uint64_t ExecutionCount;
   uint64_t FalseExecutionCount;
   bool Folded;
-  bool HasSingleByteCoverage;
 
-  CountedRegion(const CounterMappingRegion &R, uint64_t ExecutionCount,
-                bool HasSingleByteCoverage)
+  CountedRegion(const CounterMappingRegion &R, uint64_t ExecutionCount)
       : CounterMappingRegion(R), ExecutionCount(ExecutionCount),
-        FalseExecutionCount(0), Folded(false),
-        HasSingleByteCoverage(HasSingleByteCoverage) {}
+        FalseExecutionCount(0), Folded(false) {}
 
   CountedRegion(const CounterMappingRegion &R, uint64_t ExecutionCount,
-                uint64_t FalseExecutionCount, bool HasSingleByteCoverage)
+                uint64_t FalseExecutionCount)
       : CounterMappingRegion(R), ExecutionCount(ExecutionCount),
-        FalseExecutionCount(FalseExecutionCount), Folded(false),
-        HasSingleByteCoverage(HasSingleByteCoverage) {}
+        FalseExecutionCount(FalseExecutionCount), Folded(false) {}
 };
 
 /// MCDC Record grouping all information together.
@@ -702,9 +698,12 @@ struct FunctionRecord {
   std::vector<MCDCRecord> MCDCRecords;
   /// The number of times this function was executed.
   uint64_t ExecutionCount = 0;
+  bool SingleByteCoverage;
 
-  FunctionRecord(StringRef Name, ArrayRef<StringRef> Filenames)
-      : Name(Name), Filenames(Filenames.begin(), Filenames.end()) {}
+  FunctionRecord(StringRef Name, ArrayRef<StringRef> Filenames,
+                 bool SingleByteCoverage)
+      : Name(Name), Filenames(Filenames.begin(), Filenames.end()),
+        SingleByteCoverage(SingleByteCoverage) {}
 
   FunctionRecord(FunctionRecord &&FR) = default;
   FunctionRecord &operator=(FunctionRecord &&) = default;
@@ -714,11 +713,10 @@ struct FunctionRecord {
   }
 
   void pushRegion(CounterMappingRegion Region, uint64_t Count,
-                  uint64_t FalseCount, bool HasSingleByteCoverage) {
+                  uint64_t FalseCount) {
     if (Region.Kind == CounterMappingRegion::BranchRegion ||
         Region.Kind == CounterMappingRegion::MCDCBranchRegion) {
-      CountedBranchRegions.emplace_back(Region, Count, FalseCount,
-                                        HasSingleByteCoverage);
+      CountedBranchRegions.emplace_back(Region, Count, FalseCount);
       // If both counters are hard-coded to zero, then this region represents a
       // constant-folded branch.
       if (Region.Count.isZero() && Region.FalseCount.isZero())
@@ -727,8 +725,7 @@ struct FunctionRecord {
     }
     if (CountedRegions.empty())
       ExecutionCount = Count;
-    CountedRegions.emplace_back(Region, Count, FalseCount,
-                                HasSingleByteCoverage);
+    CountedRegions.emplace_back(Region, Count, FalseCount);
   }
 };
 
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index 18643c6b44485..a02136d5b0386 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -808,6 +808,7 @@ Error CoverageMapping::loadFunctionRecord(
   else
     OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName, Record.Filenames[0]);
 
+  bool SingleByteCoverage = ProfileReader.hasSingleByteCoverage();
   CounterMappingContext Ctx(Record.Expressions);
 
   std::vector<uint64_t> Counts;
@@ -855,7 +856,7 @@ Error CoverageMapping::loadFunctionRecord(
     return Error::success();
 
   MCDCDecisionRecorder MCDCDecisions;
-  FunctionRecord Function(OrigFuncName, Record.Filenames);
+  FunctionRecord Function(OrigFuncName, Record.Filenames, SingleByteCoverage);
   for (const auto &Region : Record.MappingRegions) {
     // MCDCDecisionRegion should be handled first since it overlaps with
     // others inside.
@@ -873,8 +874,7 @@ Error CoverageMapping::loadFunctionRecord(
       consumeError(std::move(E));
       return Error::success();
     }
-    Function.pushRegion(Region, *ExecutionCount, *AltExecutionCount,
-                        ProfileReader.hasSingleByteCoverage());
+    Function.pushRegion(Region, *ExecutionCount, *AltExecutionCount);
 
     // Record ExpansionRegion.
     if (Region.Kind == CounterMappingRegion::ExpansionRegion) {
@@ -1270,7 +1270,8 @@ class SegmentBuilder {
 
   /// Combine counts of regions which cover the same area.
   static ArrayRef<CountedRegion>
-  combineRegions(MutableArrayRef<CountedRegion> Regions) {
+  combineRegions(MutableArrayRef<CountedRegion> Regions,
+                 bool SingleByteCoverage) {
     if (Regions.empty())
       return Regions;
     auto Active = Regions.begin();
@@ -1297,9 +1298,7 @@ class SegmentBuilder {
       // We add counts of the regions of the same kind as the active region
       // to handle the both situations.
       if (I->Kind == Active->Kind) {
-        assert(I->HasSingleByteCoverage == Active->HasSingleByteCoverage &&
-               "Regions are generated in different coverage modes");
-        if (I->HasSingleByteCoverage)
+        if (SingleByteCoverage)
           Active->ExecutionCount = Active->ExecutionCount || I->ExecutionCount;
         else
           Active->ExecutionCount += I->ExecutionCount;
@@ -1311,12 +1310,14 @@ class SegmentBuilder {
 public:
   /// Build a sorted list of CoverageSegments from a list of Regions.
   static std::vector<CoverageSegment>
-  buildSegments(MutableArrayRef<CountedRegion> Regions) {
+  buildSegments(MutableArrayRef<CountedRegion> Regions,
+                bool SingleByteCoverage) {
     std::vector<CoverageSegment> Segments;
     SegmentBuilder Builder(Segments);
 
     sortNestedRegions(Regions);
-    ArrayRef<CountedRegion> CombinedRegions = combineRegions(Regions);
+    ArrayRef<CountedRegion> CombinedRegions =
+        combineRegions(Regions, SingleByteCoverage);
 
     LLVM_DEBUG({
       dbgs() << "Combined regions:\n";
@@ -1403,10 +1404,14 @@ CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) const {
   // the filename, we may get back some records that are not in the file.
   ArrayRef<unsigned> RecordIndices =
       getImpreciseRecordIndicesForFilename(Filename);
+  std::optional<bool> SingleByteCoverage;
   for (unsigned RecordIndex : RecordIndices) {
     const FunctionRecord &Function = Functions[RecordIndex];
     auto MainFileID = findMainViewFileID(Filename, Function);
     auto FileIDs = gatherFileIDs(Filename, Function);
+    assert(!SingleByteCoverage ||
+           *SingleByteCoverage == Function.SingleByteCoverage);
+    SingleByteCoverage = Function.SingleByteCoverage;
     for (const auto &CR : Function.CountedRegions)
       if (FileIDs.test(CR.FileID)) {
         Regions.push_back(CR);
@@ -1424,7 +1429,8 @@ CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) const {
   }
 
   LLVM_DEBUG(dbgs() << "Emitting segments for file: " << Filename << "\n");
-  FileCoverage.Segments = SegmentBuilder::buildSegments(Regions);
+  FileCoverage.Segments =
+      SegmentBuilder::buildSegments(Regions, *SingleByteCoverage);
 
   return FileCoverage;
 }
@@ -1480,7 +1486,8 @@ CoverageMapping::getCoverageForFunction(const FunctionRecord &Function) const {
 
   LLVM_DEBUG(dbgs() << "Emitting segments for function: " << Function.Name
                     << "\n");
-  FunctionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
+  FunctionCoverage.Segments =
+      SegmentBuilder::buildSegments(Regions, Function.SingleByteCoverage);
 
   return FunctionCoverage;
 }
@@ -1490,8 +1497,12 @@ CoverageData CoverageMapping::getCoverageForExpansion(
   CoverageData ExpansionCoverage(
       Expansion.Function.Filenames[Expansion.FileID]);
   std::vector<CountedRegion> Regions;
+  std::optional<bool> SingleByteCoverage;
   for (const auto &CR : Expansion.Function.CountedRegions)
     if (CR.FileID == Expansion.FileID) {
+      assert(!SingleByteCoverage ||
+             *SingleByteCoverage == Expansion.Function.SingleByteCoverage);
+      SingleByteCoverage = Expansion.Function.SingleByteCoverage;
       Regions.push_back(CR);
       if (isExpansion(CR, Expansion.FileID))
         ExpansionCoverage.Expansions.emplace_back(CR, Expansion.Function);
@@ -1503,7 +1514,8 @@ CoverageData CoverageMapping::getCoverageForExpansion(
 
   LLVM_DEBUG(dbgs() << "Emitting segments for expansion of file "
                     << Expansion.FileID << "\n");
-  ExpansionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
+  ExpansionCoverage.Segments =
+      SegmentBuilder::buildSegments(Regions, *SingleByteCoverage);
 
   return ExpansionCoverage;
 }

>From aacb50ddf87d96b4a0644c7ef5d0a86dc94f069b Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Wed, 2 Oct 2024 23:25:52 +0900
Subject: [PATCH 02/72] [Coverage] Make SingleByteCoverage work consistent to
 merging

- Round `Counts` as 1/0
- Confirm both `ExecutionCount` and `AltExecutionCount` are in range.
---
 compiler-rt/test/profile/instrprof-block-coverage.c | 2 +-
 compiler-rt/test/profile/instrprof-entry-coverage.c | 2 +-
 llvm/include/llvm/ProfileData/InstrProf.h           | 5 ++++-
 llvm/lib/ProfileData/Coverage/CoverageMapping.cpp   | 3 +++
 llvm/lib/ProfileData/InstrProf.cpp                  | 2 +-
 llvm/lib/ProfileData/InstrProfReader.cpp            | 1 +
 6 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/compiler-rt/test/profile/instrprof-block-coverage.c b/compiler-rt/test/profile/instrprof-block-coverage.c
index 829d5af8dc3f9..8d924e1cac64d 100644
--- a/compiler-rt/test/profile/instrprof-block-coverage.c
+++ b/compiler-rt/test/profile/instrprof-block-coverage.c
@@ -49,4 +49,4 @@ int main(int argc, char *argv[]) {
 
 // CHECK-ERROR-NOT: warning: {{.*}}: Found inconsistent block coverage
 
-// COUNTS: Maximum function count: 4
+// COUNTS: Maximum function count: 1
diff --git a/compiler-rt/test/profile/instrprof-entry-coverage.c b/compiler-rt/test/profile/instrprof-entry-coverage.c
index 1c6816ba01964..b93a4e0c43ccd 100644
--- a/compiler-rt/test/profile/instrprof-entry-coverage.c
+++ b/compiler-rt/test/profile/instrprof-entry-coverage.c
@@ -36,4 +36,4 @@ int main(int argc, char *argv[]) {
 // CHECK-DAG: foo
 // CHECK-DAG: bar
 
-// COUNTS: Maximum function count: 2
+// COUNTS: Maximum function count: 1
diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h
index b0b2258735e2a..df9e76966bf42 100644
--- a/llvm/include/llvm/ProfileData/InstrProf.h
+++ b/llvm/include/llvm/ProfileData/InstrProf.h
@@ -830,6 +830,7 @@ struct InstrProfValueSiteRecord {
 /// Profiling information for a single function.
 struct InstrProfRecord {
   std::vector<uint64_t> Counts;
+  bool SingleByteCoverage = false;
   std::vector<uint8_t> BitmapBytes;
 
   InstrProfRecord() = default;
@@ -839,13 +840,15 @@ struct InstrProfRecord {
       : Counts(std::move(Counts)), BitmapBytes(std::move(BitmapBytes)) {}
   InstrProfRecord(InstrProfRecord &&) = default;
   InstrProfRecord(const InstrProfRecord &RHS)
-      : Counts(RHS.Counts), BitmapBytes(RHS.BitmapBytes),
+      : Counts(RHS.Counts), SingleByteCoverage(RHS.SingleByteCoverage),
+        BitmapBytes(RHS.BitmapBytes),
         ValueData(RHS.ValueData
                       ? std::make_unique<ValueProfData>(*RHS.ValueData)
                       : nullptr) {}
   InstrProfRecord &operator=(InstrProfRecord &&) = default;
   InstrProfRecord &operator=(const InstrProfRecord &RHS) {
     Counts = RHS.Counts;
+    SingleByteCoverage = RHS.SingleByteCoverage;
     BitmapBytes = RHS.BitmapBytes;
     if (!RHS.ValueData) {
       ValueData = nullptr;
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index a02136d5b0386..bc765c5938171 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -874,6 +874,9 @@ Error CoverageMapping::loadFunctionRecord(
       consumeError(std::move(E));
       return Error::success();
     }
+    assert(!SingleByteCoverage ||
+           (0 <= *ExecutionCount && *ExecutionCount <= 1 &&
+            0 <= *AltExecutionCount && *AltExecutionCount <= 1));
     Function.pushRegion(Region, *ExecutionCount, *AltExecutionCount);
 
     // Record ExpansionRegion.
diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp
index b9937c9429b77..0f6677b4d3571 100644
--- a/llvm/lib/ProfileData/InstrProf.cpp
+++ b/llvm/lib/ProfileData/InstrProf.cpp
@@ -952,7 +952,7 @@ void InstrProfRecord::merge(InstrProfRecord &Other, uint64_t Weight,
       Value = getInstrMaxCountValue();
       Overflowed = true;
     }
-    Counts[I] = Value;
+    Counts[I] = (SingleByteCoverage && Value != 0 ? 1 : Value);
     if (Overflowed)
       Warn(instrprof_error::counter_overflow);
   }
diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp
index b90617c74f6d1..a07d7f573275b 100644
--- a/llvm/lib/ProfileData/InstrProfReader.cpp
+++ b/llvm/lib/ProfileData/InstrProfReader.cpp
@@ -743,6 +743,7 @@ Error RawInstrProfReader<IntPtrT>::readRawCounts(
 
   Record.Counts.clear();
   Record.Counts.reserve(NumCounters);
+  Record.SingleByteCoverage = hasSingleByteCoverage();
   for (uint32_t I = 0; I < NumCounters; I++) {
     const char *Ptr =
         CountersStart + CounterBaseOffset + I * getCounterTypeSize();

>From b9bbc7cac3076594cd326ffa7f2d4fc4a92fabb9 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Sat, 5 Oct 2024 10:43:26 +0900
Subject: [PATCH 03/72] Rework. (Also reverts  "[Coverage] Move
 SingleByteCoverage out of CountedRegion")

---
 .../test/profile/instrprof-block-coverage.c   |  2 +-
 .../test/profile/instrprof-entry-coverage.c   |  2 +-
 .../ProfileData/Coverage/CoverageMapping.h    | 27 +++++++------
 llvm/include/llvm/ProfileData/InstrProf.h     |  5 +--
 .../ProfileData/Coverage/CoverageMapping.cpp  | 40 +++++++------------
 llvm/lib/ProfileData/InstrProf.cpp            |  2 +-
 llvm/lib/ProfileData/InstrProfReader.cpp      |  1 -
 7 files changed, 33 insertions(+), 46 deletions(-)

diff --git a/compiler-rt/test/profile/instrprof-block-coverage.c b/compiler-rt/test/profile/instrprof-block-coverage.c
index 8d924e1cac64d..829d5af8dc3f9 100644
--- a/compiler-rt/test/profile/instrprof-block-coverage.c
+++ b/compiler-rt/test/profile/instrprof-block-coverage.c
@@ -49,4 +49,4 @@ int main(int argc, char *argv[]) {
 
 // CHECK-ERROR-NOT: warning: {{.*}}: Found inconsistent block coverage
 
-// COUNTS: Maximum function count: 1
+// COUNTS: Maximum function count: 4
diff --git a/compiler-rt/test/profile/instrprof-entry-coverage.c b/compiler-rt/test/profile/instrprof-entry-coverage.c
index b93a4e0c43ccd..1c6816ba01964 100644
--- a/compiler-rt/test/profile/instrprof-entry-coverage.c
+++ b/compiler-rt/test/profile/instrprof-entry-coverage.c
@@ -36,4 +36,4 @@ int main(int argc, char *argv[]) {
 // CHECK-DAG: foo
 // CHECK-DAG: bar
 
-// COUNTS: Maximum function count: 1
+// COUNTS: Maximum function count: 2
diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index 77c447efe1a7c..fa07b3a9e8b14 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -359,15 +359,19 @@ struct CountedRegion : public CounterMappingRegion {
   uint64_t ExecutionCount;
   uint64_t FalseExecutionCount;
   bool Folded;
+  bool HasSingleByteCoverage;
 
-  CountedRegion(const CounterMappingRegion &R, uint64_t ExecutionCount)
+  CountedRegion(const CounterMappingRegion &R, uint64_t ExecutionCount,
+                bool HasSingleByteCoverage)
       : CounterMappingRegion(R), ExecutionCount(ExecutionCount),
-        FalseExecutionCount(0), Folded(false) {}
+        FalseExecutionCount(0), Folded(false),
+        HasSingleByteCoverage(HasSingleByteCoverage) {}
 
   CountedRegion(const CounterMappingRegion &R, uint64_t ExecutionCount,
-                uint64_t FalseExecutionCount)
+                uint64_t FalseExecutionCount, bool HasSingleByteCoverage)
       : CounterMappingRegion(R), ExecutionCount(ExecutionCount),
-        FalseExecutionCount(FalseExecutionCount), Folded(false) {}
+        FalseExecutionCount(FalseExecutionCount), Folded(false),
+        HasSingleByteCoverage(HasSingleByteCoverage) {}
 };
 
 /// MCDC Record grouping all information together.
@@ -698,12 +702,9 @@ struct FunctionRecord {
   std::vector<MCDCRecord> MCDCRecords;
   /// The number of times this function was executed.
   uint64_t ExecutionCount = 0;
-  bool SingleByteCoverage;
 
-  FunctionRecord(StringRef Name, ArrayRef<StringRef> Filenames,
-                 bool SingleByteCoverage)
-      : Name(Name), Filenames(Filenames.begin(), Filenames.end()),
-        SingleByteCoverage(SingleByteCoverage) {}
+  FunctionRecord(StringRef Name, ArrayRef<StringRef> Filenames)
+      : Name(Name), Filenames(Filenames.begin(), Filenames.end()) {}
 
   FunctionRecord(FunctionRecord &&FR) = default;
   FunctionRecord &operator=(FunctionRecord &&) = default;
@@ -713,10 +714,11 @@ struct FunctionRecord {
   }
 
   void pushRegion(CounterMappingRegion Region, uint64_t Count,
-                  uint64_t FalseCount) {
+                  uint64_t FalseCount, bool HasSingleByteCoverage) {
     if (Region.Kind == CounterMappingRegion::BranchRegion ||
         Region.Kind == CounterMappingRegion::MCDCBranchRegion) {
-      CountedBranchRegions.emplace_back(Region, Count, FalseCount);
+      CountedBranchRegions.emplace_back(Region, Count, FalseCount,
+                                        HasSingleByteCoverage);
       // If both counters are hard-coded to zero, then this region represents a
       // constant-folded branch.
       if (Region.Count.isZero() && Region.FalseCount.isZero())
@@ -725,7 +727,8 @@ struct FunctionRecord {
     }
     if (CountedRegions.empty())
       ExecutionCount = Count;
-    CountedRegions.emplace_back(Region, Count, FalseCount);
+    CountedRegions.emplace_back(Region, Count, FalseCount,
+                                HasSingleByteCoverage);
   }
 };
 
diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h
index df9e76966bf42..b0b2258735e2a 100644
--- a/llvm/include/llvm/ProfileData/InstrProf.h
+++ b/llvm/include/llvm/ProfileData/InstrProf.h
@@ -830,7 +830,6 @@ struct InstrProfValueSiteRecord {
 /// Profiling information for a single function.
 struct InstrProfRecord {
   std::vector<uint64_t> Counts;
-  bool SingleByteCoverage = false;
   std::vector<uint8_t> BitmapBytes;
 
   InstrProfRecord() = default;
@@ -840,15 +839,13 @@ struct InstrProfRecord {
       : Counts(std::move(Counts)), BitmapBytes(std::move(BitmapBytes)) {}
   InstrProfRecord(InstrProfRecord &&) = default;
   InstrProfRecord(const InstrProfRecord &RHS)
-      : Counts(RHS.Counts), SingleByteCoverage(RHS.SingleByteCoverage),
-        BitmapBytes(RHS.BitmapBytes),
+      : Counts(RHS.Counts), BitmapBytes(RHS.BitmapBytes),
         ValueData(RHS.ValueData
                       ? std::make_unique<ValueProfData>(*RHS.ValueData)
                       : nullptr) {}
   InstrProfRecord &operator=(InstrProfRecord &&) = default;
   InstrProfRecord &operator=(const InstrProfRecord &RHS) {
     Counts = RHS.Counts;
-    SingleByteCoverage = RHS.SingleByteCoverage;
     BitmapBytes = RHS.BitmapBytes;
     if (!RHS.ValueData) {
       ValueData = nullptr;
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index bc765c5938171..9a03dede84b6d 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -856,7 +856,7 @@ Error CoverageMapping::loadFunctionRecord(
     return Error::success();
 
   MCDCDecisionRecorder MCDCDecisions;
-  FunctionRecord Function(OrigFuncName, Record.Filenames, SingleByteCoverage);
+  FunctionRecord Function(OrigFuncName, Record.Filenames);
   for (const auto &Region : Record.MappingRegions) {
     // MCDCDecisionRegion should be handled first since it overlaps with
     // others inside.
@@ -874,10 +874,10 @@ Error CoverageMapping::loadFunctionRecord(
       consumeError(std::move(E));
       return Error::success();
     }
-    assert(!SingleByteCoverage ||
-           (0 <= *ExecutionCount && *ExecutionCount <= 1 &&
-            0 <= *AltExecutionCount && *AltExecutionCount <= 1));
-    Function.pushRegion(Region, *ExecutionCount, *AltExecutionCount);
+    Function.pushRegion(
+        Region, (SingleByteCoverage && *ExecutionCount ? 1 : *ExecutionCount),
+        (SingleByteCoverage && *AltExecutionCount ? 1 : *AltExecutionCount),
+        SingleByteCoverage);
 
     // Record ExpansionRegion.
     if (Region.Kind == CounterMappingRegion::ExpansionRegion) {
@@ -1273,8 +1273,7 @@ class SegmentBuilder {
 
   /// Combine counts of regions which cover the same area.
   static ArrayRef<CountedRegion>
-  combineRegions(MutableArrayRef<CountedRegion> Regions,
-                 bool SingleByteCoverage) {
+  combineRegions(MutableArrayRef<CountedRegion> Regions) {
     if (Regions.empty())
       return Regions;
     auto Active = Regions.begin();
@@ -1301,7 +1300,9 @@ class SegmentBuilder {
       // We add counts of the regions of the same kind as the active region
       // to handle the both situations.
       if (I->Kind == Active->Kind) {
-        if (SingleByteCoverage)
+        assert(I->HasSingleByteCoverage == Active->HasSingleByteCoverage &&
+               "Regions are generated in different coverage modes");
+        if (I->HasSingleByteCoverage)
           Active->ExecutionCount = Active->ExecutionCount || I->ExecutionCount;
         else
           Active->ExecutionCount += I->ExecutionCount;
@@ -1313,14 +1314,12 @@ class SegmentBuilder {
 public:
   /// Build a sorted list of CoverageSegments from a list of Regions.
   static std::vector<CoverageSegment>
-  buildSegments(MutableArrayRef<CountedRegion> Regions,
-                bool SingleByteCoverage) {
+  buildSegments(MutableArrayRef<CountedRegion> Regions) {
     std::vector<CoverageSegment> Segments;
     SegmentBuilder Builder(Segments);
 
     sortNestedRegions(Regions);
-    ArrayRef<CountedRegion> CombinedRegions =
-        combineRegions(Regions, SingleByteCoverage);
+    ArrayRef<CountedRegion> CombinedRegions = combineRegions(Regions);
 
     LLVM_DEBUG({
       dbgs() << "Combined regions:\n";
@@ -1407,14 +1406,10 @@ CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) const {
   // the filename, we may get back some records that are not in the file.
   ArrayRef<unsigned> RecordIndices =
       getImpreciseRecordIndicesForFilename(Filename);
-  std::optional<bool> SingleByteCoverage;
   for (unsigned RecordIndex : RecordIndices) {
     const FunctionRecord &Function = Functions[RecordIndex];
     auto MainFileID = findMainViewFileID(Filename, Function);
     auto FileIDs = gatherFileIDs(Filename, Function);
-    assert(!SingleByteCoverage ||
-           *SingleByteCoverage == Function.SingleByteCoverage);
-    SingleByteCoverage = Function.SingleByteCoverage;
     for (const auto &CR : Function.CountedRegions)
       if (FileIDs.test(CR.FileID)) {
         Regions.push_back(CR);
@@ -1432,8 +1427,7 @@ CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) const {
   }
 
   LLVM_DEBUG(dbgs() << "Emitting segments for file: " << Filename << "\n");
-  FileCoverage.Segments =
-      SegmentBuilder::buildSegments(Regions, *SingleByteCoverage);
+  FileCoverage.Segments = SegmentBuilder::buildSegments(Regions);
 
   return FileCoverage;
 }
@@ -1489,8 +1483,7 @@ CoverageMapping::getCoverageForFunction(const FunctionRecord &Function) const {
 
   LLVM_DEBUG(dbgs() << "Emitting segments for function: " << Function.Name
                     << "\n");
-  FunctionCoverage.Segments =
-      SegmentBuilder::buildSegments(Regions, Function.SingleByteCoverage);
+  FunctionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
 
   return FunctionCoverage;
 }
@@ -1500,12 +1493,8 @@ CoverageData CoverageMapping::getCoverageForExpansion(
   CoverageData ExpansionCoverage(
       Expansion.Function.Filenames[Expansion.FileID]);
   std::vector<CountedRegion> Regions;
-  std::optional<bool> SingleByteCoverage;
   for (const auto &CR : Expansion.Function.CountedRegions)
     if (CR.FileID == Expansion.FileID) {
-      assert(!SingleByteCoverage ||
-             *SingleByteCoverage == Expansion.Function.SingleByteCoverage);
-      SingleByteCoverage = Expansion.Function.SingleByteCoverage;
       Regions.push_back(CR);
       if (isExpansion(CR, Expansion.FileID))
         ExpansionCoverage.Expansions.emplace_back(CR, Expansion.Function);
@@ -1517,8 +1506,7 @@ CoverageData CoverageMapping::getCoverageForExpansion(
 
   LLVM_DEBUG(dbgs() << "Emitting segments for expansion of file "
                     << Expansion.FileID << "\n");
-  ExpansionCoverage.Segments =
-      SegmentBuilder::buildSegments(Regions, *SingleByteCoverage);
+  ExpansionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
 
   return ExpansionCoverage;
 }
diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp
index 0f6677b4d3571..b9937c9429b77 100644
--- a/llvm/lib/ProfileData/InstrProf.cpp
+++ b/llvm/lib/ProfileData/InstrProf.cpp
@@ -952,7 +952,7 @@ void InstrProfRecord::merge(InstrProfRecord &Other, uint64_t Weight,
       Value = getInstrMaxCountValue();
       Overflowed = true;
     }
-    Counts[I] = (SingleByteCoverage && Value != 0 ? 1 : Value);
+    Counts[I] = Value;
     if (Overflowed)
       Warn(instrprof_error::counter_overflow);
   }
diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp
index a07d7f573275b..b90617c74f6d1 100644
--- a/llvm/lib/ProfileData/InstrProfReader.cpp
+++ b/llvm/lib/ProfileData/InstrProfReader.cpp
@@ -743,7 +743,6 @@ Error RawInstrProfReader<IntPtrT>::readRawCounts(
 
   Record.Counts.clear();
   Record.Counts.reserve(NumCounters);
-  Record.SingleByteCoverage = hasSingleByteCoverage();
   for (uint32_t I = 0; I < NumCounters; I++) {
     const char *Ptr =
         CountersStart + CounterBaseOffset + I * getCounterTypeSize();

>From 618e63946923a460b2684738e636c77b1706322a Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Thu, 17 Oct 2024 01:22:54 +0900
Subject: [PATCH 04/72] Introduce CounterExpressionBuilder::replace(C, Map)

This return a counter for each term in the expression replaced by
ReplaceMap.

At the moment, this doesn't update the Map, so Map is marked as `const`.
---
 .../ProfileData/Coverage/CoverageMapping.h    |  6 ++++
 .../ProfileData/Coverage/CoverageMapping.cpp  | 32 +++++++++++++++++++
 2 files changed, 38 insertions(+)

diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index fa07b3a9e8b14..d6528bd407ef3 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -34,6 +34,7 @@
 #include <cassert>
 #include <cstdint>
 #include <iterator>
+#include <map>
 #include <memory>
 #include <sstream>
 #include <string>
@@ -213,6 +214,11 @@ class CounterExpressionBuilder {
   /// Return a counter that represents the expression that subtracts RHS from
   /// LHS.
   Counter subtract(Counter LHS, Counter RHS, bool Simplify = true);
+
+  using ReplaceMap = std::map<Counter, Counter>;
+
+  /// Return a counter for each term in the expression replaced by ReplaceMap.
+  Counter replace(Counter C, const ReplaceMap &Map);
 };
 
 using LineColPair = std::pair<unsigned, unsigned>;
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index c713371da81e4..b50f025d261e1 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -135,6 +135,38 @@ Counter CounterExpressionBuilder::subtract(Counter LHS, Counter RHS,
   return Simplify ? simplify(Cnt) : Cnt;
 }
 
+Counter CounterExpressionBuilder::replace(Counter C, const ReplaceMap &Map) {
+  auto I = Map.find(C);
+
+  // Replace C with the Map even if C is Expression.
+  if (I != Map.end())
+    return I->second;
+
+  // Traverse only Expression.
+  if (!C.isExpression())
+    return C;
+
+  auto CE = Expressions[C.getExpressionID()];
+  auto NewLHS = replace(CE.LHS, Map);
+  auto NewRHS = replace(CE.RHS, Map);
+
+  // Reconstruct Expression with induced subexpressions.
+  switch (CE.Kind) {
+  case CounterExpression::Add:
+    C = add(NewLHS, NewRHS);
+    break;
+  case CounterExpression::Subtract:
+    C = subtract(NewLHS, NewRHS);
+    break;
+  }
+
+  // Reconfirm if the reconstructed expression would hit the Map.
+  if ((I = Map.find(C)) != Map.end())
+    return I->second;
+
+  return C;
+}
+
 void CounterMappingContext::dump(const Counter &C, raw_ostream &OS) const {
   switch (C.getKind()) {
   case Counter::Zero:

>From fc697f04fd6c9f3c217ce04e3f1dd082c1f1a705 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Wed, 16 Oct 2024 23:16:53 +0900
Subject: [PATCH 05/72] [Coverage] Introduce `getBranchCounterPair()`. NFC.

This aggregates the generation of branch counter pair as `ExecCnt` and
`SkipCnt`, to aggregate `CounterExpr::subtract`. At the moment:

- This change preserves the behavior of
  `llvm::EnableSingleByteCoverage`. Almost of SingleByteCoverage will
  be cleaned up by coming commits.

- `getBranchCounterPair()` is not called in
  `llvm::EnableSingleByteCoverage`. I will implement the new behavior
  of SingleByteCoverage in it.

- `IsCounterEqual(Out, Par)` is introduced instead of
  `Counter::operator==`. Tweaks would be required for the comparison
  for additional counters.

- Braces around `assert()` is intentional. I will add a statement there.

https://discourse.llvm.org/t/rfc-integrating-singlebytecoverage-with-branch-coverage/82492
---
 clang/lib/CodeGen/CoverageMappingGen.cpp | 177 +++++++++++++----------
 1 file changed, 102 insertions(+), 75 deletions(-)

diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index 07015834bc84f..0bfad9cbcbe12 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -941,6 +941,19 @@ struct CounterCoverageMappingBuilder
     return Counter::getCounter(CounterMap[S]);
   }
 
+  std::pair<Counter, Counter> getBranchCounterPair(const Stmt *S,
+                                                   Counter ParentCnt) {
+    Counter ExecCnt = getRegionCounter(S);
+    return {ExecCnt, Builder.subtract(ParentCnt, ExecCnt)};
+  }
+
+  bool IsCounterEqual(Counter OutCount, Counter ParentCount) {
+    if (OutCount == ParentCount)
+      return true;
+
+    return false;
+  }
+
   /// Push a region onto the stack.
   ///
   /// Returns the index on the stack where the region was pushed. This can be
@@ -1592,6 +1605,13 @@ struct CounterCoverageMappingBuilder
         llvm::EnableSingleByteCoverage
             ? getRegionCounter(S->getCond())
             : addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
+    auto [ExecCount, ExitCount] =
+        (llvm::EnableSingleByteCoverage
+             ? std::make_pair(getRegionCounter(S), Counter::getZero())
+             : getBranchCounterPair(S, CondCount));
+    if (!llvm::EnableSingleByteCoverage) {
+      assert(ExecCount.isZero() || ExecCount == BodyCount);
+    }
     propagateCounts(CondCount, S->getCond());
     adjustForOutOfOrderTraversal(getEnd(S));
 
@@ -1600,13 +1620,11 @@ struct CounterCoverageMappingBuilder
     if (Gap)
       fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
 
-    Counter OutCount =
-        llvm::EnableSingleByteCoverage
-            ? getRegionCounter(S)
-            : addCounters(BC.BreakCount,
-                          subtractCounters(CondCount, BodyCount));
+    Counter OutCount = llvm::EnableSingleByteCoverage
+                           ? getRegionCounter(S)
+                           : addCounters(BC.BreakCount, ExitCount);
 
-    if (OutCount != ParentCount) {
+    if (!IsCounterEqual(OutCount, ParentCount)) {
       pushRegion(OutCount);
       GapRegionCounter = OutCount;
       if (BodyHasTerminateStmt)
@@ -1615,8 +1633,7 @@ struct CounterCoverageMappingBuilder
 
     // Create Branch Region around condition.
     if (!llvm::EnableSingleByteCoverage)
-      createBranchRegion(S->getCond(), BodyCount,
-                         subtractCounters(CondCount, BodyCount));
+      createBranchRegion(S->getCond(), BodyCount, ExitCount);
   }
 
   void VisitDoStmt(const DoStmt *S) {
@@ -1645,22 +1662,26 @@ struct CounterCoverageMappingBuilder
     Counter CondCount = llvm::EnableSingleByteCoverage
                             ? getRegionCounter(S->getCond())
                             : addCounters(BackedgeCount, BC.ContinueCount);
+    auto [ExecCount, ExitCount] =
+        (llvm::EnableSingleByteCoverage
+             ? std::make_pair(getRegionCounter(S), Counter::getZero())
+             : getBranchCounterPair(S, CondCount));
+    if (!llvm::EnableSingleByteCoverage) {
+      assert(ExecCount.isZero() || ExecCount == BodyCount);
+    }
     propagateCounts(CondCount, S->getCond());
 
-    Counter OutCount =
-        llvm::EnableSingleByteCoverage
-            ? getRegionCounter(S)
-            : addCounters(BC.BreakCount,
-                          subtractCounters(CondCount, BodyCount));
-    if (OutCount != ParentCount) {
+    Counter OutCount = llvm::EnableSingleByteCoverage
+                           ? getRegionCounter(S)
+                           : addCounters(BC.BreakCount, ExitCount);
+    if (!IsCounterEqual(OutCount, ParentCount)) {
       pushRegion(OutCount);
       GapRegionCounter = OutCount;
     }
 
     // Create Branch Region around condition.
     if (!llvm::EnableSingleByteCoverage)
-      createBranchRegion(S->getCond(), BodyCount,
-                         subtractCounters(CondCount, BodyCount));
+      createBranchRegion(S->getCond(), BodyCount, ExitCount);
 
     if (BodyHasTerminateStmt)
       HasTerminateStmt = true;
@@ -1709,6 +1730,13 @@ struct CounterCoverageMappingBuilder
             : addCounters(
                   addCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount),
                   IncrementBC.ContinueCount);
+    auto [ExecCount, ExitCount] =
+        (llvm::EnableSingleByteCoverage
+             ? std::make_pair(getRegionCounter(S), Counter::getZero())
+             : getBranchCounterPair(S, CondCount));
+    if (!llvm::EnableSingleByteCoverage) {
+      assert(ExecCount.isZero() || ExecCount == BodyCount);
+    }
 
     if (const Expr *Cond = S->getCond()) {
       propagateCounts(CondCount, Cond);
@@ -1723,9 +1751,8 @@ struct CounterCoverageMappingBuilder
     Counter OutCount =
         llvm::EnableSingleByteCoverage
             ? getRegionCounter(S)
-            : addCounters(BodyBC.BreakCount, IncrementBC.BreakCount,
-                          subtractCounters(CondCount, BodyCount));
-    if (OutCount != ParentCount) {
+            : addCounters(BodyBC.BreakCount, IncrementBC.BreakCount, ExitCount);
+    if (!IsCounterEqual(OutCount, ParentCount)) {
       pushRegion(OutCount);
       GapRegionCounter = OutCount;
       if (BodyHasTerminateStmt)
@@ -1734,8 +1761,7 @@ struct CounterCoverageMappingBuilder
 
     // Create Branch Region around condition.
     if (!llvm::EnableSingleByteCoverage)
-      createBranchRegion(S->getCond(), BodyCount,
-                         subtractCounters(CondCount, BodyCount));
+      createBranchRegion(S->getCond(), BodyCount, ExitCount);
   }
 
   void VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
@@ -1764,15 +1790,21 @@ struct CounterCoverageMappingBuilder
       fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
 
     Counter OutCount;
+    Counter ExitCount;
     Counter LoopCount;
     if (llvm::EnableSingleByteCoverage)
       OutCount = getRegionCounter(S);
     else {
-      LoopCount = addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
-      OutCount =
-          addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount));
+      LoopCount =
+          (ParentCount.isZero()
+               ? ParentCount
+               : addCounters(ParentCount, BackedgeCount, BC.ContinueCount));
+      auto [ExecCount, SkipCount] = getBranchCounterPair(S, LoopCount);
+      ExitCount = SkipCount;
+      assert(ExecCount.isZero() || ExecCount == BodyCount);
+      OutCount = addCounters(BC.BreakCount, ExitCount);
     }
-    if (OutCount != ParentCount) {
+    if (!IsCounterEqual(OutCount, ParentCount)) {
       pushRegion(OutCount);
       GapRegionCounter = OutCount;
       if (BodyHasTerminateStmt)
@@ -1781,8 +1813,7 @@ struct CounterCoverageMappingBuilder
 
     // Create Branch Region around condition.
     if (!llvm::EnableSingleByteCoverage)
-      createBranchRegion(S->getCond(), BodyCount,
-                         subtractCounters(LoopCount, BodyCount));
+      createBranchRegion(S->getCond(), BodyCount, ExitCount);
   }
 
   void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) {
@@ -1803,10 +1834,13 @@ struct CounterCoverageMappingBuilder
       fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
 
     Counter LoopCount =
-        addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
-    Counter OutCount =
-        addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount));
-    if (OutCount != ParentCount) {
+        (ParentCount.isZero()
+             ? ParentCount
+             : addCounters(ParentCount, BackedgeCount, BC.ContinueCount));
+    auto [ExecCount, ExitCount] = getBranchCounterPair(S, LoopCount);
+    assert(ExecCount.isZero() || ExecCount == BodyCount);
+    Counter OutCount = addCounters(BC.BreakCount, ExitCount);
+    if (!IsCounterEqual(OutCount, ParentCount)) {
       pushRegion(OutCount);
       GapRegionCounter = OutCount;
     }
@@ -2016,9 +2050,12 @@ struct CounterCoverageMappingBuilder
     extendRegion(S->getCond());
 
     Counter ParentCount = getRegion().getCounter();
-    Counter ThenCount = llvm::EnableSingleByteCoverage
-                            ? getRegionCounter(S->getThen())
-                            : getRegionCounter(S);
+    auto [ThenCount, ElseCount] =
+        (llvm::EnableSingleByteCoverage
+             ? std::make_pair(getRegionCounter(S->getThen()),
+                              (S->getElse() ? getRegionCounter(S->getElse())
+                                            : Counter::getZero()))
+             : getBranchCounterPair(S, ParentCount));
 
     // Emitting a counter for the condition makes it easier to interpret the
     // counter for the body when looking at the coverage.
@@ -2033,12 +2070,6 @@ struct CounterCoverageMappingBuilder
     extendRegion(S->getThen());
     Counter OutCount = propagateCounts(ThenCount, S->getThen());
 
-    Counter ElseCount;
-    if (!llvm::EnableSingleByteCoverage)
-      ElseCount = subtractCounters(ParentCount, ThenCount);
-    else if (S->getElse())
-      ElseCount = getRegionCounter(S->getElse());
-
     if (const Stmt *Else = S->getElse()) {
       bool ThenHasTerminateStmt = HasTerminateStmt;
       HasTerminateStmt = false;
@@ -2061,15 +2092,14 @@ struct CounterCoverageMappingBuilder
     if (llvm::EnableSingleByteCoverage)
       OutCount = getRegionCounter(S);
 
-    if (OutCount != ParentCount) {
+    if (!IsCounterEqual(OutCount, ParentCount)) {
       pushRegion(OutCount);
       GapRegionCounter = OutCount;
     }
 
     if (!S->isConsteval() && !llvm::EnableSingleByteCoverage)
       // Create Branch Region around condition.
-      createBranchRegion(S->getCond(), ThenCount,
-                         subtractCounters(ParentCount, ThenCount));
+      createBranchRegion(S->getCond(), ThenCount, ElseCount);
   }
 
   void VisitCXXTryStmt(const CXXTryStmt *S) {
@@ -2095,9 +2125,11 @@ struct CounterCoverageMappingBuilder
     extendRegion(E);
 
     Counter ParentCount = getRegion().getCounter();
-    Counter TrueCount = llvm::EnableSingleByteCoverage
-                            ? getRegionCounter(E->getTrueExpr())
-                            : getRegionCounter(E);
+    auto [TrueCount, FalseCount] =
+        (llvm::EnableSingleByteCoverage
+             ? std::make_pair(getRegionCounter(E->getTrueExpr()),
+                              getRegionCounter(E->getFalseExpr()))
+             : getBranchCounterPair(E, ParentCount));
     Counter OutCount;
 
     if (const auto *BCO = dyn_cast<BinaryConditionalOperator>(E)) {
@@ -2116,25 +2148,20 @@ struct CounterCoverageMappingBuilder
     }
 
     extendRegion(E->getFalseExpr());
-    Counter FalseCount = llvm::EnableSingleByteCoverage
-                             ? getRegionCounter(E->getFalseExpr())
-                             : subtractCounters(ParentCount, TrueCount);
-
     Counter FalseOutCount = propagateCounts(FalseCount, E->getFalseExpr());
     if (llvm::EnableSingleByteCoverage)
       OutCount = getRegionCounter(E);
     else
       OutCount = addCounters(OutCount, FalseOutCount);
 
-    if (OutCount != ParentCount) {
+    if (!IsCounterEqual(OutCount, ParentCount)) {
       pushRegion(OutCount);
       GapRegionCounter = OutCount;
     }
 
     // Create Branch Region around condition.
     if (!llvm::EnableSingleByteCoverage)
-      createBranchRegion(E->getCond(), TrueCount,
-                         subtractCounters(ParentCount, TrueCount));
+      createBranchRegion(E->getCond(), TrueCount, FalseCount);
   }
 
   void createOrCancelDecision(const BinaryOperator *E, unsigned Since) {
@@ -2233,27 +2260,27 @@ struct CounterCoverageMappingBuilder
     extendRegion(E->getRHS());
     propagateCounts(getRegionCounter(E), E->getRHS());
 
+    if (llvm::EnableSingleByteCoverage)
+      return;
+
     // Track RHS True/False Decision.
     const auto DecisionRHS = MCDCBuilder.back();
 
+    // Extract the Parent Region Counter.
+    Counter ParentCnt = getRegion().getCounter();
+
     // Extract the RHS's Execution Counter.
-    Counter RHSExecCnt = getRegionCounter(E);
+    auto [RHSExecCnt, LHSExitCnt] = getBranchCounterPair(E, ParentCnt);
 
     // Extract the RHS's "True" Instance Counter.
-    Counter RHSTrueCnt = getRegionCounter(E->getRHS());
-
-    // Extract the Parent Region Counter.
-    Counter ParentCnt = getRegion().getCounter();
+    auto [RHSTrueCnt, RHSExitCnt] =
+        getBranchCounterPair(E->getRHS(), RHSExecCnt);
 
     // Create Branch Region around LHS condition.
-    if (!llvm::EnableSingleByteCoverage)
-      createBranchRegion(E->getLHS(), RHSExecCnt,
-                         subtractCounters(ParentCnt, RHSExecCnt), DecisionLHS);
+    createBranchRegion(E->getLHS(), RHSExecCnt, LHSExitCnt, DecisionLHS);
 
     // Create Branch Region around RHS condition.
-    if (!llvm::EnableSingleByteCoverage)
-      createBranchRegion(E->getRHS(), RHSTrueCnt,
-                         subtractCounters(RHSExecCnt, RHSTrueCnt), DecisionRHS);
+    createBranchRegion(E->getRHS(), RHSTrueCnt, RHSExitCnt, DecisionRHS);
 
     // Create MCDC Decision Region if at top-level (root).
     if (IsRootNode)
@@ -2294,31 +2321,31 @@ struct CounterCoverageMappingBuilder
     extendRegion(E->getRHS());
     propagateCounts(getRegionCounter(E), E->getRHS());
 
+    if (llvm::EnableSingleByteCoverage)
+      return;
+
     // Track RHS True/False Decision.
     const auto DecisionRHS = MCDCBuilder.back();
 
+    // Extract the Parent Region Counter.
+    Counter ParentCnt = getRegion().getCounter();
+
     // Extract the RHS's Execution Counter.
-    Counter RHSExecCnt = getRegionCounter(E);
+    auto [RHSExecCnt, LHSExitCnt] = getBranchCounterPair(E, ParentCnt);
 
     // Extract the RHS's "False" Instance Counter.
-    Counter RHSFalseCnt = getRegionCounter(E->getRHS());
+    auto [RHSFalseCnt, RHSExitCnt] =
+        getBranchCounterPair(E->getRHS(), RHSExecCnt);
 
     if (!shouldVisitRHS(E->getLHS())) {
       GapRegionCounter = OutCount;
     }
 
-    // Extract the Parent Region Counter.
-    Counter ParentCnt = getRegion().getCounter();
-
     // Create Branch Region around LHS condition.
-    if (!llvm::EnableSingleByteCoverage)
-      createBranchRegion(E->getLHS(), subtractCounters(ParentCnt, RHSExecCnt),
-                         RHSExecCnt, DecisionLHS);
+    createBranchRegion(E->getLHS(), LHSExitCnt, RHSExecCnt, DecisionLHS);
 
     // Create Branch Region around RHS condition.
-    if (!llvm::EnableSingleByteCoverage)
-      createBranchRegion(E->getRHS(), subtractCounters(RHSExecCnt, RHSFalseCnt),
-                         RHSFalseCnt, DecisionRHS);
+    createBranchRegion(E->getRHS(), RHSExitCnt, RHSFalseCnt, DecisionRHS);
 
     // Create MCDC Decision Region if at top-level (root).
     if (IsRootNode)

>From e4172ca273a6fdfcbfc4662c9e37276ef34c2df4 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Thu, 17 Oct 2024 00:32:26 +0900
Subject: [PATCH 06/72] Introduce the type `CounterPair` for RegionCounterMap

`CounterPair` can hold `<uint32_t, uint32_t>` instead of current
`unsigned`, to hold also the counter number of SkipPath. For now, this
change provides the skeleton and only `CounterPair::first` is used.

Each counter number can have `None` to suppress emitting counter
increment. `second` is initialized as `None` by default, since most
`Stmt*` don't have a pair of counters.

This change also provides stubs for the verifyer. I'll provide the
impl of verifier for `+Asserts` later.

`markStmtAsUsed(bool, Stmt*)` may be used to inform that other side
counter may not emitted.

`markStmtMaybeUsed(S)` may be used for the `Stmt` and its inner will
be excluded for emission in the case of skipping by constant
folding. I put it into places where I found.

`verifyCounterMap()` will check the coverage map the counter map and
can be used to report inconsistency.

These verifier methods shall be eliminated in `-Asserts`.

https://discourse.llvm.org/t/rfc-integrating-singlebytecoverage-with-branch-coverage/82492
---
 clang/lib/CodeGen/CGDecl.cpp             |  9 ++++++++-
 clang/lib/CodeGen/CGExpr.cpp             |  1 +
 clang/lib/CodeGen/CGExprScalar.cpp       |  9 +++++++--
 clang/lib/CodeGen/CGStmt.cpp             |  3 +++
 clang/lib/CodeGen/CodeGenFunction.cpp    |  3 +++
 clang/lib/CodeGen/CodeGenFunction.h      |  6 ++++++
 clang/lib/CodeGen/CodeGenModule.h        | 19 +++++++++++++++++++
 clang/lib/CodeGen/CodeGenPGO.cpp         | 14 ++++++++++----
 clang/lib/CodeGen/CodeGenPGO.h           | 17 +++++++++++++++--
 clang/lib/CodeGen/CoverageMappingGen.cpp |  6 +++---
 clang/lib/CodeGen/CoverageMappingGen.h   |  5 +++--
 11 files changed, 78 insertions(+), 14 deletions(-)

diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 563f728e29d78..ed5f41b624b62 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -362,6 +362,8 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D,
     return GV;
   }
 
+  PGO.markStmtMaybeUsed(D.getInit()); // FIXME: Too lazy
+
 #ifndef NDEBUG
   CharUnits VarSize = CGM.getContext().getTypeSizeInChars(D.getType()) +
                       D.getFlexibleArrayInitChars(getContext());
@@ -1869,7 +1871,10 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
   // If we are at an unreachable point, we don't need to emit the initializer
   // unless it contains a label.
   if (!HaveInsertPoint()) {
-    if (!Init || !ContainsLabel(Init)) return;
+    if (!Init || !ContainsLabel(Init)) {
+      PGO.markStmtMaybeUsed(Init);
+      return;
+    }
     EnsureInsertPoint();
   }
 
@@ -1978,6 +1983,8 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
     return EmitExprAsInit(Init, &D, lv, capturedByInit);
   }
 
+  PGO.markStmtMaybeUsed(Init);
+
   if (!emission.IsConstantAggregate) {
     // For simple scalar/complex initialization, store the value directly.
     LValue lv = MakeAddrLValue(Loc, type);
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 52d2f6d52abf9..2fd6b02a3395e 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -5134,6 +5134,7 @@ std::optional<LValue> HandleConditionalOperatorLValueSimpleCase(
       // If the true case is live, we need to track its region.
       if (CondExprBool)
         CGF.incrementProfileCounter(E);
+      CGF.markStmtMaybeUsed(Dead);
       // If a throw expression we emit it and return an undefined lvalue
       // because it can't be used.
       if (auto *ThrowExpr = dyn_cast<CXXThrowExpr>(Live->IgnoreParens())) {
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index b7f5b932c56b6..74e93f889f426 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -4982,8 +4982,10 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
     }
 
     // 0 && RHS: If it is safe, just elide the RHS, and return 0/false.
-    if (!CGF.ContainsLabel(E->getRHS()))
+    if (!CGF.ContainsLabel(E->getRHS())) {
+      CGF.markStmtMaybeUsed(E->getRHS());
       return llvm::Constant::getNullValue(ResTy);
+    }
   }
 
   // If the top of the logical operator nest, reset the MCDC temp to 0.
@@ -5122,8 +5124,10 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
     }
 
     // 1 || RHS: If it is safe, just elide the RHS, and return 1/true.
-    if (!CGF.ContainsLabel(E->getRHS()))
+    if (!CGF.ContainsLabel(E->getRHS())) {
+      CGF.markStmtMaybeUsed(E->getRHS());
       return llvm::ConstantInt::get(ResTy, 1);
+    }
   }
 
   // If the top of the logical operator nest, reset the MCDC temp to 0.
@@ -5247,6 +5251,7 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
         CGF.incrementProfileCounter(E);
       }
       Value *Result = Visit(live);
+      CGF.markStmtMaybeUsed(dead);
 
       // If the live part is a throw expression, it acts like it has a void
       // type, so evaluating it returns a null Value*.  However, a conditional
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 41dc91c578c80..dbc1ce9bf993c 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -76,6 +76,7 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
       // Verify that any decl statements were handled as simple, they may be in
       // scope of subsequent reachable statements.
       assert(!isa<DeclStmt>(*S) && "Unexpected DeclStmt!");
+      PGO.markStmtMaybeUsed(S);
       return;
     }
 
@@ -845,6 +846,7 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
         RunCleanupsScope ExecutedScope(*this);
         EmitStmt(Executed);
       }
+      PGO.markStmtMaybeUsed(Skipped);
       return;
     }
   }
@@ -2170,6 +2172,7 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
       for (unsigned i = 0, e = CaseStmts.size(); i != e; ++i)
         EmitStmt(CaseStmts[i]);
       incrementProfileCounter(&S);
+      PGO.markStmtMaybeUsed(S.getBody());
 
       // Now we want to restore the saved switch instance so that nested
       // switches continue to function properly
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index 24723e392c2a3..371aa494e014b 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -1606,6 +1606,8 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
   // Emit the standard function epilogue.
   FinishFunction(BodyRange.getEnd());
 
+  PGO.verifyCounterMap();
+
   // If we haven't marked the function nothrow through other means, do
   // a quick pass now to see if we can.
   if (!CurFn->doesNotThrow())
@@ -1728,6 +1730,7 @@ bool CodeGenFunction::ConstantFoldsToSimpleInteger(const Expr *Cond,
   if (!AllowLabels && CodeGenFunction::ContainsLabel(Cond))
     return false;  // Contains a label.
 
+  PGO.markStmtMaybeUsed(Cond);
   ResultInt = Int;
   return true;
 }
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 9ba0ed02a564d..89ac3b342d0a7 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -1620,6 +1620,12 @@ class CodeGenFunction : public CodeGenTypeCache {
                                             uint64_t LoopCount) const;
 
 public:
+  std::pair<bool, bool> getIsCounterPair(const Stmt *S) const {
+    return PGO.getIsCounterPair(S);
+  }
+
+  void markStmtMaybeUsed(const Stmt *S) { PGO.markStmtMaybeUsed(S); }
+
   /// Increment the profiler's counter for the given statement by \p StepV.
   /// If \p StepV is null, the default increment is 1.
   void incrementProfileCounter(const Stmt *S, llvm::Value *StepV = nullptr) {
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index c58bb88035ca8..9dc497321b42a 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -101,6 +101,25 @@ enum ForDefinition_t : bool {
   ForDefinition = true
 };
 
+class CounterPair : public std::pair<uint32_t, uint32_t> {
+private:
+  static constexpr uint32_t None = (1u << 31); /// None is set
+
+public:
+  static constexpr uint32_t Mask = None - 1;
+
+public:
+  CounterPair(unsigned Val = 0) {
+    assert(!(Val & ~Mask));
+    first = Val;
+    second = None;
+  }
+
+  std::pair<bool, bool> getIsCounterPair() const {
+    return {!(first & None), !(second & None)};
+  }
+};
+
 struct OrderGlobalInitsOrStermFinalizers {
   unsigned int priority;
   unsigned int lex_order;
diff --git a/clang/lib/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp
index 820bb521ccf85..069469e3de856 100644
--- a/clang/lib/CodeGen/CodeGenPGO.cpp
+++ b/clang/lib/CodeGen/CodeGenPGO.cpp
@@ -164,7 +164,7 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
   /// The function hash.
   PGOHash Hash;
   /// The map of statements to counters.
-  llvm::DenseMap<const Stmt *, unsigned> &CounterMap;
+  llvm::DenseMap<const Stmt *, CounterPair> &CounterMap;
   /// The state of MC/DC Coverage in this function.
   MCDC::State &MCDCState;
   /// Maximum number of supported MC/DC conditions in a boolean expression.
@@ -175,7 +175,7 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
   DiagnosticsEngine &Diag;
 
   MapRegionCounters(PGOHashVersion HashVersion, uint64_t ProfileVersion,
-                    llvm::DenseMap<const Stmt *, unsigned> &CounterMap,
+                    llvm::DenseMap<const Stmt *, CounterPair> &CounterMap,
                     MCDC::State &MCDCState, unsigned MCDCMaxCond,
                     DiagnosticsEngine &Diag)
       : NextCounter(0), Hash(HashVersion), CounterMap(CounterMap),
@@ -1084,7 +1084,7 @@ void CodeGenPGO::mapRegionCounters(const Decl *D) {
       (CGM.getCodeGenOpts().MCDCCoverage ? CGM.getCodeGenOpts().MCDCMaxConds
                                          : 0);
 
-  RegionCounterMap.reset(new llvm::DenseMap<const Stmt *, unsigned>);
+  RegionCounterMap.reset(new llvm::DenseMap<const Stmt *, CounterPair>);
   RegionMCDCState.reset(new MCDC::State);
   MapRegionCounters Walker(HashVersion, ProfileVersion, *RegionCounterMap,
                            *RegionMCDCState, MCDCMaxConditions, CGM.getDiags());
@@ -1186,12 +1186,18 @@ CodeGenPGO::applyFunctionAttributes(llvm::IndexedInstrProfReader *PGOReader,
   Fn->setEntryCount(FunctionCount);
 }
 
+std::pair<bool, bool> CodeGenPGO::getIsCounterPair(const Stmt *S) const {
+  if (!RegionCounterMap || RegionCounterMap->count(S) == 0)
+    return {false, false};
+  return (*RegionCounterMap)[S].getIsCounterPair();
+}
+
 void CodeGenPGO::emitCounterSetOrIncrement(CGBuilderTy &Builder, const Stmt *S,
                                            llvm::Value *StepV) {
   if (!RegionCounterMap || !Builder.GetInsertBlock())
     return;
 
-  unsigned Counter = (*RegionCounterMap)[S];
+  unsigned Counter = (*RegionCounterMap)[S].first;
 
   // Make sure that pointer to global is passed in with zero addrspace
   // This is relevant during GPU profiling
diff --git a/clang/lib/CodeGen/CodeGenPGO.h b/clang/lib/CodeGen/CodeGenPGO.h
index 9d66ffad6f435..83f35785e5327 100644
--- a/clang/lib/CodeGen/CodeGenPGO.h
+++ b/clang/lib/CodeGen/CodeGenPGO.h
@@ -35,7 +35,7 @@ class CodeGenPGO {
   std::array <unsigned, llvm::IPVK_Last + 1> NumValueSites;
   unsigned NumRegionCounters;
   uint64_t FunctionHash;
-  std::unique_ptr<llvm::DenseMap<const Stmt *, unsigned>> RegionCounterMap;
+  std::unique_ptr<llvm::DenseMap<const Stmt *, CounterPair>> RegionCounterMap;
   std::unique_ptr<llvm::DenseMap<const Stmt *, uint64_t>> StmtCountMap;
   std::unique_ptr<llvm::InstrProfRecord> ProfRecord;
   std::unique_ptr<MCDC::State> RegionMCDCState;
@@ -110,6 +110,7 @@ class CodeGenPGO {
   bool canEmitMCDCCoverage(const CGBuilderTy &Builder);
 
 public:
+  std::pair<bool, bool> getIsCounterPair(const Stmt *S) const;
   void emitCounterSetOrIncrement(CGBuilderTy &Builder, const Stmt *S,
                                  llvm::Value *StepV);
   void emitMCDCTestVectorBitmapUpdate(CGBuilderTy &Builder, const Expr *S,
@@ -122,6 +123,18 @@ class CodeGenPGO {
                                 Address MCDCCondBitmapAddr, llvm::Value *Val,
                                 CodeGenFunction &CGF);
 
+  void markStmtAsUsed(bool Skipped, const Stmt *S) {
+    // Do nothing.
+  }
+
+  void markStmtMaybeUsed(const Stmt *S) {
+    // Do nothing.
+  }
+
+  void verifyCounterMap() {
+    // Do nothing.
+  }
+
   /// Return the region count for the counter at the given index.
   uint64_t getRegionCount(const Stmt *S) {
     if (!RegionCounterMap)
@@ -130,7 +143,7 @@ class CodeGenPGO {
       return 0;
     // With profiles from a differing version of clang we can have mismatched
     // decl counts. Don't crash in such a case.
-    auto Index = (*RegionCounterMap)[S];
+    auto Index = (*RegionCounterMap)[S].first;
     if (Index >= RegionCounts.size())
       return 0;
     return RegionCounts[Index];
diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index 07015834bc84f..08e4ac80e0e87 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -885,7 +885,7 @@ struct CounterCoverageMappingBuilder
     : public CoverageMappingBuilder,
       public ConstStmtVisitor<CounterCoverageMappingBuilder> {
   /// The map of statements to count values.
-  llvm::DenseMap<const Stmt *, unsigned> &CounterMap;
+  llvm::DenseMap<const Stmt *, CounterPair> &CounterMap;
 
   MCDC::State &MCDCState;
 
@@ -938,7 +938,7 @@ struct CounterCoverageMappingBuilder
   ///
   /// This should only be called on statements that have a dedicated counter.
   Counter getRegionCounter(const Stmt *S) {
-    return Counter::getCounter(CounterMap[S]);
+    return Counter::getCounter(CounterMap[S].first);
   }
 
   /// Push a region onto the stack.
@@ -1421,7 +1421,7 @@ struct CounterCoverageMappingBuilder
 
   CounterCoverageMappingBuilder(
       CoverageMappingModuleGen &CVM,
-      llvm::DenseMap<const Stmt *, unsigned> &CounterMap,
+      llvm::DenseMap<const Stmt *, CounterPair> &CounterMap,
       MCDC::State &MCDCState, SourceManager &SM, const LangOptions &LangOpts)
       : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap),
         MCDCState(MCDCState), MCDCBuilder(CVM.getCodeGenModule(), MCDCState) {}
diff --git a/clang/lib/CodeGen/CoverageMappingGen.h b/clang/lib/CodeGen/CoverageMappingGen.h
index fe4b93f3af856..0ed50597e1dc3 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.h
+++ b/clang/lib/CodeGen/CoverageMappingGen.h
@@ -95,6 +95,7 @@ class CoverageSourceInfo : public PPCallbacks,
 namespace CodeGen {
 
 class CodeGenModule;
+class CounterPair;
 
 namespace MCDC {
 struct State;
@@ -158,7 +159,7 @@ class CoverageMappingGen {
   CoverageMappingModuleGen &CVM;
   SourceManager &SM;
   const LangOptions &LangOpts;
-  llvm::DenseMap<const Stmt *, unsigned> *CounterMap;
+  llvm::DenseMap<const Stmt *, CounterPair> *CounterMap;
   MCDC::State *MCDCState;
 
 public:
@@ -169,7 +170,7 @@ class CoverageMappingGen {
 
   CoverageMappingGen(CoverageMappingModuleGen &CVM, SourceManager &SM,
                      const LangOptions &LangOpts,
-                     llvm::DenseMap<const Stmt *, unsigned> *CounterMap,
+                     llvm::DenseMap<const Stmt *, CounterPair> *CounterMap,
                      MCDC::State *MCDCState)
       : CVM(CVM), SM(SM), LangOpts(LangOpts), CounterMap(CounterMap),
         MCDCState(MCDCState) {}

>From 5e460594c8a2550c38c759b2e6f1c5dc4152f820 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Thu, 17 Oct 2024 22:15:12 +0900
Subject: [PATCH 07/72] [Coverage] Make additional counters available for
 BranchRegion. NFC.

`getBranchCounterPair()` allocates an additional Counter to SkipPath
in `SingleByteCoverage`.

`IsCounterEqual()` calculates the comparison with rewinding counter
replacements.

`NumRegionCounters` is updated to take additional counters in account.

`incrementProfileCounter()` has a few additiona arguments.

- `UseSkipPath=true`, to specify setting counters for SkipPath. It
  assumes `UseSkipPath=false` is used together.

- `UseBoth` may be specified for marking another path. It introduces
  the same effect as issueing `markStmtAsUsed(!SkipPath, S)`.

`llvm-cov` discovers counters in `FalseCount` to allocate
`MaxCounterID` for empty profile data.
---
 clang/lib/CodeGen/CodeGenFunction.h           |  8 ++++-
 clang/lib/CodeGen/CodeGenPGO.cpp              | 31 +++++++++++++++++--
 clang/lib/CodeGen/CodeGenPGO.h                |  1 +
 clang/lib/CodeGen/CoverageMappingGen.cpp      | 31 ++++++++++++++-----
 .../ProfileData/Coverage/CoverageMapping.cpp  |  4 +++
 5 files changed, 65 insertions(+), 10 deletions(-)

diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 89ac3b342d0a7..cb1192bf6e11f 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -1629,11 +1629,17 @@ class CodeGenFunction : public CodeGenTypeCache {
   /// Increment the profiler's counter for the given statement by \p StepV.
   /// If \p StepV is null, the default increment is 1.
   void incrementProfileCounter(const Stmt *S, llvm::Value *StepV = nullptr) {
+    incrementProfileCounter(false, S, false, StepV);
+  }
+
+  void incrementProfileCounter(bool UseSkipPath, const Stmt *S,
+                               bool UseBoth = false,
+                               llvm::Value *StepV = nullptr) {
     if (CGM.getCodeGenOpts().hasProfileClangInstr() &&
         !CurFn->hasFnAttribute(llvm::Attribute::NoProfile) &&
         !CurFn->hasFnAttribute(llvm::Attribute::SkipProfile)) {
       auto AL = ApplyDebugLocation::CreateArtificial(*this);
-      PGO.emitCounterSetOrIncrement(Builder, S, StepV);
+      PGO.emitCounterSetOrIncrement(Builder, S, UseSkipPath, UseBoth, StepV);
     }
     PGO.setCurrentStmt(S);
   }
diff --git a/clang/lib/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp
index 069469e3de856..aefd53e12088b 100644
--- a/clang/lib/CodeGen/CodeGenPGO.cpp
+++ b/clang/lib/CodeGen/CodeGenPGO.cpp
@@ -1138,6 +1138,19 @@ void CodeGenPGO::emitCounterRegionMapping(const Decl *D) {
   if (CoverageMapping.empty())
     return;
 
+  // Scan max(FalseCnt) and update NumRegionCounters.
+  unsigned MaxNumCounters = NumRegionCounters;
+  for (const auto [_, V] : *RegionCounterMap) {
+    auto HasCounters = V.getIsCounterPair();
+    assert((!HasCounters.first ||
+            MaxNumCounters > (V.first & CounterPair::Mask)) &&
+           "TrueCnt should not be reassigned");
+    if (HasCounters.second)
+      MaxNumCounters =
+          std::max(MaxNumCounters, (V.second & CounterPair::Mask) + 1);
+  }
+  NumRegionCounters = MaxNumCounters;
+
   CGM.getCoverageMapping()->addFunctionMappingRecord(
       FuncNameVar, FuncName, FunctionHash, CoverageMapping);
 }
@@ -1193,11 +1206,25 @@ std::pair<bool, bool> CodeGenPGO::getIsCounterPair(const Stmt *S) const {
 }
 
 void CodeGenPGO::emitCounterSetOrIncrement(CGBuilderTy &Builder, const Stmt *S,
+                                           bool UseSkipPath, bool UseBoth,
                                            llvm::Value *StepV) {
-  if (!RegionCounterMap || !Builder.GetInsertBlock())
+  if (!RegionCounterMap)
     return;
 
-  unsigned Counter = (*RegionCounterMap)[S].first;
+  unsigned Counter;
+  auto &TheMap = (*RegionCounterMap)[S];
+  auto IsCounter = TheMap.getIsCounterPair();
+  if (!UseSkipPath) {
+    assert(IsCounter.first);
+    Counter = (TheMap.first & CounterPair::Mask);
+  } else {
+    if (!IsCounter.second)
+      return;
+    Counter = (TheMap.second & CounterPair::Mask);
+  }
+
+  if (!Builder.GetInsertBlock())
+    return;
 
   // Make sure that pointer to global is passed in with zero addrspace
   // This is relevant during GPU profiling
diff --git a/clang/lib/CodeGen/CodeGenPGO.h b/clang/lib/CodeGen/CodeGenPGO.h
index 83f35785e5327..8b769dd88d7f1 100644
--- a/clang/lib/CodeGen/CodeGenPGO.h
+++ b/clang/lib/CodeGen/CodeGenPGO.h
@@ -112,6 +112,7 @@ class CodeGenPGO {
 public:
   std::pair<bool, bool> getIsCounterPair(const Stmt *S) const;
   void emitCounterSetOrIncrement(CGBuilderTy &Builder, const Stmt *S,
+                                 bool UseFalsePath, bool UseBoth,
                                  llvm::Value *StepV);
   void emitMCDCTestVectorBitmapUpdate(CGBuilderTy &Builder, const Expr *S,
                                       Address MCDCCondBitmapAddr,
diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index a5d83e7a743bb..0bcbd20593ae2 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -887,6 +887,9 @@ struct CounterCoverageMappingBuilder
   /// The map of statements to count values.
   llvm::DenseMap<const Stmt *, CounterPair> &CounterMap;
 
+  CounterExpressionBuilder::ReplaceMap MapToExpand;
+  unsigned NextCounterNum;
+
   MCDC::State &MCDCState;
 
   /// A stack of currently live regions.
@@ -922,15 +925,11 @@ struct CounterCoverageMappingBuilder
 
   /// Return a counter for the sum of \c LHS and \c RHS.
   Counter addCounters(Counter LHS, Counter RHS, bool Simplify = true) {
-    assert(!llvm::EnableSingleByteCoverage &&
-           "cannot add counters when single byte coverage mode is enabled");
     return Builder.add(LHS, RHS, Simplify);
   }
 
   Counter addCounters(Counter C1, Counter C2, Counter C3,
                       bool Simplify = true) {
-    assert(!llvm::EnableSingleByteCoverage &&
-           "cannot add counters when single byte coverage mode is enabled");
     return addCounters(addCounters(C1, C2, Simplify), C3, Simplify);
   }
 
@@ -943,14 +942,31 @@ struct CounterCoverageMappingBuilder
 
   std::pair<Counter, Counter> getBranchCounterPair(const Stmt *S,
                                                    Counter ParentCnt) {
-    Counter ExecCnt = getRegionCounter(S);
-    return {ExecCnt, Builder.subtract(ParentCnt, ExecCnt)};
+    auto &TheMap = CounterMap[S];
+    auto ExecCnt = Counter::getCounter(TheMap.first);
+    auto SkipExpr = Builder.subtract(ParentCnt, ExecCnt);
+
+    if (!llvm::EnableSingleByteCoverage)
+      return {ExecCnt, SkipExpr};
+
+    // Assign second if second is not assigned yet.
+    if (!TheMap.getIsCounterPair().second)
+      TheMap.second = NextCounterNum++;
+
+    Counter SkipCnt = Counter::getCounter(TheMap.second);
+    MapToExpand[SkipCnt] = SkipExpr;
+    return {ExecCnt, SkipCnt};
   }
 
   bool IsCounterEqual(Counter OutCount, Counter ParentCount) {
     if (OutCount == ParentCount)
       return true;
 
+    // Try comaparison with pre-replaced expressions.
+    if (Builder.replace(Builder.subtract(OutCount, ParentCount), MapToExpand)
+            .isZero())
+      return true;
+
     return false;
   }
 
@@ -1437,7 +1453,8 @@ struct CounterCoverageMappingBuilder
       llvm::DenseMap<const Stmt *, CounterPair> &CounterMap,
       MCDC::State &MCDCState, SourceManager &SM, const LangOptions &LangOpts)
       : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap),
-        MCDCState(MCDCState), MCDCBuilder(CVM.getCodeGenModule(), MCDCState) {}
+        NextCounterNum(CounterMap.size()), MCDCState(MCDCState),
+        MCDCBuilder(CVM.getCodeGenModule(), MCDCState) {}
 
   /// Write the mapping data to the output stream
   void write(llvm::raw_ostream &OS) {
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index b50f025d261e1..fc7f36c8599f5 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -640,6 +640,10 @@ static unsigned getMaxCounterID(const CounterMappingContext &Ctx,
   unsigned MaxCounterID = 0;
   for (const auto &Region : Record.MappingRegions) {
     MaxCounterID = std::max(MaxCounterID, Ctx.getMaxCounterID(Region.Count));
+    if (Region.Kind == CounterMappingRegion::BranchRegion ||
+        Region.Kind == CounterMappingRegion::MCDCBranchRegion)
+      MaxCounterID =
+          std::max(MaxCounterID, Ctx.getMaxCounterID(Region.FalseCount));
   }
   return MaxCounterID;
 }

>From ad136910aad1c8e53a8c6091999ad2f90d180761 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Fri, 18 Oct 2024 09:37:18 +0900
Subject: [PATCH 08/72] Rewind changes for folding

---
 clang/lib/CodeGen/CoverageMappingGen.cpp | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index 0bfad9cbcbe12..8bd9ab402f4e5 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -1795,10 +1795,7 @@ struct CounterCoverageMappingBuilder
     if (llvm::EnableSingleByteCoverage)
       OutCount = getRegionCounter(S);
     else {
-      LoopCount =
-          (ParentCount.isZero()
-               ? ParentCount
-               : addCounters(ParentCount, BackedgeCount, BC.ContinueCount));
+      LoopCount = addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
       auto [ExecCount, SkipCount] = getBranchCounterPair(S, LoopCount);
       ExitCount = SkipCount;
       assert(ExecCount.isZero() || ExecCount == BodyCount);
@@ -1834,9 +1831,7 @@ struct CounterCoverageMappingBuilder
       fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
 
     Counter LoopCount =
-        (ParentCount.isZero()
-             ? ParentCount
-             : addCounters(ParentCount, BackedgeCount, BC.ContinueCount));
+        addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
     auto [ExecCount, ExitCount] = getBranchCounterPair(S, LoopCount);
     assert(ExecCount.isZero() || ExecCount == BodyCount);
     Counter OutCount = addCounters(BC.BreakCount, ExitCount);

>From 209ea4cfdb4f93d3c8fc60dc9af29af39fd24758 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Sun, 20 Oct 2024 11:58:16 +0900
Subject: [PATCH 09/72] Update comments

---
 llvm/lib/ProfileData/Coverage/CoverageMapping.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index b50f025d261e1..6f44797be20e3 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -138,14 +138,14 @@ Counter CounterExpressionBuilder::subtract(Counter LHS, Counter RHS,
 Counter CounterExpressionBuilder::replace(Counter C, const ReplaceMap &Map) {
   auto I = Map.find(C);
 
-  // Replace C with the Map even if C is Expression.
+  // Replace C with the value found in Map even if C is Expression.
   if (I != Map.end())
     return I->second;
 
-  // Traverse only Expression.
   if (!C.isExpression())
     return C;
 
+  // Traverse both sides of Expression.
   auto CE = Expressions[C.getExpressionID()];
   auto NewLHS = replace(CE.LHS, Map);
   auto NewRHS = replace(CE.RHS, Map);

>From f0afd04dd86573f1e7d868cc6e1c677d1779aa5f Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Sun, 20 Oct 2024 12:00:23 +0900
Subject: [PATCH 10/72] Use initializer statements

---
 llvm/lib/ProfileData/Coverage/CoverageMapping.cpp | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index 6f44797be20e3..7ff2e5ba69e19 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -136,10 +136,8 @@ Counter CounterExpressionBuilder::subtract(Counter LHS, Counter RHS,
 }
 
 Counter CounterExpressionBuilder::replace(Counter C, const ReplaceMap &Map) {
-  auto I = Map.find(C);
-
   // Replace C with the value found in Map even if C is Expression.
-  if (I != Map.end())
+  if (auto I = Map.find(C); I != Map.end())
     return I->second;
 
   if (!C.isExpression())
@@ -161,7 +159,7 @@ Counter CounterExpressionBuilder::replace(Counter C, const ReplaceMap &Map) {
   }
 
   // Reconfirm if the reconstructed expression would hit the Map.
-  if ((I = Map.find(C)) != Map.end())
+  if (auto I = Map.find(C); I != Map.end())
     return I->second;
 
   return C;

>From be516faa39e1152d637ac425229f8a88480ba41b Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Sun, 20 Oct 2024 11:57:03 +0900
Subject: [PATCH 11/72] `first` may be cancelled.

Currently `first` is not None by default.
---
 clang/lib/CodeGen/CodeGenPGO.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp
index aefd53e12088b..0f2090da47a37 100644
--- a/clang/lib/CodeGen/CodeGenPGO.cpp
+++ b/clang/lib/CodeGen/CodeGenPGO.cpp
@@ -1215,7 +1215,8 @@ void CodeGenPGO::emitCounterSetOrIncrement(CGBuilderTy &Builder, const Stmt *S,
   auto &TheMap = (*RegionCounterMap)[S];
   auto IsCounter = TheMap.getIsCounterPair();
   if (!UseSkipPath) {
-    assert(IsCounter.first);
+    if (!IsCounter.first)
+      return;
     Counter = (TheMap.first & CounterPair::Mask);
   } else {
     if (!IsCounter.second)

>From 52f072e5058267660aa8c8fbb00c5d09634f22b3 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Fri, 18 Oct 2024 08:32:39 +0900
Subject: [PATCH 12/72] clang/test/CoverageMapping/single-byte-counters.cpp:
 Rewrite counter matches

---
 .../CoverageMapping/single-byte-counters.cpp  | 163 +++++++-----------
 1 file changed, 65 insertions(+), 98 deletions(-)

diff --git a/clang/test/CoverageMapping/single-byte-counters.cpp b/clang/test/CoverageMapping/single-byte-counters.cpp
index 8e9b613dcc68f..d20b695bc2636 100644
--- a/clang/test/CoverageMapping/single-byte-counters.cpp
+++ b/clang/test/CoverageMapping/single-byte-counters.cpp
@@ -1,169 +1,136 @@
 // RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -mllvm -enable-single-byte-coverage=true -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name single-byte-counters.cpp %s | FileCheck %s
 
 // CHECK: testIf
-int testIf(int x) { // CHECK-NEXT: File 0, [[@LINE]]:19 -> [[@LINE+10]]:2 = #0
-                    // CHECK-NEXT: File 0, [[@LINE+5]]:7 -> [[@LINE+5]]:13 = #0
-                    // CHECK-NEXT: Gap,File 0, [[@LINE+4]]:14 -> [[@LINE+5]]:5 = #1
-                    // CHECK-NEXT: File 0, [[@LINE+4]]:5 -> [[@LINE+4]]:16 = #1
-                    // CHECK-NEXT: File 0, [[@LINE+5]]:3 -> [[@LINE+5]]:16 = #2
+int testIf(int x) { // CHECK-NEXT: File 0, [[@LINE]]:19 -> [[@LINE+7]]:2 = [[C00:#0]]
   int result = 0;
-  if (x == 0)
-    result = -1;
+  if (x == 0)       // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:13 = [[C00]]
+                    // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE+1]]:5 = [[C0T:#1]]
+    result = -1;    // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:16 = [[C0T]]
 
-  return result;
+  return result;    // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:16 = [[C0E:#2]]
 }
 
 // CHECK-NEXT: testIfElse
-int testIfElse(int x) { // CHECK-NEXT: File 0, [[@LINE]]:23 -> [[@LINE+13]]:2 = #0
-                        // CHECK-NEXT: File 0, [[@LINE+7]]:7 -> [[@LINE+7]]:12 = #0
-                        // CHECK-NEXT: Gap,File 0, [[@LINE+6]]:13 -> [[@LINE+7]]:5 = #1
-                        // CHECK-NEXT: File 0, [[@LINE+6]]:5 -> [[@LINE+6]]:15 = #1
-                        // CHECK-NEXT: Gap,File 0, [[@LINE+5]]:16 -> [[@LINE+7]]:5 = #2
-                        // CHECK-NEXT: File 0, [[@LINE+6]]:5 -> [[@LINE+6]]:19 = #2
-                        // CHECK-NEXT: File 0, [[@LINE+6]]:3 -> [[@LINE+6]]:16 = #3
+int testIfElse(int x) { // CHECK-NEXT: File 0, [[@LINE]]:23 -> [[@LINE+8]]:2 = [[C10:#0]]
   int result = 0;
-  if (x < 0)
-    result = 0;
-  else
-    result = x * x;
-  return result;
+  if (x < 0)            // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:12 = [[C10]]
+                        // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:13 -> [[@LINE+1]]:5 = [[C1T:#1]]
+    result = 0;         // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:15 = [[C1T]]
+  else                  // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:16 -> [[@LINE+1]]:5 = [[C1F:#2]]
+    result = x * x;     // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:19 = [[C1F]]
+  return result;        // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:16 = [[C1E:#3]]
 }
 
 // CHECK-NEXT: testIfElseReturn
-int testIfElseReturn(int x) { // CHECK-NEXT: File 0, [[@LINE]]:29 -> [[@LINE+14]]:2 = #0
-                              // CHECK-NEXT: File 0, [[@LINE+8]]:7 -> [[@LINE+8]]:12 = #0
-                              // CHECK-NEXT: Gap,File 0, [[@LINE+7]]:13 -> [[@LINE+8]]:5 = #1
-                              // CHECK-NEXT: File 0, [[@LINE+7]]:5 -> [[@LINE+7]]:19 = #1
-                              // CHECK-NEXT: Gap,File 0, [[@LINE+6]]:20 -> [[@LINE+8]]:5 = #2
-                              // CHECK-NEXT: File 0, [[@LINE+7]]:5 -> [[@LINE+7]]:13 = #2
-                              // CHECK-NEXT: Gap,File 0, [[@LINE+6]]:14 -> [[@LINE+7]]:3 = #3
-                              // CHECK-NEXT: File 0, [[@LINE+6]]:3 -> [[@LINE+6]]:16 = #3
+int testIfElseReturn(int x) { // CHECK-NEXT: File 0, [[@LINE]]:29 -> [[@LINE+9]]:2 = [[C20:#0]]
   int result = 0;
-  if (x > 0)
-    result = x * x;
-  else
-    return 0;
-  return result;
+  if (x > 0)                  // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:12 = [[C20]]
+                              // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:13 -> [[@LINE+1]]:5 = [[C2T:#1]]
+    result = x * x;           // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:19 = [[C2T]]
+  else                        // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:20 -> [[@LINE+1]]:5 = [[C2F:#2]]
+    return 0;                 // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:13 = [[C2F]]
+                              // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE+1]]:3 = [[C2E:#3]]
+  return result;              // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:16 = [[C2E:#3]]
 }
 
 // CHECK-NEXT: testSwitch
-int testSwitch(int x) { // CHECK-NEXT: File 0, [[@LINE]]:23 -> [[@LINE+22]]:2 = #0
-                        // CHECK-NEXT: Gap,File 0, [[@LINE+9]]:14 -> [[@LINE+17]]:15 = 0
-                        // CHECK-NEXT: File 0, [[@LINE+9]]:3 -> [[@LINE+11]]:10 = #2
-                        // CHECK-NEXT: Gap,File 0, [[@LINE+10]]:11 -> [[@LINE+11]]:3 = 0
-                        // CHECK-NEXT: File 0, [[@LINE+10]]:3 -> [[@LINE+12]]:10 = #3
-                        // CHECK-NEXT: Gap,File 0, [[@LINE+11]]:11 -> [[@LINE+12]]:3 = 0
-                        // CHECK-NEXT: File 0, [[@LINE+11]]:3 -> [[@LINE+12]]:15 = #4
-                        // CHECK-NEXT: Gap,File 0, [[@LINE+12]]:4 -> [[@LINE+14]]:3 = #1
-                        // CHECK-NEXT: File 0, [[@LINE+13]]:3 -> [[@LINE+13]]:16 = #1
+int testSwitch(int x) { // CHECK-NEXT: File 0, [[@LINE]]:23 -> [[@LINE+17]]:2 = [[C30:#0]]
   int result;
   switch (x) {
-  case 1:
+                        // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE+10]]:15 = 0
+  case 1:               // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:10 = [[C31:#2]]
     result = 1;
     break;
-  case 2:
+                        // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:11 -> [[@LINE+1]]:3 = 0
+  case 2:               // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:10 = [[C32:#3]]
     result = 2;
     break;
-  default:
+                        // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:11 -> [[@LINE+1]]:3 = 0
+  default:              // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:15 = [[C3D:#4]]
     result = 0;
   }
-
-  return result;
+                        // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:4 -> [[@LINE+1]]:3 = [[C3E:#1]]
+  return result;        // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:16 = [[C3E]]
 }
 
 // CHECK-NEXT: testWhile
-int testWhile() { // CHECK-NEXT: File 0, [[@LINE]]:17 -> [[@LINE+13]]:2 = #0
-                  // CHECK-NEXT: File 0, [[@LINE+6]]:10 -> [[@LINE+6]]:16 = #1
-                  // CHECK-NEXT: Gap,File 0, [[@LINE+5]]:17 -> [[@LINE+5]]:18 = #2
-                  // CHECK-NEXT: File 0, [[@LINE+4]]:18 -> [[@LINE+7]]:4 = #2
-                  // CHECK-NEXT: File 0, [[@LINE+8]]:3 -> [[@LINE+8]]:13 = #3
+int testWhile() {       // CHECK-NEXT: File 0, [[@LINE]]:17 -> [[@LINE+11]]:2 = [[C40:#0]]
   int i = 0;
   int sum = 0;
-  while (i < 10) {
+  while (i < 10) {      // CHECK-NEXT: File 0, [[@LINE]]:10 -> [[@LINE]]:16 = [[C4C:#1]]
+                        // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:17 -> [[@LINE-1]]:18 = [[C4T:#2]]
+                        // CHECK-NEXT: File 0, [[@LINE-2]]:18 -> [[@LINE+3]]:4 = [[C4T]]
     sum += i;
     i++;
   }
 
-  return sum;
+  return sum;           // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:13 = [[C4E:#3]]
 }
 
 // CHECK-NEXT: testContinue
-int testContinue() { // CHECK-NEXT: File 0, [[@LINE]]:20 -> [[@LINE+21]]:2 = #0
-                     // CHECK-NEXT: File 0, [[@LINE+12]]:10 -> [[@LINE+12]]:16 = #1
-                     // CHECK-NEXT: Gap,File 0, [[@LINE+11]]:17 -> [[@LINE+11]]:18 = #2
-                     // CHECK-NEXT: File 0, [[@LINE+10]]:18 -> [[@LINE+15]]:4 = #2
-                     // CHECK-NEXT: File 0, [[@LINE+10]]:9 -> [[@LINE+10]]:15 = #2
-                     // CHECK-NEXT: Gap,File 0, [[@LINE+9]]:16 -> [[@LINE+10]]:7 = #4
-                     // CHECK-NEXT: File 0, [[@LINE+9]]:7 -> [[@LINE+9]]:15 = #4
-                     // CHECK-NEXT: Gap,File 0, [[@LINE+8]]:16 -> [[@LINE+9]]:5 = #5
-                     // CHECK-NEXT: File 0, [[@LINE+8]]:5 -> [[@LINE+10]]:4 = #5
-                     // CHECK-NEXT: Gap,File 0, [[@LINE+9]]:4 -> [[@LINE+11]]:3 = #3
-                     // CHECK-NEXT: File 0, [[@LINE+10]]:3 -> [[@LINE+10]]:13 = #3
+int testContinue() { // CHECK-NEXT: File 0, [[@LINE]]:20 -> [[@LINE+15]]:2 = [[C50:#0]]
   int i = 0;
   int sum = 0;
-  while (i < 10) {
-    if (i == 4)
-      continue;
-    sum += i;
+  while (i < 10) {   // CHECK-NEXT: File 0, [[@LINE]]:10 -> [[@LINE]]:16 = [[C5C:#1]]
+                     // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:17 -> [[@LINE-1]]:18 = [[C5B:#2]]
+                     // CHECK-NEXT: File 0, [[@LINE-2]]:18 -> [[@LINE+7]]:4 = [[C5B]]
+    if (i == 4)      // CHECK-NEXT: File 0, [[@LINE]]:9 -> [[@LINE]]:15 = [[C5B]]
+                     // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:16 -> [[@LINE+1]]:7 = [[C5T:#4]]
+      continue;      // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:15 = [[C5T]]
+                     // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:16 -> [[@LINE+1]]:5 = [[C5F:#5]]
+    sum += i;        // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE+2]]:4 = [[C5F]]
     i++;
   }
-
-  return sum;
+                     // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:4 -> [[@LINE+1]]:3 = [[C5E:#3]]
+  return sum;        // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:13 = [[C5E]]
 }
 
 // CHECK-NEXT: testFor
-int testFor() { // CHECK-NEXT: File 0, [[@LINE]]:15 -> [[@LINE+13]]:2 = #0
-                // CHECK-NEXT: File 0, [[@LINE+7]]:19 -> [[@LINE+7]]:25 = #1
-                // CHECK-NEXT: File 0, [[@LINE+6]]:27 -> [[@LINE+6]]:30 = #2
-                // CHECK-NEXT: Gap,File 0, [[@LINE+5]]:31 -> [[@LINE+5]]:32 = #3
-                // CHECK-NEXT: File 0, [[@LINE+4]]:32 -> [[@LINE+6]]:4 = #3
-                // CHECK-NEXT: File 0, [[@LINE+7]]:3 -> [[@LINE+7]]:13 = #4
+int testFor() { // CHECK-NEXT: File 0, [[@LINE]]:15 -> [[@LINE+12]]:2 = [[C60:#0]]
   int i;
   int sum = 0;
+                // CHECK-NEXT: File 0, [[@LINE+2]]:19 -> [[@LINE+2]]:25 = [[C61:#1]]
+                // CHECK-NEXT: File 0, [[@LINE+1]]:27 -> [[@LINE+1]]:30 = [[C6C:#2]]
   for (int i = 0; i < 10; i++) {
+                // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:31 -> [[@LINE-1]]:32 = [[C6B:#3]]
+                // CHECK-NEXT: File 0, [[@LINE-2]]:32 -> [[@LINE+2]]:4 = [[C6B]]
     sum += i;
   }
 
-  return sum;
+  return sum;   // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:13 = [[C6E:#4]]
 }
 
 // CHECK-NEXT: testForRange
-int testForRange() { // CHECK-NEXT: File 0, [[@LINE]]:20 -> [[@LINE+12]]:2 = #0
-                     // CHECK-NEXT: Gap,File 0, [[@LINE+6]]:28 -> [[@LINE+6]]:29 = #1
-                     // CHECK-NEXT: File 0, [[@LINE+5]]:29 -> [[@LINE+7]]:4 = #1
-                     // CHECK-NEXT: File 0, [[@LINE+8]]:3 -> [[@LINE+8]]:13 = #2
+int testForRange() {    // CHECK-NEXT: File 0, [[@LINE]]:20 -> [[@LINE+11]]:2 = [[C70:#0]]
   int sum = 0;
   int array[] = {1, 2, 3, 4, 5};
 
   for (int element : array) {
+                        // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:28 -> [[@LINE-1]]:29 = [[C7B:#1]]
+                        // CHECK-NEXT: File 0, [[@LINE-2]]:29 -> [[@LINE+2]]:4 = [[C7B]]
       sum += element;
   }
 
-  return sum;
+  return sum;           // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:13 = [[C7E:#2]]
 }
 
 // CHECK-NEXT: testDo
-int testDo() { // CHECK-NEXT: File 0, [[@LINE]]:14 -> [[@LINE+12]]:2 = #0
-               // CHECK-NEXT: File 0, [[@LINE+5]]:6 -> [[@LINE+8]]:4 = #1
-               // CHECK-NEXT: File 0, [[@LINE+7]]:12 -> [[@LINE+7]]:17 = #2
-               // CHECK-NEXT: File 0, [[@LINE+8]]:3 -> [[@LINE+8]]:13 = #3
+int testDo() {          // CHECK-NEXT: File 0, [[@LINE]]:14 -> [[@LINE+9]]:2 = [[C80:#0]]
   int i = 0;
   int sum = 0;
-  do {
+  do {                  // CHECK-NEXT: File 0, [[@LINE]]:6 -> [[@LINE+3]]:4 = [[C8B:#1]]
     sum += i;
     i++;
-  } while (i < 5);
+  } while (i < 5);      // CHECK-NEXT: File 0, [[@LINE]]:12 -> [[@LINE]]:17 = [[C8C:#2]]
 
-  return sum;
+  return sum;           // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:13 = [[C8E:#3]]
 }
 
 // CHECK-NEXT: testConditional
-int testConditional(int x) { // CHECK-NEXT: File 0, [[@LINE]]:28 -> [[@LINE+8]]:2 = #0
-                             // CHECK-NEXT: File 0, [[@LINE+5]]:15 -> [[@LINE+5]]:22 = #0
-                             // CHECK-NEXT: Gap,File 0, [[@LINE+4]]:24 -> [[@LINE+4]]:25 = #2
-                             // CHECK-NEXT: File 0, [[@LINE+3]]:25 -> [[@LINE+3]]:26 = #2
-                             // CHECK-NEXT: File 0, [[@LINE+2]]:29 -> [[@LINE+2]]:31 = #3
-                             // CHECK-NEXT: File 0, [[@LINE+2]]:2 -> [[@LINE+2]]:15 = #1
- int result = (x > 0) ? 1 : -1;
- return result;
+int testConditional(int x) {    // CHECK-NEXT: File 0, [[@LINE]]:28 -> [[@LINE+6]]:2 = [[C90:#0]]
+ int result = (x > 0) ? 1 : -1; // CHECK-NEXT: File 0, [[@LINE]]:15 -> [[@LINE]]:22 = [[C90]]
+                                // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:24 -> [[@LINE-1]]:25 = [[C9T:#2]]
+                                // CHECK-NEXT: File 0, [[@LINE-2]]:25 -> [[@LINE-2]]:26 = [[C9T]]
+                                // CHECK-NEXT: File 0, [[@LINE-3]]:29 -> [[@LINE-3]]:31 = [[C9F:#3]]
+ return result;                 // CHECK-NEXT: File 0, [[@LINE]]:2 -> [[@LINE]]:15 = [[C9E:#1]]
 }

>From 03cfce188cb45adbe78f7e77c2fdd244650f5a3c Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Wed, 23 Oct 2024 14:39:35 +0000
Subject: [PATCH 13/72] CGF::markStmtAsUsed

---
 clang/lib/CodeGen/CodeGenFunction.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 89ac3b342d0a7..fcad1cbcae5e3 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -1624,6 +1624,9 @@ class CodeGenFunction : public CodeGenTypeCache {
     return PGO.getIsCounterPair(S);
   }
 
+  void markStmtAsUsed(bool Skipped, const Stmt *S) {
+    PGO.markStmtAsUsed(Skipped, S);
+  }
   void markStmtMaybeUsed(const Stmt *S) { PGO.markStmtMaybeUsed(S); }
 
   /// Increment the profiler's counter for the given statement by \p StepV.

>From afc8481f7cf20da7de4e95a60bf3ccdb04bd08f3 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Wed, 23 Oct 2024 14:39:35 +0000
Subject: [PATCH 14/72] CGF.markStmtMaybeUsed for binop

---
 clang/lib/CodeGen/CGExprScalar.cpp | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 74e93f889f426..9e8533ca90a5c 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -4970,7 +4970,8 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
         CGF.incrementProfileCounter(E->getRHS());
         CGF.EmitBranch(FBlock);
         CGF.EmitBlock(FBlock);
-      }
+      } else
+        CGF.markStmtMaybeUsed(E->getRHS());
 
       CGF.MCDCLogOpStack.pop_back();
       // If the top of the logical operator nest, update the MCDC bitmap.
@@ -5112,7 +5113,8 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
         CGF.incrementProfileCounter(E->getRHS());
         CGF.EmitBranch(FBlock);
         CGF.EmitBlock(FBlock);
-      }
+      } else
+        CGF.markStmtMaybeUsed(E->getRHS());
 
       CGF.MCDCLogOpStack.pop_back();
       // If the top of the logical operator nest, update the MCDC bitmap.

>From ab84f17fc181cb4b38693dc6ea80ac44f44bf990 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Sun, 27 Oct 2024 20:28:26 +0900
Subject: [PATCH 15/72] Introduce skeleton getSwitchImplicitDefaultCounter()

---
 clang/lib/CodeGen/CoverageMappingGen.cpp | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index 1782434bdb9aa..532f6e8ba1820 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -947,6 +947,11 @@ struct CounterCoverageMappingBuilder
     return {ExecCnt, Builder.subtract(ParentCnt, ExecCnt)};
   }
 
+  Counter getSwitchImplicitDefaultCounter(const Stmt *Cond, Counter ParentCount,
+                                          Counter CaseCountSum) {
+    return Builder.subtract(ParentCount, CaseCountSum);
+  }
+
   bool IsCounterEqual(Counter OutCount, Counter ParentCount) {
     if (OutCount == ParentCount)
       return true;
@@ -1903,7 +1908,8 @@ struct CounterCoverageMappingBuilder
     // the hidden branch, which will be added later by the CodeGen. This region
     // will be associated with the switch statement's condition.
     if (!HasDefaultCase) {
-      Counter DefaultCount = subtractCounters(ParentCount, CaseCountSum);
+      Counter DefaultCount = getSwitchImplicitDefaultCounter(
+          S->getCond(), ParentCount, CaseCountSum);
       createBranchRegion(S->getCond(), Counter::getZero(), DefaultCount);
     }
   }

>From a4608854e1b727817db3cc01234f97e78285f8c7 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Sun, 27 Oct 2024 20:40:44 +0900
Subject: [PATCH 16/72] Update getSwitchImplicitDefaultCounter

---
 clang/lib/CodeGen/CoverageMappingGen.cpp | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index d4a1b2613eab9..cb861e61d3272 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -960,7 +960,10 @@ struct CounterCoverageMappingBuilder
 
   Counter getSwitchImplicitDefaultCounter(const Stmt *Cond, Counter ParentCount,
                                           Counter CaseCountSum) {
-    return Builder.subtract(ParentCount, CaseCountSum);
+    return (
+        llvm::EnableSingleByteCoverage
+            ? Counter::getCounter(CounterMap[Cond].second = NextCounterNum++)
+            : Builder.subtract(ParentCount, CaseCountSum));
   }
 
   bool IsCounterEqual(Counter OutCount, Counter ParentCount) {

>From 02853943407a5c550554e4920586b8724dd63a76 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Mon, 28 Oct 2024 00:55:49 +0900
Subject: [PATCH 17/72] Don't allocate second if SkipExpr isn't Expr.

---
 clang/lib/CodeGen/CoverageMappingGen.cpp | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index cb861e61d3272..8584f58548eae 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -946,8 +946,12 @@ struct CounterCoverageMappingBuilder
     auto ExecCnt = Counter::getCounter(TheMap.first);
     auto SkipExpr = Builder.subtract(ParentCnt, ExecCnt);
 
-    if (!llvm::EnableSingleByteCoverage)
+    if (!llvm::EnableSingleByteCoverage || !SkipExpr.isExpression()) {
+      assert(
+          !TheMap.getIsCounterPair().second &&
+          "SkipCnt shouldn't be allocated but refer to an existing counter.");
       return {ExecCnt, SkipExpr};
+    }
 
     // Assign second if second is not assigned yet.
     if (!TheMap.getIsCounterPair().second)

>From 97a4a8f40afb53250639c29e193edd814cb82f58 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Wed, 20 Nov 2024 23:33:51 +0900
Subject: [PATCH 18/72] test/llvm-cov: Transform %.c* tests to {%.test,
 Inputs/%.c*}

And reformat. NFC.
---
 .../{ => Inputs}/branch-logical-mixed.cpp     | 13 +---
 .../llvm-cov/{ => Inputs}/branch-macros.cpp   | 14 +---
 .../Inputs/branch-showBranchPercentage.c      | 58 +++++++++++++++
 .../llvm-cov/Inputs/branch-templates.cpp      | 38 ++++++++++
 .../Inputs/showLineExecutionCounts.cpp        | 29 ++++++++
 .../test/tools/llvm-cov/branch-c-general.test |  2 +-
 .../tools/llvm-cov/branch-logical-mixed.test  | 11 +++
 llvm/test/tools/llvm-cov/branch-macros.test   | 11 +++
 .../tools/llvm-cov/branch-noShowBranch.test   |  8 +-
 ...age.c => branch-showBranchPercentage.test} | 57 +--------------
 ...ch-templates.cpp => branch-templates.test} | 46 ++----------
 .../llvm-cov/showLineExecutionCounts.cpp      | 73 -------------------
 .../llvm-cov/showLineExecutionCounts.test     | 43 +++++++++++
 13 files changed, 209 insertions(+), 194 deletions(-)
 rename llvm/test/tools/llvm-cov/{ => Inputs}/branch-logical-mixed.cpp (80%)
 rename llvm/test/tools/llvm-cov/{ => Inputs}/branch-macros.cpp (70%)
 create mode 100644 llvm/test/tools/llvm-cov/Inputs/branch-showBranchPercentage.c
 create mode 100644 llvm/test/tools/llvm-cov/Inputs/branch-templates.cpp
 create mode 100644 llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts.cpp
 create mode 100644 llvm/test/tools/llvm-cov/branch-logical-mixed.test
 create mode 100644 llvm/test/tools/llvm-cov/branch-macros.test
 rename llvm/test/tools/llvm-cov/{branch-showBranchPercentage.c => branch-showBranchPercentage.test} (51%)
 rename llvm/test/tools/llvm-cov/{branch-templates.cpp => branch-templates.test} (54%)
 delete mode 100644 llvm/test/tools/llvm-cov/showLineExecutionCounts.cpp
 create mode 100644 llvm/test/tools/llvm-cov/showLineExecutionCounts.test

diff --git a/llvm/test/tools/llvm-cov/branch-logical-mixed.cpp b/llvm/test/tools/llvm-cov/Inputs/branch-logical-mixed.cpp
similarity index 80%
rename from llvm/test/tools/llvm-cov/branch-logical-mixed.cpp
rename to llvm/test/tools/llvm-cov/Inputs/branch-logical-mixed.cpp
index f5f7871124467..0a7d8d8967115 100644
--- a/llvm/test/tools/llvm-cov/branch-logical-mixed.cpp
+++ b/llvm/test/tools/llvm-cov/Inputs/branch-logical-mixed.cpp
@@ -1,6 +1,6 @@
-// RUN: llvm-profdata merge %S/Inputs/branch-logical-mixed.proftext -o %t.profdata
-// RUN: llvm-cov show --show-branches=count %S/Inputs/branch-logical-mixed.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S %s | FileCheck %s
-// RUN: llvm-cov report --show-branch-summary %S/Inputs/branch-logical-mixed.o32l -instr-profile %t.profdata -show-functions -path-equivalence=/tmp,%S %s | FileCheck %s -check-prefix=REPORT
+
+
+
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -81,10 +81,3 @@ int main(int argc, char *argv[])
   __llvm_profile_write_file();
   return 0;
 }
-
-// REPORT: Name                        Regions    Miss   Cover     Lines    Miss   Cover  Branches    Miss   Cover
-// REPORT-NEXT: ---
-// REPORT-NEXT: _Z4funcii                        77       9  88.31%        68       3  95.59%        80      32  60.00%
-// REPORT-NEXT: main                              1       0 100.00%         5       0 100.00%         0       0   0.00%
-// REPORT-NEXT: ---
-// REPORT-NEXT: TOTAL                            78       9  88.46%        73       3  95.89%        80      32  60.00%
diff --git a/llvm/test/tools/llvm-cov/branch-macros.cpp b/llvm/test/tools/llvm-cov/Inputs/branch-macros.cpp
similarity index 70%
rename from llvm/test/tools/llvm-cov/branch-macros.cpp
rename to llvm/test/tools/llvm-cov/Inputs/branch-macros.cpp
index 73042ac397d40..712b2790f774a 100644
--- a/llvm/test/tools/llvm-cov/branch-macros.cpp
+++ b/llvm/test/tools/llvm-cov/Inputs/branch-macros.cpp
@@ -1,6 +1,6 @@
-// RUN: llvm-profdata merge %S/Inputs/branch-macros.proftext -o %t.profdata
-// RUN: llvm-cov show --show-expansions --show-branches=count %S/Inputs/branch-macros.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S %s | FileCheck %s
-// RUN: llvm-cov report --show-branch-summary %S/Inputs/branch-macros.o32l -instr-profile %t.profdata -show-functions -path-equivalence=/tmp,%S %s | FileCheck %s -check-prefix=REPORT
+
+
+
 
 #define COND1 (a == b)
 #define COND2 (a != b)
@@ -50,11 +50,3 @@ int main(int argc, char *argv[])
   __llvm_profile_write_file();
   return 0;
 }
-
-// REPORT: Name                        Regions    Miss   Cover     Lines    Miss   Cover  Branches    Miss   Cover
-// REPORT-NEXT: ---
-// REPORT-NEXT: _Z4funcii                        28       4  85.71%        18       0 100.00%        30      14  53.33%
-// REPORT-NEXT: _Z5func2ii                       13       1  92.31%         8       0 100.00%        10       2  80.00%
-// REPORT-NEXT: main                              1       0 100.00%         6       0 100.00%         0       0   0.00%
-// REPORT-NEXT: ---
-// REPORT-NEXT: TOTAL                            42       5  88.10%        32       0 100.00% 40      16  60.00%
diff --git a/llvm/test/tools/llvm-cov/Inputs/branch-showBranchPercentage.c b/llvm/test/tools/llvm-cov/Inputs/branch-showBranchPercentage.c
new file mode 100644
index 0000000000000..c41739ff0b22f
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/branch-showBranchPercentage.c
@@ -0,0 +1,58 @@
+
+
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+extern void __llvm_profile_write_file(void);
+
+int main(int argc, char *argv[])
+{
+  int i = 0;
+  if (argc < 3)                       // CHECK: Branch ([[@LINE]]:7): [True: 16.67%, False: 83.33%]
+  {
+    __llvm_profile_write_file();
+    return 0;
+  }
+
+  int a = atoi(argv[1]);
+  int b = atoi(argv[2]);
+
+                                      // CHECK: Branch ([[@LINE+4]]:8): [True: 20.00%, False: 80.00%]
+                                      // CHECK: Branch ([[@LINE+3]]:18): [True: 0.00%, False: 100.00%]
+                                      // CHECK: Branch ([[@LINE+2]]:29): [True: 0.00%, False: 100.00%]
+                                      // CHECK: Branch ([[@LINE+1]]:40): [True: 40.00%, False: 60.00%]
+  if ((a == 0 && b == 2) || b == 34 || a == b)
+    printf("case1\n");
+
+  b = (a != 0 || a == 2) ? b : b+2;   // CHECK: Branch ([[@LINE]]:8): [True: 80.00%, False: 20.00%]
+                                      // CHECK: Branch ([[@LINE-1]]:18): [True: 0.00%, False: 100.00%]
+  b = (a != 0 && a == 1);             // CHECK: Branch ([[@LINE]]:8): [True: 80.00%, False: 20.00%]
+                                      // CHECK: Branch ([[@LINE-1]]:18): [True: 25.00%, False: 75.00%]
+  for (i = 0; i < b; i++) { a = 2 + b + b; }
+                                      // CHECK: Branch ([[@LINE-1]]:15): [True: 16.67%, False: 83.33%]
+
+  b = a;
+
+  switch (a)
+  {
+    case 0:                           // CHECK: Branch ([[@LINE]]:5): [True: 20.00%, False: 80.00%]
+      printf("case0\n");
+    case 2:                           // CHECK: Branch ([[@LINE]]:5): [True: 20.00%, False: 80.00%]
+      printf("case2\n");
+    case 3:                           // CHECK: Branch ([[@LINE]]:5): [True: 0.00%, False: 100.00%]
+      printf("case3\n");
+    default: break;                   // CHECK: Branch ([[@LINE]]:5): [True: 60.00%, False: 40.00%]
+  }
+
+  i = 0;
+  do {
+    printf("loop\n");
+  } while (i++ < 10);                 // CHECK: Branch ([[@LINE]]:12): [True: 90.91%, False: 9.09%]
+
+  __llvm_profile_write_file();
+
+  return b;
+}
diff --git a/llvm/test/tools/llvm-cov/Inputs/branch-templates.cpp b/llvm/test/tools/llvm-cov/Inputs/branch-templates.cpp
new file mode 100644
index 0000000000000..0795a5346380d
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/branch-templates.cpp
@@ -0,0 +1,38 @@
+
+
+
+
+
+#include <stdio.h>
+template<typename T>
+void unused(T x) {
+  return;
+}
+
+template<typename T>
+int func(T x) {
+  if(x)       // CHECK: |  Branch ([[@LINE]]:6): [True: 0, False: 1]
+    return 0; // CHECK: |  Branch ([[@LINE-1]]:6): [True: 1, False: 0]
+  else        // CHECK: |  Branch ([[@LINE-2]]:6): [True: 0, False: 1]
+    return 1;
+  int j = 1;
+}
+
+              // CHECK-LABEL: _Z4funcIiEiT_:
+              // CHECK: |  |  Branch ([[@LINE-8]]:6): [True: 0, False: 1]
+              // CHECK-LABEL: _Z4funcIbEiT_:
+              // CHECK: |  |  Branch ([[@LINE-10]]:6): [True: 1, False: 0]
+              // CHECK-LABEL: _Z4funcIfEiT_:
+              // CHECK: |  |  Branch ([[@LINE-12]]:6): [True: 0, False: 1]
+
+extern "C" { extern void __llvm_profile_write_file(void); }
+int main() {
+  if (func<int>(0))      // CHECK: |  Branch ([[@LINE]]:7): [True: 1, False: 0]
+    printf("case1\n");
+  if (func<bool>(true))  // CHECK: |  Branch ([[@LINE]]:7): [True: 0, False: 1]
+    printf("case2\n");
+  if (func<float>(0.0))  // CHECK: |  Branch ([[@LINE]]:7): [True: 1, False: 0]
+    printf("case3\n");
+  __llvm_profile_write_file();
+  return 0;
+}
diff --git a/llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts.cpp b/llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts.cpp
new file mode 100644
index 0000000000000..c7e8c8fb0c75e
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts.cpp
@@ -0,0 +1,29 @@
+// HTML-WHOLE-FILE: <td class='line-number'><a name='L[[@LINE+2]]' href='#L[[@LINE+2]]'><pre>[[@LINE+2]]</pre></a></td><td class='skipped-line'></td><td class='code'><pre>// before
+// HTML-FILTER-NOT: <td class='line-number'><a name='L[[@LINE+1]]' href='#L[[@LINE+1]]'><pre>[[@LINE+1]]</pre></a></td><td class='skipped-line'></td><td class='code'><pre>// before
+// before any coverage              // WHOLE-FILE: [[@LINE]]|      |// before
+                                    // FILTER-NOT: [[@LINE-1]]|    |// before
+// HTML: <td class='line-number'><a name='L[[@LINE+1]]' href='#L[[@LINE+1]]'><pre>[[@LINE+1]]</pre></a></td><td class='covered-line'><pre>161</pre></td><td class='code'><pre>int main() {
+int main() {                              // TEXT: [[@LINE]]|   161|int main(
+  int x = 0;                              // TEXT: [[@LINE]]|   161|  int x
+                                          // TEXT: [[@LINE]]|   161|
+  if (x) {                                // TEXT: [[@LINE]]|   161|  if (x)
+    x = 0;                                // TEXT: [[@LINE]]|     0|    x = 0
+  } else {                                // TEXT: [[@LINE]]|   161|  } else
+    x = 1;                                // TEXT: [[@LINE]]|   161|    x = 1
+  }                                       // TEXT: [[@LINE]]|   161|  }
+                                          // TEXT: [[@LINE]]|   161|
+  for (int i = 0; i < 100; ++i) {         // TEXT: [[@LINE]]| 16.2k|  for (
+    x = 1;                                // TEXT: [[@LINE]]| 16.1k|    x = 1
+  }                                       // TEXT: [[@LINE]]| 16.1k|  }
+                                          // TEXT: [[@LINE]]|   161|
+  x = x < 10 ? x + 1 : x - 1;             // TEXT: [[@LINE]]|   161|  x =
+  x = x > 10 ?                            // TEXT: [[@LINE]]|   161|  x =
+        x - 1:                            // TEXT: [[@LINE]]|     0|        x
+        x + 1;                            // TEXT: [[@LINE]]|   161|        x
+                                          // TEXT: [[@LINE]]|   161|
+  return 0;                               // TEXT: [[@LINE]]|   161|  return
+}                                         // TEXT: [[@LINE]]|   161|}
+// after coverage                   // WHOLE-FILE: [[@LINE]]|      |// after
+                                    // FILTER-NOT: [[@LINE-1]]|    |// after
+// HTML-WHOLE-FILE: <td class='line-number'><a name='L[[@LINE-2]]' href='#L[[@LINE-2]]'><pre>[[@LINE-2]]</pre></a></td><td class='skipped-line'></td><td class='code'><pre>// after
+// HTML-FILTER-NOT: <td class='line-number'><a name='L[[@LINE-3]]' href='#L[[@LINE-3]]'><pre>[[@LINE-3]]</pre></a></td><td class='skipped-line'></td><td class='code'><pre>// after
diff --git a/llvm/test/tools/llvm-cov/branch-c-general.test b/llvm/test/tools/llvm-cov/branch-c-general.test
index 2fa99dfe61532..865a2662460e8 100644
--- a/llvm/test/tools/llvm-cov/branch-c-general.test
+++ b/llvm/test/tools/llvm-cov/branch-c-general.test
@@ -114,7 +114,7 @@
 
 
 
-//      REPORT: Name                        Regions    Miss   Cover     Lines    Miss   Cover  Branches    Miss   Cover
+// REPORT:      Name                        Regions    Miss   Cover     Lines    Miss   Cover  Branches    Miss   Cover
 // REPORT-NEXT: ---
 // REPORT-NEXT: simple_loops                      8       0 100.00%         9       0 100.00%         6       0 100.00%
 // REPORT-NEXT: conditionals                     24       0 100.00%        15       0 100.00%        16       2  87.50%
diff --git a/llvm/test/tools/llvm-cov/branch-logical-mixed.test b/llvm/test/tools/llvm-cov/branch-logical-mixed.test
new file mode 100644
index 0000000000000..a07d2357f2c34
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/branch-logical-mixed.test
@@ -0,0 +1,11 @@
+// RUN: llvm-profdata merge %S/Inputs/branch-logical-mixed.proftext -o %t.profdata
+// RUN: llvm-cov show --show-branches=count %S/Inputs/branch-logical-mixed.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs | FileCheck %S/Inputs/branch-logical-mixed.cpp
+// RUN: llvm-cov report --show-branch-summary %S/Inputs/branch-logical-mixed.o32l -instr-profile %t.profdata -show-functions -path-equivalence=/tmp,%S/Inputs %S/Inputs/branch-logical-mixed.cpp
+| FileCheck %s -check-prefix=REPORT
+
+// REPORT:      Name                        Regions    Miss   Cover     Lines    Miss   Cover  Branches    Miss   Cover
+// REPORT-NEXT: ---
+// REPORT-NEXT: _Z4funcii                        77      15  80.52%        60       2  96.67%        80      30  62.50%
+// REPORT-NEXT: main                              1       0 100.00%         5       0 100.00%         0       0   0.00%
+// REPORT-NEXT: ---
+// REPORT-NEXT: TOTAL                            78      15  80.77%        65       2  96.92%        80      30  62.50%
diff --git a/llvm/test/tools/llvm-cov/branch-macros.test b/llvm/test/tools/llvm-cov/branch-macros.test
new file mode 100644
index 0000000000000..fbe7694b4f4e0
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/branch-macros.test
@@ -0,0 +1,11 @@
+// RUN: llvm-profdata merge %S/Inputs/branch-macros.proftext -o %t.profdata
+// RUN: llvm-cov show --show-expansions --show-branches=count %S/Inputs/branch-macros.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs | FileCheck %S/Inputs/branch-macros.cpp
+// RUN: llvm-cov report --show-branch-summary %S/Inputs/branch-macros.o32l -instr-profile %t.profdata -show-functions -path-equivalence=/tmp,%S/Inputs %S/Inputs/branch-macros.cpp | FileCheck %s -check-prefix=REPORT
+
+// REPORT:      Name                        Regions    Miss   Cover     Lines    Miss   Cover  Branches    Miss   Cover
+// REPORT-NEXT: ---
+// REPORT-NEXT: _Z4funcii                        28       4  85.71%        18       0 100.00%        30      14  53.33%
+// REPORT-NEXT: _Z5func2ii                       13       1  92.31%         8       0 100.00%        10       2  80.00%
+// REPORT-NEXT: main                              1       0 100.00%         6       0 100.00%         0       0   0.00%
+// REPORT-NEXT: ---
+// REPORT-NEXT: TOTAL                            42       5  88.10%        32       0 100.00%        40      16  60.00%
diff --git a/llvm/test/tools/llvm-cov/branch-noShowBranch.test b/llvm/test/tools/llvm-cov/branch-noShowBranch.test
index 25a98d59481aa..cabeeb01bfe3e 100644
--- a/llvm/test/tools/llvm-cov/branch-noShowBranch.test
+++ b/llvm/test/tools/llvm-cov/branch-noShowBranch.test
@@ -5,9 +5,9 @@
 
 // CHECK-NOT: | Branch
 
-// REPORT: Name                        Regions    Miss   Cover     Lines    Miss   Cover
+// REPORT:     Name                        Regions    Miss   Cover     Lines    Miss   Cover
 // REPORT-NOT: Name                        Regions    Miss   Cover     Lines    Miss   Cover  Branches    Miss   Cover
-// REPORT: ---
+// REPORT:     ---
 // REPORT-NOT: simple_loops                      8       0 100.00%         9       0 100.00%         6       0 100.00%
 // REPORT-NOT: conditionals                     24       0 100.00%        15       0 100.00%        16       2  87.50%
 // REPORT-NOT: early_exits                      20       4  80.00%        25       2  92.00%        16       6  62.50%
@@ -20,6 +20,6 @@
 // REPORT-NOT: do_fallthrough                    9       0 100.00%        12       0 100.00%         6       0 100.00%
 // REPORT-NOT: main                              1       0 100.00%        16       0 100.00%         0       0   0.00%
 // REPORT-NOT: c-general.c:static_func           4       0 100.00%         4       0 100.00%         2       0 100.00%
-// REPORT: TOTAL                           197      24  87.82%       234       8  96.58%
-// REPORT-NOT: TOTAL                           197      24  87.82%       234       13  94.44%       174      38  78.16%
+// REPORT:     TOTAL                           197      24  87.82%       234       8  96.58%
+// REPORT-NOT: TOTAL                           197      24  87.82%       234      13  94.44%       174      38  78.16%
 
diff --git a/llvm/test/tools/llvm-cov/branch-showBranchPercentage.c b/llvm/test/tools/llvm-cov/branch-showBranchPercentage.test
similarity index 51%
rename from llvm/test/tools/llvm-cov/branch-showBranchPercentage.c
rename to llvm/test/tools/llvm-cov/branch-showBranchPercentage.test
index a649462116a08..f6f9e3df742b4 100644
--- a/llvm/test/tools/llvm-cov/branch-showBranchPercentage.c
+++ b/llvm/test/tools/llvm-cov/branch-showBranchPercentage.test
@@ -1,63 +1,10 @@
 // Test visualization of branch taken percentages
 
 // RUN: llvm-profdata merge %S/Inputs/branch-showBranchPercentage.proftext -o %t.profdata
-// RUN: llvm-cov show --show-branches=percent %S/Inputs/branch-showBranchPercentage.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S %s | FileCheck %s
+// RUN: llvm-cov show --show-branches=percent %S/Inputs/branch-showBranchPercentage.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs | FileCheck %S/Inputs/branch-showBranchPercentage.c
 
-#include <stdio.h>
-#include <stdlib.h>
-
-extern void __llvm_profile_write_file(void);
-
-int main(int argc, char *argv[])
-{
-  int i = 0;
-  if (argc < 3)                       // CHECK: Branch ([[@LINE]]:7): [True: 16.67%, False: 83.33%]
-  {
-    __llvm_profile_write_file();
-    return 0;
-  }
-
-  int a = atoi(argv[1]);
-  int b = atoi(argv[2]);
-
-                                      // CHECK: Branch ([[@LINE+4]]:8): [True: 20.00%, False: 80.00%]
-                                      // CHECK: Branch ([[@LINE+3]]:18): [True: 0.00%, False: 100.00%]
-                                      // CHECK: Branch ([[@LINE+2]]:29): [True: 0.00%, False: 100.00%]
-                                      // CHECK: Branch ([[@LINE+1]]:40): [True: 40.00%, False: 60.00%]
-  if ((a == 0 && b == 2) || b == 34 || a == b)
-    printf("case1\n");
-
-  b = (a != 0 || a == 2) ? b : b+2;   // CHECK: Branch ([[@LINE]]:8): [True: 80.00%, False: 20.00%]
-                                      // CHECK: Branch ([[@LINE-1]]:18): [True: 0.00%, False: 100.00%]
-  b = (a != 0 && a == 1);             // CHECK: Branch ([[@LINE]]:8): [True: 80.00%, False: 20.00%]
-                                      // CHECK: Branch ([[@LINE-1]]:18): [True: 25.00%, False: 75.00%]
-  for (i = 0; i < b; i++) { a = 2 + b + b; }
-                                      // CHECK: Branch ([[@LINE-1]]:15): [True: 16.67%, False: 83.33%]
-
-  b = a;
-
-  switch (a)
-  {
-    case 0:                           // CHECK: Branch ([[@LINE]]:5): [True: 20.00%, False: 80.00%]
-      printf("case0\n");
-    case 2:                           // CHECK: Branch ([[@LINE]]:5): [True: 20.00%, False: 80.00%]
-      printf("case2\n");
-    case 3:                           // CHECK: Branch ([[@LINE]]:5): [True: 0.00%, False: 100.00%]
-      printf("case3\n");
-    default: break;                   // CHECK: Branch ([[@LINE]]:5): [True: 60.00%, False: 40.00%]
-  }
-
-  i = 0;
-  do {
-    printf("loop\n");
-  } while (i++ < 10);                 // CHECK: Branch ([[@LINE]]:12): [True: 90.91%, False: 9.09%]
-
-  __llvm_profile_write_file();
-
-  return b;
-}
 // RUN: llvm-profdata merge %S/Inputs/branch-showBranchPercentage.proftext -o %t.profdata
-// RUN: llvm-cov show --show-branches=percent %S/Inputs/branch-showBranchPercentage.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S %s -format html -o %t.html.dir
+// RUN: llvm-cov show --show-branches=percent %S/Inputs/branch-showBranchPercentage.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs -format html -o %t.html.dir
 
 // Test html output.
 // RUN: FileCheck -check-prefix=HTML -input-file=%t.html.dir/coverage/tmp/branch-showBranchPercentage.c.html %s
diff --git a/llvm/test/tools/llvm-cov/branch-templates.cpp b/llvm/test/tools/llvm-cov/branch-templates.test
similarity index 54%
rename from llvm/test/tools/llvm-cov/branch-templates.cpp
rename to llvm/test/tools/llvm-cov/branch-templates.test
index 4797428f8835a..74aef16050228 100644
--- a/llvm/test/tools/llvm-cov/branch-templates.cpp
+++ b/llvm/test/tools/llvm-cov/branch-templates.test
@@ -1,43 +1,9 @@
 // RUN: llvm-profdata merge %S/Inputs/branch-templates.proftext -o %t.profdata
-// RUN: llvm-cov show --show-expansions --show-branches=count %S/Inputs/branch-templates.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S %s | FileCheck %s
-// RUN: llvm-cov report --show-branch-summary %S/Inputs/branch-templates.o32l -instr-profile %t.profdata -show-functions -path-equivalence=/tmp,%S %s | FileCheck %s -check-prefix=REPORT
-// RUN: llvm-cov report --show-branch-summary %S/Inputs/branch-templates.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S %s | FileCheck %s -check-prefix=REPORTFILE
+// RUN: llvm-cov show --show-expansions --show-branches=count %S/Inputs/branch-templates.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs | FileCheck %S/Inputs/branch-templates.cpp
+// RUN: llvm-cov report --show-branch-summary %S/Inputs/branch-templates.o32l -instr-profile %t.profdata -show-functions -path-equivalence=/tmp,%S/Inputs %S/Inputs/branch-templates.cpp | FileCheck %s -check-prefix=REPORT
+// RUN: llvm-cov report --show-branch-summary %S/Inputs/branch-templates.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs | FileCheck %s -check-prefix=REPORTFILE
 
-#include <stdio.h>
-template<typename T>
-void unused(T x) {
-  return;
-}
-
-template<typename T>
-int func(T x) {
-  if(x)       // CHECK: |  Branch ([[@LINE]]:6): [True: 0, False: 1]
-    return 0; // CHECK: |  Branch ([[@LINE-1]]:6): [True: 1, False: 0]
-  else        // CHECK: |  Branch ([[@LINE-2]]:6): [True: 0, False: 1]
-    return 1;
-  int j = 1;
-}
-
-              // CHECK-LABEL: _Z4funcIiEiT_:
-              // CHECK: |  |  Branch ([[@LINE-8]]:6): [True: 0, False: 1]
-              // CHECK-LABEL: _Z4funcIbEiT_:
-              // CHECK: |  |  Branch ([[@LINE-10]]:6): [True: 1, False: 0]
-              // CHECK-LABEL: _Z4funcIfEiT_:
-              // CHECK: |  |  Branch ([[@LINE-12]]:6): [True: 0, False: 1]
-
-extern "C" { extern void __llvm_profile_write_file(void); }
-int main() {
-  if (func<int>(0))      // CHECK: |  Branch ([[@LINE]]:7): [True: 1, False: 0]
-    printf("case1\n");
-  if (func<bool>(true))  // CHECK: |  Branch ([[@LINE]]:7): [True: 0, False: 1]
-    printf("case2\n");
-  if (func<float>(0.0))  // CHECK: |  Branch ([[@LINE]]:7): [True: 1, False: 0]
-    printf("case3\n");
-  __llvm_profile_write_file();
-  return 0;
-}
-
-// REPORT: Name                        Regions    Miss   Cover     Lines    Miss   Cover  Branches    Miss   Cover
+// REPORT:      Name                        Regions    Miss   Cover     Lines    Miss   Cover  Branches    Miss   Cover
 // REPORT-NEXT: ---
 // REPORT-NEXT: main                              7       1  85.71%        10       1  90.00%         6       3  50.00%
 // REPORT-NEXT: _Z4funcIiEiT_                     5       2  60.00%         7       3  57.14%         2       1  50.00%
@@ -54,8 +20,8 @@ int main() {
 // respectively).  This is returned by: FunctionCoverageSummary::get(const
 // InstantiationGroup &Group, ...)
 
-// REPORTFILE: Filename                      Regions    Missed Regions     Cover   Functions  Missed Functions  Executed       Lines      Missed Lines     Cover    Branches   Missed Branches     Cover
+// REPORTFILE:      Filename                 Regions    Missed Regions     Cover   Functions  Missed Functions  Executed       Lines      Missed Lines     Cover    Branches   Missed Branches     Cover
 // REPORTFILE-NEXT: ---
 // REPORTFILE-NEXT: branch-templates.cpp          12                 3    75.00%           2                 0   100.00%          17                 4    76.47%           8                 4    50.00%
 // REPORTFILE-NEXT: ---
-// REPORTFILE-NEXT: TOTAL                              12                 3    75.00%           2                 0   100.00%          17                 4    76.47%           8                 4    50.00%
+// REPORTFILE-NEXT: TOTAL                         12                 3    75.00%           2                 0   100.00%          17                 4    76.47%           8                 4    50.00%
diff --git a/llvm/test/tools/llvm-cov/showLineExecutionCounts.cpp b/llvm/test/tools/llvm-cov/showLineExecutionCounts.cpp
deleted file mode 100644
index f72a9978b8a73..0000000000000
--- a/llvm/test/tools/llvm-cov/showLineExecutionCounts.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-// Basic handling of line counts.
-// RUN: llvm-profdata merge %S/Inputs/lineExecutionCounts.proftext -o %t.profdata
-
-// before any coverage              // WHOLE-FILE: [[@LINE]]|      |// before
-                                    // FILTER-NOT: [[@LINE-1]]|    |// before
-int main() {                              // TEXT: [[@LINE]]|   161|int main(
-  int x = 0;                              // TEXT: [[@LINE]]|   161|  int x
-                                          // TEXT: [[@LINE]]|   161|
-  if (x) {                                // TEXT: [[@LINE]]|   161|  if (x)
-    x = 0;                                // TEXT: [[@LINE]]|     0|    x = 0
-  } else {                                // TEXT: [[@LINE]]|   161|  } else
-    x = 1;                                // TEXT: [[@LINE]]|   161|    x = 1
-  }                                       // TEXT: [[@LINE]]|   161|  }
-                                          // TEXT: [[@LINE]]|   161|
-  for (int i = 0; i < 100; ++i) {         // TEXT: [[@LINE]]| 16.2k|  for (
-    x = 1;                                // TEXT: [[@LINE]]| 16.1k|    x = 1
-  }                                       // TEXT: [[@LINE]]| 16.1k|  }
-                                          // TEXT: [[@LINE]]|   161|
-  x = x < 10 ? x + 1 : x - 1;             // TEXT: [[@LINE]]|   161|  x =
-  x = x > 10 ?                            // TEXT: [[@LINE]]|   161|  x =
-        x - 1:                            // TEXT: [[@LINE]]|     0|        x
-        x + 1;                            // TEXT: [[@LINE]]|   161|        x
-                                          // TEXT: [[@LINE]]|   161|
-  return 0;                               // TEXT: [[@LINE]]|   161|  return
-}                                         // TEXT: [[@LINE]]|   161|}
-// after coverage                   // WHOLE-FILE: [[@LINE]]|      |// after
-                                    // FILTER-NOT: [[@LINE-1]]|    |// after
-
-// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata -path-equivalence=/tmp,%S %s | FileCheck -check-prefixes=TEXT,WHOLE-FILE %s
-// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata -path-equivalence=/tmp,%S -name=main %s | FileCheck -check-prefixes=TEXT,FILTER %s
-
-// Test -output-dir.
-// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -o %t.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S %s
-// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -output-dir %t.filtered.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S -name=main %s
-// RUN: FileCheck -check-prefixes=TEXT,WHOLE-FILE -input-file %t.dir/coverage/tmp/showLineExecutionCounts.cpp.txt %s
-// RUN: FileCheck -check-prefixes=TEXT,FILTER -input-file %t.filtered.dir/coverage/tmp/showLineExecutionCounts.cpp.txt %s
-//
-// RUN: llvm-cov export %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata 2>/dev/null -summary-only > %t.export-summary.json
-// RUN: not grep '"name":"main"' %t.export-summary.json
-//
-// Test html output.
-// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -format html -o %t.html.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S %s
-// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -format html -o %t.html.filtered.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S -name=main %s
-// RUN: FileCheck -check-prefixes=HTML,HTML-WHOLE-FILE -input-file %t.html.dir/coverage/tmp/showLineExecutionCounts.cpp.html %s
-// RUN: FileCheck -check-prefixes=HTML,HTML-FILTER -input-file %t.html.filtered.dir/coverage/tmp/showLineExecutionCounts.cpp.html %s
-//
-// HTML-WHOLE-FILE: <td class='line-number'><a name='L4' href='#L4'><pre>4</pre></a></td><td class='skipped-line'></td><td class='code'><pre>// before
-// HTML-FILTER-NOT: <td class='line-number'><a name='L4' href='#L4'><pre>4</pre></a></td><td class='skipped-line'></td><td class='code'><pre>// before
-// HTML: <td class='line-number'><a name='L6' href='#L6'><pre>6</pre></a></td><td class='covered-line'><pre>161</pre></td><td class='code'><pre>int main() {
-// HTML-WHOLE-FILE: <td class='line-number'><a name='L26' href='#L26'><pre>26</pre></a></td><td class='skipped-line'></td><td class='code'><pre>// after
-// HTML-FILTER-NOT: <td class='line-number'><a name='L26' href='#L26'><pre>26</pre></a></td><td class='skipped-line'></td><td class='code'><pre>// after
-//
-// Test index creation.
-// RUN: FileCheck -check-prefix=TEXT-INDEX -input-file %t.dir/index.txt %s
-// TEXT-INDEX: Filename
-// TEXT-INDEX-NEXT: ---
-// TEXT-INDEX-NEXT: {{.*}}showLineExecutionCounts.cpp
-//
-// RUN: FileCheck -check-prefix HTML-INDEX -input-file %t.html.dir/index.html %s
-// HTML-INDEX-LABEL: <table>
-// HTML-INDEX: <td class='column-entry-bold'>Filename</td>
-// HTML-INDEX: <td class='column-entry-bold'>Function Coverage</td>
-// HTML-INDEX: <td class='column-entry-bold'>Line Coverage</td>
-// HTML-INDEX: <td class='column-entry-bold'>Region Coverage</td>
-// HTML-INDEX: <a href='coverage{{.*}}showLineExecutionCounts.cpp.html'{{.*}}showLineExecutionCounts.cpp</a>
-// HTML-INDEX: <td class='column-entry-green'>
-// HTML-INDEX: 100.00% (1/1)
-// HTML-INDEX: <td class='column-entry-yellow'>
-// HTML-INDEX: 90.00% (18/20)
-// HTML-INDEX: <td class='column-entry-red'>
-// HTML-INDEX: 72.73% (8/11)
-// HTML-INDEX: <tr class='light-row-bold'>
-// HTML-INDEX: Totals
diff --git a/llvm/test/tools/llvm-cov/showLineExecutionCounts.test b/llvm/test/tools/llvm-cov/showLineExecutionCounts.test
new file mode 100644
index 0000000000000..997b16a0b8e94
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/showLineExecutionCounts.test
@@ -0,0 +1,43 @@
+// Basic handling of line counts.
+// RUN: rm -rf %t*.dir
+// RUN: llvm-profdata merge %S/Inputs/lineExecutionCounts.proftext -o %t.profdata
+
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs | FileCheck -check-prefixes=TEXT,WHOLE-FILE %S/Inputs/showLineExecutionCounts.cpp
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs -name=main | FileCheck -check-prefixes=TEXT,FILTER %S/Inputs/showLineExecutionCounts.cpp
+
+// Test -output-dir.
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -o %t.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -output-dir %t.filtered.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs -name=main
+// RUN: FileCheck -check-prefixes=TEXT,WHOLE-FILE -input-file %t.dir/coverage/tmp/showLineExecutionCounts.cpp.txt %S/Inputs/showLineExecutionCounts.cpp
+// RUN: FileCheck -check-prefixes=TEXT,FILTER -input-file %t.filtered.dir/coverage/tmp/showLineExecutionCounts.cpp.txt %S/Inputs/showLineExecutionCounts.cpp
+//
+// RUN: llvm-cov export %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata 2>/dev/null -summary-only > %t.export-summary.json
+// RUN: not grep '"name":"main"' %t.export-summary.json
+//
+// Test html output.
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -format html -o %t.html.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -format html -o %t.html.filtered.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs -name=main
+// RUN: FileCheck -check-prefixes=HTML,HTML-WHOLE-FILE -input-file %t.html.dir/coverage/tmp/showLineExecutionCounts.cpp.html %S/Inputs/showLineExecutionCounts.cpp
+// RUN: FileCheck -check-prefixes=HTML,HTML-FILTER -input-file %t.html.filtered.dir/coverage/tmp/showLineExecutionCounts.cpp.html %S/Inputs/showLineExecutionCounts.cpp
+//
+// Test index creation.
+// RUN: FileCheck -check-prefix=TEXT-INDEX -input-file %t.dir/index.txt %s
+// TEXT-INDEX: Filename
+// TEXT-INDEX-NEXT: ---
+// TEXT-INDEX-NEXT: {{.*}}showLineExecutionCounts.cpp
+//
+// RUN: FileCheck -check-prefix HTML-INDEX -input-file %t.html.dir/index.html %s
+// HTML-INDEX-LABEL: <table>
+// HTML-INDEX: <td class='column-entry-bold'>Filename</td>
+// HTML-INDEX: <td class='column-entry-bold'>Function Coverage</td>
+// HTML-INDEX: <td class='column-entry-bold'>Line Coverage</td>
+// HTML-INDEX: <td class='column-entry-bold'>Region Coverage</td>
+// HTML-INDEX: <a href='coverage{{.*}}showLineExecutionCounts.cpp.html'{{.*}}showLineExecutionCounts.cpp</a>
+// HTML-INDEX: <td class='column-entry-green'>
+// HTML-INDEX: 100.00% (1/1)
+// HTML-INDEX: <td class='column-entry-yellow'>
+// HTML-INDEX: 90.00% (18/20)
+// HTML-INDEX: <td class='column-entry-red'>
+// HTML-INDEX: 72.73% (8/11)
+// HTML-INDEX: <tr class='light-row-bold'>
+// HTML-INDEX: Totals

>From c50c492964a9239fc9e07ffe4a56bdbd4bf17aa8 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Wed, 20 Nov 2024 23:34:04 +0900
Subject: [PATCH 19/72] Introduce test/llvm-cov/Inputs/yaml.makefile for
 convenience.

---
 llvm/test/tools/llvm-cov/Inputs/yaml.makefile | 96 +++++++++++++++++++
 1 file changed, 96 insertions(+)
 create mode 100644 llvm/test/tools/llvm-cov/Inputs/yaml.makefile

diff --git a/llvm/test/tools/llvm-cov/Inputs/yaml.makefile b/llvm/test/tools/llvm-cov/Inputs/yaml.makefile
new file mode 100644
index 0000000000000..2a256f0cffc0b
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/yaml.makefile
@@ -0,0 +1,96 @@
+# This is for developers' convenience and not expected to be in build steps.
+#
+# Usage:
+#   cd /path/to/llvm-project/llvm/test/tools/llvm-cov/Inputs
+#   PATH=/path/to/build/bin:$PATH make -f yaml.makefile
+
+CFLAGS_COVMAP	= -fcoverage-compilation-dir=. \
+		  -mllvm -runtime-counter-relocation=true \
+		  -mllvm -conditional-counter-update=true \
+		  -mllvm -enable-name-compression=false \
+		  -fprofile-instr-generate -fcoverage-mapping \
+		  $(if $(filter mcdc-%, $*), $(CFLAGS_MCDC))
+
+CFLAGS_MCDC	= -fcoverage-mcdc
+
+%.o: %.cpp
+	clang++ $< -c -o $@ $(CFLAGS_COVMAP)
+
+%.o: %.c
+	clang $< -c -o $@ $(CFLAGS_COVMAP)
+
+%-single.o: %.cpp
+	clang++ $< -c -o $@ \
+		-mllvm -enable-single-byte-coverage=true \
+		$(CFLAGS_COVMAP)
+
+%-single.o: %.c
+	clang $< -c -o $@ \
+		-mllvm -enable-single-byte-coverage=true \
+		$(CFLAGS_COVMAP)
+
+%.covmap.o: %.o
+	llvm-objcopy \
+		--only-section=__llvm_covfun \
+		--only-section=__llvm_covmap \
+		--only-section=__llvm_prf_names \
+		--strip-unneeded \
+		$< $@
+
+%.yaml: %.covmap.o
+	obj2yaml $< > $@
+
+%.exe: %.o
+	clang++ -fprofile-instr-generate $^ -o $@
+
+ARGS_branch-logical-mixed := \
+	0 0; \
+	0 1; \
+	1 0; \
+	1 1
+
+ARGS_branch-macros := \
+	0 1; \
+	1 0; \
+	1 1
+
+ARGS_branch-showBranchPercentage := \
+	0 1; \
+	1 1; \
+	2 2; \
+	4 0; \
+	5 0; \
+	1
+
+ARGS_showLineExecutionCounts := $(patsubst %,%;,$(shell seq 161))
+
+ARGS_mcdc-const-folding := \
+	0 1; \
+	1 0; \
+	1 1; \
+	1 1
+
+%.profdata: %.exe
+	-find -name '$*.*.profraw' | xargs rm -fv
+	@if [ "$(ARGS_$(patsubst %-single,%,$*))" = "" ]; then \
+	  echo "Executing: $<"; \
+	  LLVM_PROFILE_FILE=$*.%p%c.profraw ./$<; \
+	else \
+	  LLVM_PROFILE_FILE=$*.%p%c.profraw; \
+	  export LLVM_PROFILE_FILE; \
+	  for xcmd in $(shell echo "$(ARGS_$(patsubst %-single,%,$*))" | tr ';[:blank:]' ' %'); do \
+	    cmd=$$(echo "$$xcmd" | tr '%' ' '); \
+	    echo "Executing series: $< $$cmd"; \
+	    eval "./$< $$cmd"; \
+	  done; \
+	fi
+	find -name '$*.*.profraw' | xargs llvm-profdata merge --sparse -o $@
+
+%.proftext: %.profdata
+	llvm-profdata merge --text -o $@ $<
+
+.PHONY: all
+all:	\
+	$(patsubst %.yaml,%.proftext, $(wildcard *.yaml)) \
+	$(wildcard *.yaml)
+	-find -name '*.profraw' | xargs rm -f

>From d7c5b4404c48a6b02ddffc331849335580e16b9b Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Wed, 20 Nov 2024 23:34:16 +0900
Subject: [PATCH 20/72] Add tests for SingleByteCoverage

---
 .../Inputs/branch-c-general-single.proftext   | 297 ++++++++++++++++++
 .../Inputs/branch-c-general-single.yaml       | 177 +++++++++++
 .../tools/llvm-cov/Inputs/branch-c-general.c  | 202 ++++++------
 .../branch-logical-mixed-single.proftext      |  84 +++++
 .../Inputs/branch-logical-mixed-single.yaml   |  57 ++++
 .../llvm-cov/Inputs/branch-logical-mixed.cpp  |  86 ++---
 .../Inputs/branch-macros-single.proftext      |  53 ++++
 .../llvm-cov/Inputs/branch-macros-single.yaml |  69 ++++
 .../tools/llvm-cov/Inputs/branch-macros.cpp   |  46 +--
 .../Inputs/branch-showBranchPercentage.c      |   6 +-
 .../Inputs/branch-templates-single.proftext   |  49 +++
 .../Inputs/branch-templates-single.yaml       |  81 +++++
 .../llvm-cov/Inputs/branch-templates.cpp      |  22 +-
 .../showLineExecutionCounts-single.proftext   |  23 ++
 .../showLineExecutionCounts-single.yaml       |  45 +++
 .../Inputs/showLineExecutionCounts.cpp        |  40 +--
 .../test/tools/llvm-cov/branch-c-general.test |   4 +
 .../tools/llvm-cov/branch-logical-mixed.test  |   8 +-
 llvm/test/tools/llvm-cov/branch-macros.test   |   6 +-
 .../test/tools/llvm-cov/branch-templates.test |   4 +
 .../llvm-cov/showLineExecutionCounts.test     |   7 +
 21 files changed, 1163 insertions(+), 203 deletions(-)
 create mode 100644 llvm/test/tools/llvm-cov/Inputs/branch-c-general-single.proftext
 create mode 100644 llvm/test/tools/llvm-cov/Inputs/branch-c-general-single.yaml
 create mode 100644 llvm/test/tools/llvm-cov/Inputs/branch-logical-mixed-single.proftext
 create mode 100644 llvm/test/tools/llvm-cov/Inputs/branch-logical-mixed-single.yaml
 create mode 100644 llvm/test/tools/llvm-cov/Inputs/branch-macros-single.proftext
 create mode 100644 llvm/test/tools/llvm-cov/Inputs/branch-macros-single.yaml
 create mode 100644 llvm/test/tools/llvm-cov/Inputs/branch-templates-single.proftext
 create mode 100644 llvm/test/tools/llvm-cov/Inputs/branch-templates-single.yaml
 create mode 100644 llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts-single.proftext
 create mode 100644 llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts-single.yaml

diff --git a/llvm/test/tools/llvm-cov/Inputs/branch-c-general-single.proftext b/llvm/test/tools/llvm-cov/Inputs/branch-c-general-single.proftext
new file mode 100644
index 0000000000000..ea8c6f9bc634e
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/branch-c-general-single.proftext
@@ -0,0 +1,297 @@
+# Instrument block coverage
+:single_byte_coverage
+big_switch
+# Func Hash:
+13144136522122330070
+# Num Counters:
+27
+# Counter Values:
+1
+1
+1
+1
+1
+1
+1
+0
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+
+boolean_operators
+# Func Hash:
+1245693242827665
+# Num Counters:
+17
+# Counter Values:
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+
+boolop_loops
+# Func Hash:
+12402604614320574815
+# Num Counters:
+23
+# Counter Values:
+1
+0
+1
+1
+1
+1
+0
+1
+1
+1
+1
+0
+1
+1
+1
+1
+1
+0
+1
+1
+1
+1
+1
+
+branch-c-general.c:static_func
+# Func Hash:
+18129
+# Num Counters:
+5
+# Counter Values:
+1
+1
+1
+1
+1
+
+conditional_operator
+# Func Hash:
+54992
+# Num Counters:
+5
+# Counter Values:
+1
+1
+0
+1
+1
+
+conditionals
+# Func Hash:
+4904767535850050386
+# Num Counters:
+25
+# Counter Values:
+1
+1
+1
+1
+1
+1
+0
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+
+do_fallthrough
+# Func Hash:
+8714614136504380050
+# Num Counters:
+10
+# Counter Values:
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+
+early_exits
+# Func Hash:
+2880354649761471549
+# Num Counters:
+20
+# Counter Values:
+1
+0
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+0
+1
+1
+1
+0
+0
+
+jumps
+# Func Hash:
+15051420506203462683
+# Num Counters:
+38
+# Counter Values:
+1
+1
+0
+1
+0
+0
+0
+1
+0
+1
+1
+0
+1
+1
+0
+1
+1
+1
+1
+1
+1
+1
+0
+1
+1
+0
+1
+1
+1
+1
+1
+1
+1
+0
+0
+1
+1
+1
+
+main
+# Func Hash:
+24
+# Num Counters:
+1
+# Counter Values:
+1
+
+simple_loops
+# Func Hash:
+1245818015463121
+# Num Counters:
+11
+# Counter Values:
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+
+switches
+# Func Hash:
+43242458792028222
+# Num Counters:
+29
+# Counter Values:
+1
+1
+1
+1
+1
+1
+0
+1
+1
+0
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+0
+1
+1
+1
+1
+1
+1
+0
+0
+
diff --git a/llvm/test/tools/llvm-cov/Inputs/branch-c-general-single.yaml b/llvm/test/tools/llvm-cov/Inputs/branch-c-general-single.yaml
new file mode 100644
index 0000000000000..9d23dcb67ad2a
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/branch-c-general-single.yaml
@@ -0,0 +1,177 @@
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_X86_64
+  SectionHeaderStringTable: .strtab
+Sections:
+  - Name:            __llvm_covfun
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_GNU_RETAIN ]
+    AddressAlign:    0x8
+    Content:         D7878914FBE99B074D000000D136449C106D04004C551E9517F40F4F0101000D010715080205020F0016090018001B0D001C009D808080080D001D0104110203040215000A000F19001001858080800819010500081D01030202210006000825001000181001010001
+  - Name:            '__llvm_covfun (1)'
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_GNU_RETAIN ]
+    AddressAlign:    0x8
+    Content:         83AD05A5F1438E68EA00000052D33558163C11444C551E9517F40F4F010100260111150E02050113001A09001C001F0D002000A1808080080D00210B040D0109000E15000F009080808008150010020615010B000C21000D008E8080800821000E0010310106008C8080800831000C04063100100015290016009780808008290017020629010B000C35000D008E8080800835000E00102D0106008C808080082D000C02062D010B000C3D000D008E808080083D000E0010100201005B1D010502041D0009000A1D0009000F4D000E000F45001000918080800845001100134901050104490009000A490009000F5D000E000F55001000918080800855001100131002010001
+  - Name:            '__llvm_covfun (2)'
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_GNU_RETAIN ]
+    AddressAlign:    0x8
+    Content:         0449C70428C57369F80000003D5C2D0E4B13F9274C551E9517F40F4F01010028012114180210020100010101070008050009008A8080800805000A000C100101000109010313020D000A00111100120093808080081100130604110209000F190010018780808008190107000C1D000D0185808080081D010502041D0009000E21000F018780808008210107000F15010402838080800810010100011501030B021500070008290009008A8080800829000A000C10010100012D010309023100060504310109000F3D00100187808080083D0107000D41000E028780808008410207000A35010C0013390015028380808008100101000139010302023900070008490009008A8080800849000A000C1001010001
+  - Name:            '__llvm_covfun (3)'
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_GNU_RETAIN ]
+    AddressAlign:    0x8
+    Content:         55947829059F255EB80100001B9C495D3463E1D04C551E9517F40F4F01010046013B0E2F02100201000105010F001409001600190D001A009B808080080D001B040400011402858080800810010100230001050104000009000A15000B008C8080800815000C000E11010402818080800810010100011D010126021D01070008210009008A8080800821000A000C1001010001250103000D25000E0283808080081001010001000103210229000A000B2D000C008D808080082D000D03043501030204350109000A39000B008C8080800839000C000E1002010001310103000D31000E0181808080084101011B024501011A024901011902490207000C4D000D0185808080084D0105000F5100100283808080081001010001510103140255000A000F5900100091808080085900110A04610103090400011006918080800869010501110001120185808080086D0105011200011301858080800871010501115D030402838080800810010100015D0103080275000F0015790017001A7D001B009C808080087D001C0604000115028580808008100101003F0001050304000009000A8501000B008C808080088501000C000E8D01010302048D010109000A9101000B008C808080089101000C000E1002010001
+  - Name:            '__llvm_covfun (4)'
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_GNU_RETAIN ]
+    AddressAlign:    0x8
+    Content:         7129CA3C268292BF4D0100003E688383C9A099004C551E9517F40F4F01010035016C112502100201011C000217028A80808008090103010A05020402838080800810010100620501031C020D003F0046110048004B15004C00CD8080800815004D1704000119148F80808008210105130F21010B000C25000D008E8080800825000E001010010100152D0105100F2D010B000C31000D008E8080800831000E0010350107000C35000D0185808080083901050D0F39010B000C3D000D008E808080083D000E0010410107000F4100100185808080084501050A0F45010B000C49000D008E8080800849000E00104D0107080F000012039180808008550107021155010D000E59000F00908080800859001000125D010900115101080285808080081001010001610105020F61010B0017650018018980808008650109000F1902040383808080081001010121190203020219000700116D00120093808080086D001300151001010001
+  - Name:            '__llvm_covfun (5)'
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_GNU_RETAIN ]
+    AddressAlign:    0x8
+    Content:         3F4D1C6E6087417B32010000D6FF56B8865A69B64C551E9517F40F4F01010031019301131F02050113001909001B001E0D001F00A0808080080D00201C04000115198C80808008190105180C19010B000C1D000D008E808080081D000E00101001010015250105150C25010B000C29000D008E8080800829000E00102D0107000C2D000D018580808008310105120C31010B000C35000D008E8080800835000E0010390107000C39000D03858080800810010101013D02050D0C3D010B000C41000D008E8080800841000E0010450107000C45000D0185808080084901050A0C49010B000C4D000D008E808080084D000E0010510107000C51000D0385808080081001010101550205050C55010B000C59000D008E8080800859000E00105D0107000C5D000D018580808008610105020C61010B000C65000D008E8080800865000E0010690107000C1003010001
+  - Name:            '__llvm_covfun (6)'
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_GNU_RETAIN ]
+    AddressAlign:    0x8
+    Content:         59A48AA8899AA3587200000091E33C8FF36C04004C551E9517F40F4F0101001501B4011A0C02050213001A09001C001F0D002000A1808080080D002108040D0109000E1500120013100101005D0D0109000E1D00120013100101005D0D0109000E0D000900172D0012001725001B001C10010100630D0109000E0D000900173D0012001735001B001C1002010063
+  - Name:            '__llvm_covfun (7)'
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_GNU_RETAIN ]
+    AddressAlign:    0x8
+    Content:         F5953D044B505D139E0000005FD132562FE71EAC4C551E9517F40F4F0101001D01C201150D02100201000111010A000B11000A001511000F0015090016018580808008090105000810010100010D0103070225000A001125000A001C250015001C1D001D0185808080081D01050008100101000121010304023D001100123D0011001C3D0016001C31001E002135002200231001010061390103020255000A001155000A001C550015001C49001E00214D002200231001010061
+  - Name:            '__llvm_covfun (8)'
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_GNU_RETAIN ]
+    AddressAlign:    0x8
+    Content:         20E5C369BDF15C7940000000D0D60000000000004C551E9517F40F4F0101000B01D1011D0702100201000101010B001109001300948080800809001400150D001800191001010001050103020205000B000C01001000111001010001
+  - Name:            '__llvm_covfun (9)'
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_GNU_RETAIN ]
+    AddressAlign:    0x8
+    Content:         7DE8E7C47096EB425200000092EAF0986287F0784C551E9517F40F4F0101000D01DA01170B02050113001909001B001E0D001F00A0808080080D002009041502080606100101024D15030B00102100110092808080082100120017250018018780808008250107010619010E0013
+  - Name:            '__llvm_covfun (10)'
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_GNU_RETAIN ]
+    AddressAlign:    0x8
+    Content:         FAD58DE7366495DB0A00000018000000000000004C551E9517F40F4F0101000101F501280F02
+  - Name:            '__llvm_covfun (11)'
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_GNU_RETAIN ]
+    AddressAlign:    0x8
+    Content:         4CB4F49D6737EBF922000000D1460000000000004C551E9517F40F4F0101000501E7011B0302050113001909001B001E0D001F00A0808080080D00200104
+  - Name:            __llvm_covmap
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_GNU_RETAIN ]
+    AddressAlign:    0x8
+    Content:         0000000017000000000000000600000002140000126272616E63682D632D67656E6572616C2E6300
+  - Name:            __llvm_prf_names
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_GNU_RETAIN ]
+    AddressAlign:    0x1
+    Content:         A6010073696D706C655F6C6F6F707301636F6E646974696F6E616C73016561726C795F6578697473016A756D7073017377697463686573016269675F73776974636801626F6F6C65616E5F6F70657261746F727301626F6F6C6F705F6C6F6F707301636F6E646974696F6E616C5F6F70657261746F7201646F5F66616C6C7468726F756768016D61696E016272616E63682D632D67656E6572616C2E633A7374617469635F66756E63
+  - Type:            SectionHeaderTable
+    Sections:
+      - Name:            .strtab
+      - Name:            __llvm_covfun
+      - Name:            '__llvm_covfun (1)'
+      - Name:            '__llvm_covfun (2)'
+      - Name:            '__llvm_covfun (3)'
+      - Name:            '__llvm_covfun (4)'
+      - Name:            '__llvm_covfun (5)'
+      - Name:            '__llvm_covfun (6)'
+      - Name:            '__llvm_covfun (7)'
+      - Name:            '__llvm_covfun (8)'
+      - Name:            '__llvm_covfun (9)'
+      - Name:            '__llvm_covfun (10)'
+      - Name:            '__llvm_covfun (11)'
+      - Name:            __llvm_covmap
+      - Name:            __llvm_prf_names
+      - Name:            .symtab
+Symbols:
+  - Name:            __llvm_covmap
+    Type:            STT_SECTION
+    Section:         __llvm_covmap
+  - Name:            __llvm_prf_names
+    Type:            STT_SECTION
+    Section:         __llvm_prf_names
+  - Name:            __covrec_79BE9FB148987D7u
+    Type:            STT_OBJECT
+    Section:         __llvm_covfun
+    Binding:         STB_WEAK
+    Size:            0x69
+    Other:           [ STV_HIDDEN ]
+  - Name:            __covrec_688E43F1A505AD83u
+    Type:            STT_OBJECT
+    Section:         '__llvm_covfun (1)'
+    Binding:         STB_WEAK
+    Size:            0x106
+    Other:           [ STV_HIDDEN ]
+  - Name:            __covrec_6973C52804C74904u
+    Type:            STT_OBJECT
+    Section:         '__llvm_covfun (2)'
+    Binding:         STB_WEAK
+    Size:            0x114
+    Other:           [ STV_HIDDEN ]
+  - Name:            __covrec_5E259F0529789455u
+    Type:            STT_OBJECT
+    Section:         '__llvm_covfun (3)'
+    Binding:         STB_WEAK
+    Size:            0x1D4
+    Other:           [ STV_HIDDEN ]
+  - Name:            __covrec_BF9282263CCA2971u
+    Type:            STT_OBJECT
+    Section:         '__llvm_covfun (4)'
+    Binding:         STB_WEAK
+    Size:            0x169
+    Other:           [ STV_HIDDEN ]
+  - Name:            __covrec_7B4187606E1C4D3Fu
+    Type:            STT_OBJECT
+    Section:         '__llvm_covfun (5)'
+    Binding:         STB_WEAK
+    Size:            0x14E
+    Other:           [ STV_HIDDEN ]
+  - Name:            __covrec_58A39A89A88AA459u
+    Type:            STT_OBJECT
+    Section:         '__llvm_covfun (6)'
+    Binding:         STB_WEAK
+    Size:            0x8E
+    Other:           [ STV_HIDDEN ]
+  - Name:            __covrec_135D504B043D95F5u
+    Type:            STT_OBJECT
+    Section:         '__llvm_covfun (7)'
+    Binding:         STB_WEAK
+    Size:            0xBA
+    Other:           [ STV_HIDDEN ]
+  - Name:            __covrec_795CF1BD69C3E520u
+    Type:            STT_OBJECT
+    Section:         '__llvm_covfun (8)'
+    Binding:         STB_WEAK
+    Size:            0x5C
+    Other:           [ STV_HIDDEN ]
+  - Name:            __covrec_42EB9670C4E7E87Du
+    Type:            STT_OBJECT
+    Section:         '__llvm_covfun (9)'
+    Binding:         STB_WEAK
+    Size:            0x6E
+    Other:           [ STV_HIDDEN ]
+  - Name:            __covrec_DB956436E78DD5FAu
+    Type:            STT_OBJECT
+    Section:         '__llvm_covfun (10)'
+    Binding:         STB_WEAK
+    Size:            0x26
+    Other:           [ STV_HIDDEN ]
+  - Name:            __covrec_F9EB37679DF4B44Cu
+    Type:            STT_OBJECT
+    Section:         '__llvm_covfun (11)'
+    Binding:         STB_WEAK
+    Size:            0x3E
+    Other:           [ STV_HIDDEN ]
+...
diff --git a/llvm/test/tools/llvm-cov/Inputs/branch-c-general.c b/llvm/test/tools/llvm-cov/Inputs/branch-c-general.c
index 2e7e773e5c394..5ea9ecb42b0ed 100644
--- a/llvm/test/tools/llvm-cov/Inputs/branch-c-general.c
+++ b/llvm/test/tools/llvm-cov/Inputs/branch-c-general.c
@@ -4,75 +4,75 @@
 
 
 
-void simple_loops() {
+void simple_loops() {           // CHECK: @LINE|{{.*}}simple_loops()
   int i;
-  for (i = 0; i < 100; ++i) {
+  for (i = 0; i < 100; ++i) {   // BRCOV: Branch ([[@LINE]]:15): [True: [[C100:100|1]], False: 1]
   }
-  while (i > 0)
+  while (i > 0)                 // BRCOV: Branch ([[@LINE]]:10): [True: [[C100]], False: 1]
     i--;
-  do {} while (i++ < 75);
+  do {} while (i++ < 75);       // BRCOV: Branch ([[@LINE]]:16): [True: [[C75:75|1]], False: 1]
 
 }
 
-void conditionals() {
-  for (int i = 0; i < 100; ++i) {
-    if (i % 2) {
-      if (i) {}
-    } else if (i % 3) {
-      if (i) {}
+void conditionals() {           // CHECK: @LINE|{{.*}}conditionals()
+  for (int i = 0; i < 100; ++i) {//BRCOV: Branch ([[@LINE]]:19): [True: [[C100]], False: 1]
+    if (i % 2) {                // BRCOV: Branch ([[@LINE]]:9): [True: [[C50:50|1]], False: [[C50]]]
+      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: [[C50]], False: 0]
+    } else if (i % 3) {         // BRCOV: Branch ([[@LINE]]:16): [True: [[C33:33|1]], False: [[C17:17|1]]]
+      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: [[C33]], False: 0]
     } else {
-      if (i) {}
+      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: [[C16:16|1]], False: 1]
     }
-
-    if (1 && i) {}
-    if (0 || i) {}
-  }
+                                // BRCOV: Branch ([[@LINE+1]]:9): [True: [[C100]], Folded]
+    if (1 && i) {}              // BRCOV: Branch ([[@LINE]]:14): [True: [[C99:99|1]], False: 1]
+    if (0 || i) {}              // BRCOV: Branch ([[@LINE]]:9): [Folded, False: [[C100]]]
+  }                             // BRCOV: Branch ([[@LINE-1]]:14): [True: [[C99]], False: 1]
 
 }
 
-void early_exits() {
+void early_exits() {            // CHECK: @LINE|{{.*}}early_exits()
   int i = 0;
 
-  if (i) {}
+  if (i) {}                     // BRCOV: Branch ([[@LINE]]:7): [True: 0, False: 1]
 
-  while (i < 100) {
+  while (i < 100) {             // BRCOV: Branch ([[@LINE]]:10): [True: [[C51:51|1]], False: 0]
     i++;
-    if (i > 50)
+    if (i > 50)                 // BRCOV: Branch ([[@LINE]]:9): [True: 1, False: [[C50]]]
       break;
-    if (i % 2)
+    if (i % 2)                  // BRCOV: Branch ([[@LINE]]:9): [True: [[C25:25|1]], False: [[C25]]]
       continue;
   }
 
-  if (i) {}
+  if (i) {}                     // BRCOV: Branch ([[@LINE]]:7): [True: 1, False: 0]
 
   do {
-    if (i > 75)
+    if (i > 75)                 // BRCOV: Branch ([[@LINE]]:9): [True: 1, False: [[C25]]]
       return;
     else
       i++;
-  } while (i < 100);
+  } while (i < 100);            // BRCOV: Branch ([[@LINE]]:12): [True: [[C25]], False: 0]
 
-  if (i) {}
+  if (i) {}                     // BRCOV: Branch ([[@LINE]]:7): [True: 0, False: 0]
 
 }
 
-void jumps() {
+void jumps() {                  // CHECK: @LINE|{{.*}}jumps()
   int i;
 
-  for (i = 0; i < 2; ++i) {
+  for (i = 0; i < 2; ++i) {     // BRCOV: Branch ([[@LINE]]:15): [True: 1, False: 0]
     goto outofloop;
     // Never reached -> no weights
-    if (i) {}
+    if (i) {}                   // BRCOV: Branch ([[@LINE]]:9): [True: 0, False: 0]
   }
 
 outofloop:
-  if (i) {}
+  if (i) {}                     // BRCOV: Branch ([[@LINE]]:7): [True: 0, False: 1]
 
   goto loop1;
 
-  while (i) {
+  while (i) {                   // BRCOV: Branch ([[@LINE]]:10): [True: 0, False: 1]
   loop1:
-    if (i) {}
+    if (i) {}                   // BRCOV: Branch ([[@LINE]]:9): [True: 0, False: 1]
   }
 
   goto loop2;
@@ -80,143 +80,143 @@ void jumps() {
 second:
 third:
   i++;
-  if (i < 3)
+  if (i < 3)                    // BRCOV: Branch ([[@LINE]]:7): [True: [[C2:2|1]], False: 1]
     goto loop2;
 
-  while (i < 3) {
+  while (i < 3) {               // BRCOV: Branch ([[@LINE]]:10): [True: 0, False: 1]
   loop2:
     switch (i) {
-    case 0:
+    case 0:                     // BRCOV: Branch ([[@LINE]]:5): [True: 1, Folded]
       goto first;
-    case 1:
+    case 1:                     // BRCOV: Branch ([[@LINE]]:5): [True: 1, Folded]
       goto second;
-    case 2:
+    case 2:                     // BRCOV: Branch ([[@LINE]]:5): [True: 1, Folded]
       goto third;
     }
   }
 
-  for (i = 0; i < 10; ++i) {
+  for (i = 0; i < 10; ++i) {    // BRCOV: Branch ([[@LINE]]:15): [True: [[C10:10|1]], False: 1]
     goto withinloop;
-    // never reached -> no weights
-    if (i) {}
+                                // never reached -> no weights
+    if (i) {}                   // BRCOV: Branch ([[@LINE]]:9): [True: 0, False: 0]
   withinloop:
-    if (i) {}
+    if (i) {}                   // BRCOV: Branch ([[@LINE]]:9): [True: [[C9:9|1]], False: 1]
   }
 
 }
 
-void switches() {
+void switches() {               // CHECK: @LINE|{{.*}}switches()
   static int weights[] = {1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5};
 
   // No cases -> no weights
   switch (weights[0]) {
-  default:
+  default:                      // BRCOV: Branch ([[@LINE]]:3): [True: 1, Folded]
     break;
   }
-
+                                // BRCOV: Branch ([[@LINE+1]]:63): [True: [[C15:15|1]], False: 0]
   for (int i = 0, len = sizeof(weights) / sizeof(weights[0]); i < len; ++i) {
     switch (i[weights]) {
-    case 1:
-      if (i) {}
+    case 1:                     // BRCOV: Branch ([[@LINE]]:5): [True: 1, Folded]
+      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: 0, False: 1]
       // fallthrough
-    case 2:
-      if (i) {}
+    case 2:                     // BRCOV: Branch ([[@LINE]]:5): [True: [[C2]], Folded]
+      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: [[C2]], False: 1]
       break;
-    case 3:
-      if (i) {}
+    case 3:                     // BRCOV: Branch ([[@LINE]]:5): [True: [[C3:3|1]], Folded]
+      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: [[C3]], False: 0]
       continue;
-    case 4:
-      if (i) {}
+    case 4:                     // BRCOV: Branch ([[@LINE]]:5): [True: [[C4:4|1]], Folded]
+      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: [[C4]], False: 0]
       switch (i) {
-      case 6 ... 9:
-        if (i) {}
+      case 6 ... 9:             // BRCOV: Branch ([[@LINE]]:7): [True: [[C4]], Folded]
+        if (i) {}               // BRCOV: Branch ([[@LINE]]:13): [True: [[C4]], False: 0]
         continue;
       }
 
-    default:
-      if (i == len - 1)
+    default:                    // BRCOV: Branch ([[@LINE]]:5): [True: [[C5:5|1]], Folded]
+      if (i == len - 1)         // BRCOV: Branch ([[@LINE]]:11): [True: 1, False: [[C4]]]
         return;
     }
   }
 
   // Never reached -> no weights
-  if (weights[0]) {}
+  if (weights[0]) {}            // BRCOV: Branch ([[@LINE]]:7): [True: 0, False: 0]
 
 }
 
-void big_switch() {
-  for (int i = 0; i < 32; ++i) {
+void big_switch() {             // CHECK: @LINE|{{.*}}big_switch()
+  for (int i = 0; i < 32; ++i) {// BRCOV: Branch ([[@LINE]]:19): [True: [[C32:32|1]], False: 1]
     switch (1 << i) {
-    case (1 << 0):
-      if (i) {}
+    case (1 << 0):              // BRCOV: Branch ([[@LINE]]:5): [True: 1, Folded]
+      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: 0, False: 1]
       // fallthrough
-    case (1 << 1):
-      if (i) {}
+    case (1 << 1):              // BRCOV: Branch ([[@LINE]]:5): [True: 1, Folded]
+      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: 1, False: 1]
       break;
-    case (1 << 2) ... (1 << 12):
-      if (i) {}
+    case (1 << 2) ... (1 << 12):// BRCOV: Branch ([[@LINE]]:5): [True: [[C11:11|1]], Folded]
+      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: [[C11]], False: 0]
       break;
       // The branch for the large case range above appears after the case body.
 
-    case (1 << 13):
-      if (i) {}
+    case (1 << 13):             // BRCOV: Branch ([[@LINE]]:5): [True: 1, Folded]
+      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: 1, False: 0]
       break;
-    case (1 << 14) ... (1 << 28):
-      if (i) {}
+    case (1 << 14) ... (1 << 28)://BRCOV: Branch ([[@LINE]]:5): [True: [[C15]], Folded]
+      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: [[C15]], False: 0]
       break;
     // The branch for the large case range above appears after the case body.
 
     case (1 << 29) ... ((1 << 29) + 1):
-      if (i) {}
+      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: 1, False: 0]
       break;
-    default:
-      if (i) {}
+    default:                    // BRCOV: Branch ([[@LINE]]:5): [True: [[C2]], Folded]
+      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: [[C2]], False: 0]
       break;
     }
   }
 
 }
 
-void boolean_operators() {
+void boolean_operators() {      // CHECK: @LINE|{{.*}}boolean_operators()
   int v;
   for (int i = 0; i < 100; ++i) {
-    v = i % 3 || i;
-
-    v = i % 3 && i;
-
-    v = i % 3 || i % 2 || i;
-
-    v = i % 2 && i % 3 && i;
-  }
-
-}
-
-void boolop_loops() {
+    v = i % 3 || i;             // BRCOV: Branch ([[@LINE]]:9): [True: [[C66:66|1]], False: [[C34:34|1]]]
+                                // BRCOV: Branch ([[@LINE-1]]:18): [True: [[C33]], False: 1]
+    v = i % 3 && i;             // BRCOV: Branch ([[@LINE]]:9): [True: [[C66]], False: [[C34]]]
+                                // BRCOV: Branch ([[@LINE-1]]:18): [True: [[C66]], False: 0]
+    v = i % 3 || i % 2 || i;    // BRCOV: Branch ([[@LINE]]:9): [True: [[C66]], False: [[C34]]]
+                                // BRCOV: Branch ([[@LINE-1]]:18): [True: [[C17]], False: [[C17]]]
+    v = i % 2 && i % 3 && i;    // BRCOV: Branch ([[@LINE-2]]:27): [True: [[C16]], False: 1]
+  }                             // BRCOV: Branch ([[@LINE-1]]:9): [True: [[C50]], False: [[C50]]]
+                                // BRCOV: Branch ([[@LINE-2]]:18): [True: [[C33]], False: [[C17]]]
+}                               // BRCOV: Branch ([[@LINE-3]]:27): [True: [[C33]], False: 0]
+
+void boolop_loops() {           // CHECK: @LINE|{{.*}}boolop_loops()
   int i = 100;
 
-  while (i && i > 50)
-    i--;
-
-  while ((i % 2) || (i > 0))
-    i--;
-
-  for (i = 100; i && i > 50; --i);
+  while (i && i > 50)           // BRCOV: Branch ([[@LINE]]:10): [True: [[C51]], False: 0]
+    i--;                        // BRCOV: Branch ([[@LINE-1]]:15): [True: [[C50]], False: 1]
 
-  for (; (i % 2) || (i > 0); --i);
+  while ((i % 2) || (i > 0))    // BRCOV: Branch ([[@LINE]]:10): [True: [[C25]], False: [[C26:26|1]]]
+    i--;                        // BRCOV: Branch ([[@LINE-1]]:21): [True: [[C25]], False: 1]
 
+  for (i = 100; i && i > 50; --i);  // BRCOV: Branch ([[@LINE]]:17): [True: [[C51]], False: 0]
+                                    // BRCOV: Branch ([[@LINE-1]]:22): [True: [[C50]], False: 1]
+  for (; (i % 2) || (i > 0); --i);  // BRCOV: Branch ([[@LINE]]:10): [True: [[C25]], False: [[C26]]]
+                                    // BRCOV: Branch ([[@LINE-1]]:21): [True: [[C25]], False: 1]
 }
 
-void conditional_operator() {
+void conditional_operator() {   // CHECK: @LINE|{{.*}}conditional_operator()
   int i = 100;
 
-  int j = i < 50 ? i : 1;
+  int j = i < 50 ? i : 1;       // BRCOV: Branch ([[@LINE]]:11): [True: 0, False: 1]
 
-  int k = i ?: 0;
+  int k = i ?: 0;               // BRCOV: Branch ([[@LINE]]:11): [True: 1, False: 0]
 
 }
 
-void do_fallthrough() {
-  for (int i = 0; i < 10; ++i) {
+void do_fallthrough() {         // CHECK: @LINE|{{.*}}do_fallthrough()
+  for (int i = 0; i < 10; ++i) {// BRCOV: Branch ([[@LINE]]:19): [True: [[C10]], False: 1]
     int j = 0;
     do {
       // The number of exits out of this do-loop via the break statement
@@ -224,12 +224,12 @@ void do_fallthrough() {
       // fallthrough count). Make sure that does not violate any assertions.
       if (i < 8) break;
       j++;
-    } while (j < 2);
+    } while (j < 2);            // BRCOV: Branch ([[@LINE]]:14): [True: [[C2]], False: [[C2]]]
   }
 }
 
-static void static_func() {
-  for (int i = 0; i < 10; ++i) {
+static void static_func() {     // CHECK: @LINE|{{.*}}static_func()
+  for (int i = 0; i < 10; ++i) {// BRCOV: Branch ([[@LINE]]:19): [True: [[C10]], False: 1]
   }
 }
 
@@ -254,7 +254,7 @@ int main(int argc, const char *argv[]) {
   conditional_operator();
   do_fallthrough();
   static_func();
-  extern void __llvm_profile_write_file();
-  __llvm_profile_write_file();
+  (void)0;
+  (void)0;
   return 0;
 }
diff --git a/llvm/test/tools/llvm-cov/Inputs/branch-logical-mixed-single.proftext b/llvm/test/tools/llvm-cov/Inputs/branch-logical-mixed-single.proftext
new file mode 100644
index 0000000000000..f9662438de0e6
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/branch-logical-mixed-single.proftext
@@ -0,0 +1,84 @@
+# Instrument block coverage
+:single_byte_coverage
+_Z4funcii
+# Func Hash:
+8468630735863722633
+# Num Counters:
+67
+# Counter Values:
+4
+0
+0
+0
+0
+2
+0
+2
+2
+3
+2
+0
+0
+0
+0
+0
+0
+1
+0
+1
+1
+3
+3
+3
+3
+3
+3
+1
+2
+0
+3
+0
+0
+0
+1
+0
+1
+0
+3
+3
+3
+3
+4
+1
+0
+2
+1
+0
+0
+3
+0
+2
+0
+2
+0
+0
+4
+4
+4
+0
+4
+1
+3
+4
+3
+1
+4
+
+main
+# Func Hash:
+24
+# Num Counters:
+1
+# Counter Values:
+4
+
diff --git a/llvm/test/tools/llvm-cov/Inputs/branch-logical-mixed-single.yaml b/llvm/test/tools/llvm-cov/Inputs/branch-logical-mixed-single.yaml
new file mode 100644
index 0000000000000..56f3d4955f4d9
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/branch-logical-mixed-single.yaml
@@ -0,0 +1,57 @@
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_X86_64
+  SectionHeaderStringTable: .strtab
+Sections:
+  - Name:            __llvm_covfun
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_GNU_RETAIN ]
+    AddressAlign:    0x8
+    Content:         F0A0ED2C305C0BB32D02000089B21C19C99E86758F2950E06FBD46E8010100600108194302100701000101010C000E01000C010E01000C020E01000C030E01000C040E25010C000E1D010C000E15010C000E0D010C000E05010C000E100101000101010C000E01000C010E01000C020E01000C030E01000C040E4D010C000E45010C000E3D010C000E35010C000E2D010C000E100101000101010C011001000C031001000C051001000C071001000C091001000D000F69010D000F65010C011065000D000F71010D000F61010C011061000D000F79010D000F5D010C01105D000D000F8101010D000F59010C011059000D000F8901010D000F55010C011055000D000F9101010D000F100101000101010C011001000C031001000C051001000C071001000C091001000D000FAD01010D000FA901010C0110A901000D000FB501010D000FA501010C0110A501000D000FBD01010D000FA101010C0110A101000D000FC501010D000F9D01010C01109D01000D000FCD01010D000F9901010C01109901000D000FD501010D000F10010100010101070008DD010009018580808008DD0101050016E1010017028580808008E101020500161001010001E50101030E02E50100070008E9010009018580808008E90101050016ED010017028580808008ED01020500161001010001F10101030902F10100070008F5010009018580808008F50101050016F9010017028580808008F901020500161001010001FD0101030402FD01000700088102000901858080800881020105001685020017028580808008850202050016
+  - Name:            '__llvm_covfun (1)'
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_GNU_RETAIN ]
+    AddressAlign:    0x8
+    Content:         FAD58DE7366495DB0900000018000000000000008F2950E06FBD46E801010001014F010402
+  - Name:            __llvm_covmap
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_GNU_RETAIN ]
+    AddressAlign:    0x8
+    Content:         000000001D0000000000000006000000021A0000186272616E63682D6C6F676963616C2D6D697865642E637070000000
+  - Name:            __llvm_prf_names
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_GNU_RETAIN ]
+    AddressAlign:    0x1
+    Content:         0E005F5A3466756E636969016D61696E
+  - Type:            SectionHeaderTable
+    Sections:
+      - Name:            .strtab
+      - Name:            __llvm_covfun
+      - Name:            '__llvm_covfun (1)'
+      - Name:            __llvm_covmap
+      - Name:            __llvm_prf_names
+      - Name:            .symtab
+Symbols:
+  - Name:            __llvm_covmap
+    Type:            STT_SECTION
+    Section:         __llvm_covmap
+  - Name:            __llvm_prf_names
+    Type:            STT_SECTION
+    Section:         __llvm_prf_names
+  - Name:            __covrec_B30B5C302CEDA0F0u
+    Type:            STT_OBJECT
+    Section:         __llvm_covfun
+    Binding:         STB_WEAK
+    Size:            0x249
+    Other:           [ STV_HIDDEN ]
+  - Name:            __covrec_DB956436E78DD5FAu
+    Type:            STT_OBJECT
+    Section:         '__llvm_covfun (1)'
+    Binding:         STB_WEAK
+    Size:            0x25
+    Other:           [ STV_HIDDEN ]
+...
diff --git a/llvm/test/tools/llvm-cov/Inputs/branch-logical-mixed.cpp b/llvm/test/tools/llvm-cov/Inputs/branch-logical-mixed.cpp
index 0a7d8d8967115..0eaf4c963ef9f 100644
--- a/llvm/test/tools/llvm-cov/Inputs/branch-logical-mixed.cpp
+++ b/llvm/test/tools/llvm-cov/Inputs/branch-logical-mixed.cpp
@@ -4,7 +4,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-
+// CHECK: |{{ +}}[[C4:4|1]]|void func(
 void func(int a, int b) {
   bool b0 = a <= b;
   bool b1 = a == b;
@@ -13,71 +13,71 @@ void func(int a, int b) {
   bool b4 = a > b;
   bool b5 = a != b;
 
-  bool c = b0 &&           // CHECK: Branch ([[@LINE]]:12): [True: 3, False: 1]
-           b1 &&           // CHECK: Branch ([[@LINE]]:12): [True: 2, False: 1]
-           b2 &&           // CHECK: Branch ([[@LINE]]:12): [True: 2, False: 0]
-           b3 &&           // CHECK: Branch ([[@LINE]]:12): [True: 0, False: 2]
-           b4 &&           // CHECK: Branch ([[@LINE]]:12): [True: 0, False: 0]
-           b5;             // CHECK: Branch ([[@LINE]]:12): [True: 0, False: 0]
+  bool c = b0 &&           // BRCOV: Branch ([[@LINE]]:12): [True: [[C3:3|1]], False: 1]
+           b1 &&           // BRCOV: Branch ([[@LINE]]:12): [True: [[C2:2|1]], False: 1]
+           b2 &&           // BRCOV: Branch ([[@LINE]]:12): [True: [[C2]], False: 0]
+           b3 &&           // BRCOV: Branch ([[@LINE]]:12): [True: 0, False: [[C2]]]
+           b4 &&           // BRCOV: Branch ([[@LINE]]:12): [True: 0, False: 0]
+           b5;             // BRCOV: Branch ([[@LINE]]:12): [True: 0, False: 0]
 
-  bool d = b0 ||           // CHECK: Branch ([[@LINE]]:12): [True: 3, False: 1]
-           b1 ||           // CHECK: Branch ([[@LINE]]:12): [True: 0, False: 1]
-           b2 ||           // CHECK: Branch ([[@LINE]]:12): [True: 1, False: 0]
-           b3 ||           // CHECK: Branch ([[@LINE]]:12): [True: 0, False: 0]
-           b4 ||           // CHECK: Branch ([[@LINE]]:12): [True: 0, False: 0]
-           b5;             // CHECK: Branch ([[@LINE]]:12): [True: 0, False: 0]
+  bool d = b0 ||           // BRCOV: Branch ([[@LINE]]:12): [True: [[C3]], False: 1]
+           b1 ||           // BRCOV: Branch ([[@LINE]]:12): [True: 0, False: 1]
+           b2 ||           // BRCOV: Branch ([[@LINE]]:12): [True: 1, False: 0]
+           b3 ||           // BRCOV: Branch ([[@LINE]]:12): [True: 0, False: 0]
+           b4 ||           // BRCOV: Branch ([[@LINE]]:12): [True: 0, False: 0]
+           b5;             // BRCOV: Branch ([[@LINE]]:12): [True: 0, False: 0]
 
-  bool e = (b0  &&         // CHECK: Branch ([[@LINE]]:13): [True: 3, False: 1]
-            b5) ||         // CHECK: Branch ([[@LINE]]:13): [True: 1, False: 2]
-           (b1  &&         // CHECK: Branch ([[@LINE]]:13): [True: 2, False: 1]
-            b4) ||         // CHECK: Branch ([[@LINE]]:13): [True: 0, False: 2]
-           (b2  &&         // CHECK: Branch ([[@LINE]]:13): [True: 3, False: 0]
-            b3) ||         // CHECK: Branch ([[@LINE]]:13): [True: 0, False: 3]
-           (b3  &&         // CHECK: Branch ([[@LINE]]:13): [True: 0, False: 3]
-            b2) ||         // CHECK: Branch ([[@LINE]]:13): [True: 0, False: 0]
-           (b4  &&         // CHECK: Branch ([[@LINE]]:13): [True: 1, False: 2]
-            b1) ||         // CHECK: Branch ([[@LINE]]:13): [True: 0, False: 1]
-           (b5  &&         // CHECK: Branch ([[@LINE]]:13): [True: 1, False: 2]
-            b0);           // CHECK: Branch ([[@LINE]]:13): [True: 0, False: 1]
+  bool e = (b0  &&         // BRCOV: Branch ([[@LINE]]:13): [True: [[C3]], False: 1]
+            b5) ||         // BRCOV: Branch ([[@LINE]]:13): [True: 1, False: [[C2]]]
+           (b1  &&         // BRCOV: Branch ([[@LINE]]:13): [True: [[C2]], False: 1]
+            b4) ||         // BRCOV: Branch ([[@LINE]]:13): [True: 0, False: [[C2]]]
+           (b2  &&         // BRCOV: Branch ([[@LINE]]:13): [True: [[C3]], False: 0]
+            b3) ||         // BRCOV: Branch ([[@LINE]]:13): [True: 0, False: [[C3]]]
+           (b3  &&         // BRCOV: Branch ([[@LINE]]:13): [True: 0, False: [[C3]]]
+            b2) ||         // BRCOV: Branch ([[@LINE]]:13): [True: 0, False: 0]
+           (b4  &&         // BRCOV: Branch ([[@LINE]]:13): [True: 1, False: [[C2]]]
+            b1) ||         // BRCOV: Branch ([[@LINE]]:13): [True: 0, False: 1]
+           (b5  &&         // BRCOV: Branch ([[@LINE]]:13): [True: 1, False: [[C2]]]
+            b0);           // BRCOV: Branch ([[@LINE]]:13): [True: 0, False: 1]
 
-  bool f = (b0  ||         // CHECK: Branch ([[@LINE]]:13): [True: 3, False: 1]
-            b5) &&         // CHECK: Branch ([[@LINE]]:13): [True: 1, False: 0]
-           (b1  ||         // CHECK: Branch ([[@LINE]]:13): [True: 2, False: 2]
-            b4) &&         // CHECK: Branch ([[@LINE]]:13): [True: 1, False: 1]
-           (b2  ||         // CHECK: Branch ([[@LINE]]:13): [True: 3, False: 0]
-            b3) &&         // CHECK: Branch ([[@LINE]]:13): [True: 0, False: 0]
-           (b3  ||         // CHECK: Branch ([[@LINE]]:13): [True: 0, False: 3]
-            b2) &&         // CHECK: Branch ([[@LINE]]:13): [True: 3, False: 0]
-           (b4  ||         // CHECK: Branch ([[@LINE]]:13): [True: 1, False: 2]
-            b1) &&         // CHECK: Branch ([[@LINE]]:13): [True: 2, False: 0]
-           (b5  ||         // CHECK: Branch ([[@LINE]]:13): [True: 1, False: 2]
-            b0);           // CHECK: Branch ([[@LINE]]:13): [True: 2, False: 0]
+  bool f = (b0  ||         // BRCOV: Branch ([[@LINE]]:13): [True: [[C3]], False: 1]
+            b5) &&         // BRCOV: Branch ([[@LINE]]:13): [True: 1, False: 0]
+           (b1  ||         // BRCOV: Branch ([[@LINE]]:13): [True: [[C2]], False: [[C2]]]
+            b4) &&         // BRCOV: Branch ([[@LINE]]:13): [True: 1, False: 1]
+           (b2  ||         // BRCOV: Branch ([[@LINE]]:13): [True: [[C3]], False: 0]
+            b3) &&         // BRCOV: Branch ([[@LINE]]:13): [True: 0, False: 0]
+           (b3  ||         // BRCOV: Branch ([[@LINE]]:13): [True: 0, False: [[C3]]]
+            b2) &&         // BRCOV: Branch ([[@LINE]]:13): [True: [[C3]], False: 0]
+           (b4  ||         // BRCOV: Branch ([[@LINE]]:13): [True: 1, False: [[C2]]]
+            b1) &&         // BRCOV: Branch ([[@LINE]]:13): [True: [[C2]], False: 0]
+           (b5  ||         // BRCOV: Branch ([[@LINE]]:13): [True: 1, False: [[C2]]]
+            b0);           // BRCOV: Branch ([[@LINE]]:13): [True: [[C2]], False: 0]
 
-  if (c)                   // CHECK: Branch ([[@LINE]]:7): [True: 0, False: 4]
+  if (c)                   // BRCOV: Branch ([[@LINE]]:7): [True: 0, False: [[C4]]]
     printf("case0\n");
   else
     printf("case1\n");
 
-  if (d)                   // CHECK: Branch ([[@LINE]]:7): [True: 4, False: 0]
+  if (d)                   // BRCOV: Branch ([[@LINE]]:7): [True: [[C4]], False: 0]
     printf("case2\n");
   else
     printf("case3\n");
 
-  if (e)                   // CHECK: Branch ([[@LINE]]:7): [True: 1, False: 3]
+  if (e)                   // BRCOV: Branch ([[@LINE]]:7): [True: 1, False: [[C3]]]
     printf("case4\n");
   else
     printf("case5\n");
 
-  if (f)                   // CHECK: Branch ([[@LINE]]:7): [True: 3, False: 1]
+  if (f)                   // BRCOV: Branch ([[@LINE]]:7): [True: [[C3]], False: 1]
     printf("case6\n");
   else
     printf("case7\n");
 }
 
-extern "C" { extern void __llvm_profile_write_file(void); }
+
 int main(int argc, char *argv[])
 {
   func(atoi(argv[1]), atoi(argv[2]));
-  __llvm_profile_write_file();
+  (void)0;
   return 0;
 }
diff --git a/llvm/test/tools/llvm-cov/Inputs/branch-macros-single.proftext b/llvm/test/tools/llvm-cov/Inputs/branch-macros-single.proftext
new file mode 100644
index 0000000000000..afb4b1038d3f8
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/branch-macros-single.proftext
@@ -0,0 +1,53 @@
+# Instrument block coverage
+:single_byte_coverage
+_Z4funcii
+# Func Hash:
+456046650042366162
+# Num Counters:
+19
+# Counter Values:
+3
+1
+0
+1
+0
+1
+0
+1
+0
+1
+0
+0
+0
+0
+0
+0
+0
+0
+0
+
+_Z5func2ii
+# Func Hash:
+14151920320560143107
+# Num Counters:
+10
+# Counter Values:
+3
+3
+2
+1
+0
+3
+0
+3
+1
+0
+
+main
+# Func Hash:
+24
+# Num Counters:
+1
+# Counter Values:
+3
+
diff --git a/llvm/test/tools/llvm-cov/Inputs/branch-macros-single.yaml b/llvm/test/tools/llvm-cov/Inputs/branch-macros-single.yaml
new file mode 100644
index 0000000000000..5c5f62b11863b
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/branch-macros-single.yaml
@@ -0,0 +1,69 @@
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_X86_64
+  SectionHeaderStringTable: .strtab
+Sections:
+  - Name:            __llvm_covfun
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_GNU_RETAIN ]
+    AddressAlign:    0x8
+    Content:         F0A0ED2C305C0BB33F010000D238C8100334540693E696313ECE8F5D15010101010101010101010101010101010101010101001501101911020C010C0011140015001A100101005C1C010C0011100101006224010C001210010100682C010C0012100101006E34010C0012100101007401010A000B01000A001001000A001501000A001A45000F00103D00140015350019001A2D001E001F10010104550201050F001701000F00170105060F00170301070F001F3C00100015440019001E014C0910001501540A100016015C0B1000160201050F001701000F0017010D060F00170301070F001F64001000156C0019001E017409100015017C0A1000160201050F001701000F00170115060F00170301070F001F8401001000158C010019001E019401091000150201050F001701000F0017011D060F00170301070F001F9C0100100015A4010019001E0201050F001701000F00170125060F0017
+  - Name:            '__llvm_covfun (1)'
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_GNU_RETAIN ]
+    AddressAlign:    0x8
+    Content:         B01D983FC67363959E000000039B9E2C8DB865C493E696313ECE8F5D0D01010101010101010101010101000401241A07020C010E0014140018001D1001010365011C0B1000160405080F002624001000152C0018001D3400200025013C0A1000160305070F001F44001000154C0019001E0119060F0017011D050F00170154091000150205050F001705000F00170121060F00170401070F001F01000F001F5C00100015640019001E0201050F001701000F0017010D060F0017
+  - Name:            '__llvm_covfun (2)'
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_GNU_RETAIN ]
+    AddressAlign:    0x8
+    Content:         FAD58DE7366495DB09000000180000000000000093E696313ECE8F5D01010001012F010502
+  - Name:            __llvm_covmap
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_GNU_RETAIN ]
+    AddressAlign:    0x8
+    Content:         0000000016000000000000000600000002130000116272616E63682D6D6163726F732E6370700000
+  - Name:            __llvm_prf_names
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_GNU_RETAIN ]
+    AddressAlign:    0x1
+    Content:         19005F5A3466756E636969015F5A3566756E63326969016D61696E
+  - Type:            SectionHeaderTable
+    Sections:
+      - Name:            .strtab
+      - Name:            __llvm_covfun
+      - Name:            '__llvm_covfun (1)'
+      - Name:            '__llvm_covfun (2)'
+      - Name:            __llvm_covmap
+      - Name:            __llvm_prf_names
+      - Name:            .symtab
+Symbols:
+  - Name:            __llvm_covmap
+    Type:            STT_SECTION
+    Section:         __llvm_covmap
+  - Name:            __llvm_prf_names
+    Type:            STT_SECTION
+    Section:         __llvm_prf_names
+  - Name:            __covrec_B30B5C302CEDA0F0u
+    Type:            STT_OBJECT
+    Section:         __llvm_covfun
+    Binding:         STB_WEAK
+    Size:            0x15B
+    Other:           [ STV_HIDDEN ]
+  - Name:            __covrec_956373C63F981DB0u
+    Type:            STT_OBJECT
+    Section:         '__llvm_covfun (1)'
+    Binding:         STB_WEAK
+    Size:            0xBA
+    Other:           [ STV_HIDDEN ]
+  - Name:            __covrec_DB956436E78DD5FAu
+    Type:            STT_OBJECT
+    Section:         '__llvm_covfun (2)'
+    Binding:         STB_WEAK
+    Size:            0x25
+    Other:           [ STV_HIDDEN ]
+...
diff --git a/llvm/test/tools/llvm-cov/Inputs/branch-macros.cpp b/llvm/test/tools/llvm-cov/Inputs/branch-macros.cpp
index 712b2790f774a..e2abe748d86dc 100644
--- a/llvm/test/tools/llvm-cov/Inputs/branch-macros.cpp
+++ b/llvm/test/tools/llvm-cov/Inputs/branch-macros.cpp
@@ -12,41 +12,41 @@
 
 #include <stdlib.h>
 
-
+// CHECK: |{{ +}}[[C3:3|1]]|bool func(
 bool func(int a, int b) {
-  bool c = COND1 && COND2; // CHECK: |  |  |  Branch ([[@LINE-12]]:15): [True: 1, False: 2]
-                           // CHECK: |  |  |  Branch ([[@LINE-12]]:15): [True: 0, False: 1]
-  bool d = COND3;          // CHECK: |  |  |  |  |  Branch ([[@LINE-14]]:15): [True: 1, False: 2]
-                           // CHECK: |  |  |  |  |  Branch ([[@LINE-14]]:15): [True: 0, False: 1]
-  bool e = MACRO1;         // CHECK: |  |  |  |  |  |  |  Branch ([[@LINE-16]]:15): [True: 1, False: 2]
-                           // CHECK: |  |  |  |  |  |  |  Branch ([[@LINE-16]]:15): [True: 0, False: 1]
-  bool f = MACRO2;         // CHECK: |  |  |  |  |  |  |  |  |  Branch ([[@LINE-18]]:15): [True: 1, False: 2]
-                           // CHECK: |  |  |  |  |  |  |  |  |  Branch ([[@LINE-18]]:15): [True: 0, False: 1]
-  bool g = MACRO3;         // CHECK: |  |  |  |  |  |  |  |  |  |  |  Branch ([[@LINE-20]]:15): [True: 1, False: 2]
-                           // CHECK: |  |  |  |  |  |  |  |  |  |  |  Branch ([[@LINE-20]]:15): [True: 0, False: 1]
+  bool c = COND1 && COND2; // BRCOV: |  |  |  Branch ([[@LINE-12]]:15): [True: 1, False: [[C2:2|1]]]
+                           // BRCOV: |  |  |  Branch ([[@LINE-12]]:15): [True: 0, False: 1]
+  bool d = COND3;          // BRCOV: |  |  |  |  |  Branch ([[@LINE-14]]:15): [True: 1, False: [[C2]]]
+                           // BRCOV: |  |  |  |  |  Branch ([[@LINE-14]]:15): [True: 0, False: 1]
+  bool e = MACRO1;         // BRCOV: |  |  |  |  |  |  |  Branch ([[@LINE-16]]:15): [True: 1, False: [[C2]]]
+                           // BRCOV: |  |  |  |  |  |  |  Branch ([[@LINE-16]]:15): [True: 0, False: 1]
+  bool f = MACRO2;         // BRCOV: |  |  |  |  |  |  |  |  |  Branch ([[@LINE-18]]:15): [True: 1, False: [[C2]]]
+                           // BRCOV: |  |  |  |  |  |  |  |  |  Branch ([[@LINE-18]]:15): [True: 0, False: 1]
+  bool g = MACRO3;         // BRCOV: |  |  |  |  |  |  |  |  |  |  |  Branch ([[@LINE-20]]:15): [True: 1, False: [[C2]]]
+                           // BRCOV: |  |  |  |  |  |  |  |  |  |  |  Branch ([[@LINE-20]]:15): [True: 0, False: 1]
   return c && d && e && f && g;
-                           // CHECK: |  Branch ([[@LINE-1]]:10): [True: 0, False: 3]
-                           // CHECK: |  Branch ([[@LINE-2]]:15): [True: 0, False: 0]
-                           // CHECK: |  Branch ([[@LINE-3]]:20): [True: 0, False: 0]
-                           // CHECK: |  Branch ([[@LINE-4]]:25): [True: 0, False: 0]
-                           // CHECK: |  Branch ([[@LINE-5]]:30): [True: 0, False: 0]
+                           // BRCOV: |  Branch ([[@LINE-1]]:10): [True: 0, False: [[C3]]]
+                           // BRCOV: |  Branch ([[@LINE-2]]:15): [True: 0, False: 0]
+                           // BRCOV: |  Branch ([[@LINE-3]]:20): [True: 0, False: 0]
+                           // BRCOV: |  Branch ([[@LINE-4]]:25): [True: 0, False: 0]
+                           // BRCOV: |  Branch ([[@LINE-5]]:30): [True: 0, False: 0]
 }
 
 
 bool func2(int a, int b) {
-    bool h = MACRO3 || COND4;  // CHECK: |  |  |  |  |  |  |  |  |  |  |  Branch ([[@LINE-32]]:15): [True: 1, False: 2]
-                               // CHECK: |  |  |  |  |  |  |  |  |  |  |  Branch ([[@LINE-32]]:15): [True: 0, False: 1]
-                               // CHECK: |  |  |  |  |  |  |  Branch ([[@LINE-34]]:15): [True: 1, False: 2]
-                               // CHECK: |  |  |  |  |  |  |  Branch ([[@LINE-34]]:15): [True: 0, False: 1]
-                               // CHECK: |  |  |  Branch ([[@LINE-33]]:15): [True: 1, False: 2]
+    bool h = MACRO3 || COND4;  // BRCOV: |  |  |  |  |  |  |  |  |  |  |  Branch ([[@LINE-32]]:15): [True: 1, False: [[C2]]]
+                               // BRCOV: |  |  |  |  |  |  |  |  |  |  |  Branch ([[@LINE-32]]:15): [True: 0, False: 1]
+                               // BRCOV: |  |  |  |  |  |  |  Branch ([[@LINE-34]]:15): [True: 1, False: [[C2]]]
+                               // BRCOV: |  |  |  |  |  |  |  Branch ([[@LINE-34]]:15): [True: 0, False: 1]
+                               // BRCOV: |  |  |  Branch ([[@LINE-33]]:15): [True: 1, False: [[C2]]]
   return h;
 }
 
-extern "C" { extern void __llvm_profile_write_file(void); }
+
 int main(int argc, char *argv[])
 {
   func(atoi(argv[1]), atoi(argv[2]));
   func2(atoi(argv[1]), atoi(argv[2]));
-  __llvm_profile_write_file();
+  (void)0;
   return 0;
 }
diff --git a/llvm/test/tools/llvm-cov/Inputs/branch-showBranchPercentage.c b/llvm/test/tools/llvm-cov/Inputs/branch-showBranchPercentage.c
index c41739ff0b22f..6db980a8bd64a 100644
--- a/llvm/test/tools/llvm-cov/Inputs/branch-showBranchPercentage.c
+++ b/llvm/test/tools/llvm-cov/Inputs/branch-showBranchPercentage.c
@@ -13,7 +13,7 @@ int main(int argc, char *argv[])
   int i = 0;
   if (argc < 3)                       // CHECK: Branch ([[@LINE]]:7): [True: 16.67%, False: 83.33%]
   {
-    __llvm_profile_write_file();
+    (void)0;
     return 0;
   }
 
@@ -52,7 +52,7 @@ int main(int argc, char *argv[])
     printf("loop\n");
   } while (i++ < 10);                 // CHECK: Branch ([[@LINE]]:12): [True: 90.91%, False: 9.09%]
 
-  __llvm_profile_write_file();
+  (void)b;
 
-  return b;
+  return 0;
 }
diff --git a/llvm/test/tools/llvm-cov/Inputs/branch-templates-single.proftext b/llvm/test/tools/llvm-cov/Inputs/branch-templates-single.proftext
new file mode 100644
index 0000000000000..829431334478f
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/branch-templates-single.proftext
@@ -0,0 +1,49 @@
+# Instrument block coverage
+:single_byte_coverage
+_Z4funcIbEiT_
+# Func Hash:
+11045778961
+# Num Counters:
+4
+# Counter Values:
+1
+1
+0
+0
+
+_Z4funcIfEiT_
+# Func Hash:
+11045778961
+# Num Counters:
+4
+# Counter Values:
+1
+0
+1
+0
+
+_Z4funcIiEiT_
+# Func Hash:
+11045778961
+# Num Counters:
+4
+# Counter Values:
+1
+0
+1
+0
+
+main
+# Func Hash:
+185286008276329560
+# Num Counters:
+7
+# Counter Values:
+1
+1
+1
+0
+1
+1
+1
+
diff --git a/llvm/test/tools/llvm-cov/Inputs/branch-templates-single.yaml b/llvm/test/tools/llvm-cov/Inputs/branch-templates-single.yaml
new file mode 100644
index 0000000000000..d4ede6db448e6
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/branch-templates-single.yaml
@@ -0,0 +1,81 @@
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_X86_64
+  SectionHeaderStringTable: .strtab
+Sections:
+  - Name:            __llvm_covfun
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_GNU_RETAIN ]
+    AddressAlign:    0x8
+    Content:         FAD58DE7366495DB5100000058242991A444920226ED9A40DAABBC6B0101000D011D0C090201010700130500140185808080080501050016090103060209000700170D00180185808080080D01050016110103040211000700171500180185808080081501050016190103010B
+  - Name:            '__llvm_covfun (1)'
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_GNU_RETAIN ]
+    AddressAlign:    0x8
+    Content:         5427717259E0E43E38000000113661920200000026ED9A40DAABBC6B01010008010D0F06020101060007050008018580808008050105000D09000E028580808008090205000D0D000E0183808080080D01030102
+  - Name:            '__llvm_covfun (2)'
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_GNU_RETAIN ]
+    AddressAlign:    0x8
+    Content:         4B7E22082F0551AA38000000113661920200000026ED9A40DAABBC6B01010008010D0F06020101060007050008018580808008050105000D09000E028580808008090205000D0D000E0183808080080D01030102
+  - Name:            '__llvm_covfun (3)'
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_GNU_RETAIN ]
+    AddressAlign:    0x8
+    Content:         AC1440BC3DA3E41A38000000113661920200000026ED9A40DAABBC6B01010008010D0F06020101060007050008018580808008050105000D09000E028580808008090205000D0D000E0183808080080D01030102
+  - Name:            __llvm_covmap
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_GNU_RETAIN ]
+    AddressAlign:    0x8
+    Content:         0000000019000000000000000600000002160000146272616E63682D74656D706C617465732E637070000000
+  - Name:            __llvm_prf_names
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_GNU_RETAIN ]
+    AddressAlign:    0x1
+    Content:         2E006D61696E015F5A3466756E6349694569545F015F5A3466756E6349624569545F015F5A3466756E6349664569545F
+  - Type:            SectionHeaderTable
+    Sections:
+      - Name:            .strtab
+      - Name:            __llvm_covfun
+      - Name:            '__llvm_covfun (1)'
+      - Name:            '__llvm_covfun (2)'
+      - Name:            '__llvm_covfun (3)'
+      - Name:            __llvm_covmap
+      - Name:            __llvm_prf_names
+      - Name:            .symtab
+Symbols:
+  - Name:            __llvm_covmap
+    Type:            STT_SECTION
+    Section:         __llvm_covmap
+  - Name:            __llvm_prf_names
+    Type:            STT_SECTION
+    Section:         __llvm_prf_names
+  - Name:            __covrec_DB956436E78DD5FAu
+    Type:            STT_OBJECT
+    Section:         __llvm_covfun
+    Binding:         STB_WEAK
+    Size:            0x6D
+    Other:           [ STV_HIDDEN ]
+  - Name:            __covrec_3EE4E05972712754u
+    Type:            STT_OBJECT
+    Section:         '__llvm_covfun (1)'
+    Binding:         STB_WEAK
+    Size:            0x54
+    Other:           [ STV_HIDDEN ]
+  - Name:            __covrec_AA51052F08227E4Bu
+    Type:            STT_OBJECT
+    Section:         '__llvm_covfun (2)'
+    Binding:         STB_WEAK
+    Size:            0x54
+    Other:           [ STV_HIDDEN ]
+  - Name:            __covrec_1AE4A33DBC4014ACu
+    Type:            STT_OBJECT
+    Section:         '__llvm_covfun (3)'
+    Binding:         STB_WEAK
+    Size:            0x54
+    Other:           [ STV_HIDDEN ]
+...
diff --git a/llvm/test/tools/llvm-cov/Inputs/branch-templates.cpp b/llvm/test/tools/llvm-cov/Inputs/branch-templates.cpp
index 0795a5346380d..4d932eaf5944a 100644
--- a/llvm/test/tools/llvm-cov/Inputs/branch-templates.cpp
+++ b/llvm/test/tools/llvm-cov/Inputs/branch-templates.cpp
@@ -11,28 +11,28 @@ void unused(T x) {
 
 template<typename T>
 int func(T x) {
-  if(x)       // CHECK: |  Branch ([[@LINE]]:6): [True: 0, False: 1]
-    return 0; // CHECK: |  Branch ([[@LINE-1]]:6): [True: 1, False: 0]
-  else        // CHECK: |  Branch ([[@LINE-2]]:6): [True: 0, False: 1]
+  if(x)       // BRCOV: |  Branch ([[@LINE]]:6): [True: 0, False: 1]
+    return 0; // BRCOV: |  Branch ([[@LINE-1]]:6): [True: 1, False: 0]
+  else        // BRCOV: |  Branch ([[@LINE-2]]:6): [True: 0, False: 1]
     return 1;
   int j = 1;
 }
 
               // CHECK-LABEL: _Z4funcIiEiT_:
-              // CHECK: |  |  Branch ([[@LINE-8]]:6): [True: 0, False: 1]
+              // BRCOV: |  |  Branch ([[@LINE-8]]:6): [True: 0, False: 1]
               // CHECK-LABEL: _Z4funcIbEiT_:
-              // CHECK: |  |  Branch ([[@LINE-10]]:6): [True: 1, False: 0]
+              // BRCOV: |  |  Branch ([[@LINE-10]]:6): [True: 1, False: 0]
               // CHECK-LABEL: _Z4funcIfEiT_:
-              // CHECK: |  |  Branch ([[@LINE-12]]:6): [True: 0, False: 1]
+              // BRCOV: |  |  Branch ([[@LINE-12]]:6): [True: 0, False: 1]
+
 
-extern "C" { extern void __llvm_profile_write_file(void); }
 int main() {
-  if (func<int>(0))      // CHECK: |  Branch ([[@LINE]]:7): [True: 1, False: 0]
+  if (func<int>(0))      // BRCOV: |  Branch ([[@LINE]]:7): [True: 1, False: 0]
     printf("case1\n");
-  if (func<bool>(true))  // CHECK: |  Branch ([[@LINE]]:7): [True: 0, False: 1]
+  if (func<bool>(true))  // BRCOV: |  Branch ([[@LINE]]:7): [True: 0, False: 1]
     printf("case2\n");
-  if (func<float>(0.0))  // CHECK: |  Branch ([[@LINE]]:7): [True: 1, False: 0]
+  if (func<float>(0.0))  // BRCOV: |  Branch ([[@LINE]]:7): [True: 1, False: 0]
     printf("case3\n");
-  __llvm_profile_write_file();
+  (void)0;
   return 0;
 }
diff --git a/llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts-single.proftext b/llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts-single.proftext
new file mode 100644
index 0000000000000..1b7b949de4962
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts-single.proftext
@@ -0,0 +1,23 @@
+# Instrument block coverage
+:single_byte_coverage
+main
+# Func Hash:
+15239891155360101223
+# Num Counters:
+14
+# Counter Values:
+161
+0
+161
+161
+161
+161
+161
+161
+161
+161
+0
+161
+0
+161
+
diff --git a/llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts-single.yaml b/llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts-single.yaml
new file mode 100644
index 0000000000000..84b184023f082
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts-single.yaml
@@ -0,0 +1,45 @@
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_X86_64
+  SectionHeaderStringTable: .strtab
+Sections:
+  - Name:            __llvm_covfun
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_GNU_RETAIN ]
+    AddressAlign:    0x8
+    Content:         FAD58DE7366495DB9A0000006733DBEA42F87ED3C60E0B951FF3509D0101001A01060C130210020100010101070008050009008A8080800805000A0204090204008A8080800809000A020410030100010D01030A02110013001A15001C001F19002000A180808008190021020410030100011D010306021D0007000D25000F0090808080082500100015290018001D2101030502210007000D31000F018980808008310109000E350109000E10010100012D0103000B
+  - Name:            __llvm_covmap
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_GNU_RETAIN ]
+    AddressAlign:    0x8
+    Content:         00000000200000000000000006000000021D00001B73686F774C696E65457865637574696F6E436F756E74732E637070
+  - Name:            __llvm_prf_names
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_GNU_RETAIN ]
+    AddressAlign:    0x1
+    Content:         04006D61696E
+  - Type:            SectionHeaderTable
+    Sections:
+      - Name:            .strtab
+      - Name:            __llvm_covfun
+      - Name:            __llvm_covmap
+      - Name:            __llvm_prf_names
+      - Name:            .symtab
+Symbols:
+  - Name:            __llvm_covmap
+    Type:            STT_SECTION
+    Section:         __llvm_covmap
+  - Name:            __llvm_prf_names
+    Type:            STT_SECTION
+    Section:         __llvm_prf_names
+  - Name:            __covrec_DB956436E78DD5FAu
+    Type:            STT_OBJECT
+    Section:         __llvm_covfun
+    Binding:         STB_WEAK
+    Size:            0xB6
+    Other:           [ STV_HIDDEN ]
+...
diff --git a/llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts.cpp b/llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts.cpp
index c7e8c8fb0c75e..b14409f173849 100644
--- a/llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts.cpp
+++ b/llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts.cpp
@@ -3,26 +3,26 @@
 // before any coverage              // WHOLE-FILE: [[@LINE]]|      |// before
                                     // FILTER-NOT: [[@LINE-1]]|    |// before
 // HTML: <td class='line-number'><a name='L[[@LINE+1]]' href='#L[[@LINE+1]]'><pre>[[@LINE+1]]</pre></a></td><td class='covered-line'><pre>161</pre></td><td class='code'><pre>int main() {
-int main() {                              // TEXT: [[@LINE]]|   161|int main(
-  int x = 0;                              // TEXT: [[@LINE]]|   161|  int x
-                                          // TEXT: [[@LINE]]|   161|
-  if (x) {                                // TEXT: [[@LINE]]|   161|  if (x)
-    x = 0;                                // TEXT: [[@LINE]]|     0|    x = 0
-  } else {                                // TEXT: [[@LINE]]|   161|  } else
-    x = 1;                                // TEXT: [[@LINE]]|   161|    x = 1
-  }                                       // TEXT: [[@LINE]]|   161|  }
-                                          // TEXT: [[@LINE]]|   161|
-  for (int i = 0; i < 100; ++i) {         // TEXT: [[@LINE]]| 16.2k|  for (
-    x = 1;                                // TEXT: [[@LINE]]| 16.1k|    x = 1
-  }                                       // TEXT: [[@LINE]]| 16.1k|  }
-                                          // TEXT: [[@LINE]]|   161|
-  x = x < 10 ? x + 1 : x - 1;             // TEXT: [[@LINE]]|   161|  x =
-  x = x > 10 ?                            // TEXT: [[@LINE]]|   161|  x =
-        x - 1:                            // TEXT: [[@LINE]]|     0|        x
-        x + 1;                            // TEXT: [[@LINE]]|   161|        x
-                                          // TEXT: [[@LINE]]|   161|
-  return 0;                               // TEXT: [[@LINE]]|   161|  return
-}                                         // TEXT: [[@LINE]]|   161|}
+int main() {                              // TEXT: [[@LINE]]|     [[C161:161|1]]|int main(
+  int x = 0;                              // TEXT: [[@LINE]]|           [[C161]]|  int x
+
+  if (x) {                                // TEXT: [[@LINE]]|           [[C161]]|  if (x)
+    x = 0;                                // TEXT: [[@LINE]]|                  0|    x = 0
+  } else {                                // TEXT: [[@LINE]]|           [[C161]]|  } else
+    x = 1;                                // TEXT: [[@LINE]]|           [[C161]]|    x = 1
+  }                                       // TEXT: [[@LINE]]|           [[C161]]|  }
+
+  for (int i = 0; i < 100; ++i) {         // TEXT: [[@LINE]]| [[C16K2:16\.2k|161]]|  for (
+    x = 1;                                // TEXT: [[@LINE]]| [[C16K1:16\.1k|161]]|    x = 1
+  }                                       // TEXT: [[@LINE]]|          [[C16K1]]|  }
+
+  x = x < 10 ? x + 1 : x - 1;             // TEXT: [[@LINE]]|           [[C161]]|  x =
+  x = x > 10 ?                            // TEXT: [[@LINE]]|           [[C161]]|  x =
+        x - 1:                            // TEXT: [[@LINE]]|                  0|        x
+        x + 1;                            // TEXT: [[@LINE]]|           [[C161]]|        x
+
+  return 0;                               // TEXT: [[@LINE]]|           [[C161]]|  return
+}                                         // TEXT: [[@LINE]]|           [[C161]]|}
 // after coverage                   // WHOLE-FILE: [[@LINE]]|      |// after
                                     // FILTER-NOT: [[@LINE-1]]|    |// after
 // HTML-WHOLE-FILE: <td class='line-number'><a name='L[[@LINE-2]]' href='#L[[@LINE-2]]'><pre>[[@LINE-2]]</pre></a></td><td class='skipped-line'></td><td class='code'><pre>// after
diff --git a/llvm/test/tools/llvm-cov/branch-c-general.test b/llvm/test/tools/llvm-cov/branch-c-general.test
index 865a2662460e8..3d0b7ee563222 100644
--- a/llvm/test/tools/llvm-cov/branch-c-general.test
+++ b/llvm/test/tools/llvm-cov/branch-c-general.test
@@ -164,3 +164,7 @@
 // HTML-INDEX: 79.07% (136/172)
 // HTML-INDEX: <tr class='light-row-bold'>
 // HTML-INDEX: Totals
+
+// RUN: yaml2obj %S/Inputs/branch-c-general-single.yaml -o %t.o
+// RUN: llvm-profdata merge %S/Inputs/branch-c-general-single.proftext -o %t.profdata
+// RUN: llvm-cov show --show-branches=count %t.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs %S/Inputs/branch-c-general.c | FileCheck %S/Inputs/branch-c-general.c
diff --git a/llvm/test/tools/llvm-cov/branch-logical-mixed.test b/llvm/test/tools/llvm-cov/branch-logical-mixed.test
index a07d2357f2c34..b03cabeb01855 100644
--- a/llvm/test/tools/llvm-cov/branch-logical-mixed.test
+++ b/llvm/test/tools/llvm-cov/branch-logical-mixed.test
@@ -1,8 +1,14 @@
 // RUN: llvm-profdata merge %S/Inputs/branch-logical-mixed.proftext -o %t.profdata
-// RUN: llvm-cov show --show-branches=count %S/Inputs/branch-logical-mixed.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs | FileCheck %S/Inputs/branch-logical-mixed.cpp
+// RUN: llvm-cov show --show-branches=count %S/Inputs/branch-logical-mixed.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs | FileCheck %S/Inputs/branch-logical-mixed.cpp -check-prefixes=CHECK,BRCOV
 // RUN: llvm-cov report --show-branch-summary %S/Inputs/branch-logical-mixed.o32l -instr-profile %t.profdata -show-functions -path-equivalence=/tmp,%S/Inputs %S/Inputs/branch-logical-mixed.cpp
 | FileCheck %s -check-prefix=REPORT
 
+// RUN: yaml2obj %S/Inputs/branch-logical-mixed-single.yaml -o %t.o
+// RUN: llvm-profdata merge %S/Inputs/branch-logical-mixed-single.proftext -o %t.profdata
+// RUN: llvm-cov show --show-branches=count %t.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck %S/Inputs/branch-logical-mixed.cpp
+// RUN: llvm-cov report --show-branch-summary %t.o -instr-profile %t.profdata -show-functions -path-equivalence=.,%S/Inputs %S/Inputs/branch-logical-mixed.cpp
+| FileCheck %s -check-prefix=REPORT
+
 // REPORT:      Name                        Regions    Miss   Cover     Lines    Miss   Cover  Branches    Miss   Cover
 // REPORT-NEXT: ---
 // REPORT-NEXT: _Z4funcii                        77      15  80.52%        60       2  96.67%        80      30  62.50%
diff --git a/llvm/test/tools/llvm-cov/branch-macros.test b/llvm/test/tools/llvm-cov/branch-macros.test
index fbe7694b4f4e0..a4790afc53422 100644
--- a/llvm/test/tools/llvm-cov/branch-macros.test
+++ b/llvm/test/tools/llvm-cov/branch-macros.test
@@ -1,7 +1,11 @@
 // RUN: llvm-profdata merge %S/Inputs/branch-macros.proftext -o %t.profdata
-// RUN: llvm-cov show --show-expansions --show-branches=count %S/Inputs/branch-macros.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs | FileCheck %S/Inputs/branch-macros.cpp
+// RUN: llvm-cov show --show-expansions --show-branches=count %S/Inputs/branch-macros.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs | FileCheck %S/Inputs/branch-macros.cpp -check-prefixes=CHECK,BRCOV
 // RUN: llvm-cov report --show-branch-summary %S/Inputs/branch-macros.o32l -instr-profile %t.profdata -show-functions -path-equivalence=/tmp,%S/Inputs %S/Inputs/branch-macros.cpp | FileCheck %s -check-prefix=REPORT
 
+// RUN: yaml2obj %S/Inputs/branch-macros-single.yaml -o %t.o
+// RUN: llvm-profdata merge %S/Inputs/branch-macros-single.proftext -o %t.profdata
+// RUN: llvm-cov show --show-expansions --show-branches=count %t.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck %S/Inputs/branch-macros.cpp
+
 // REPORT:      Name                        Regions    Miss   Cover     Lines    Miss   Cover  Branches    Miss   Cover
 // REPORT-NEXT: ---
 // REPORT-NEXT: _Z4funcii                        28       4  85.71%        18       0 100.00%        30      14  53.33%
diff --git a/llvm/test/tools/llvm-cov/branch-templates.test b/llvm/test/tools/llvm-cov/branch-templates.test
index 74aef16050228..d5535022239f5 100644
--- a/llvm/test/tools/llvm-cov/branch-templates.test
+++ b/llvm/test/tools/llvm-cov/branch-templates.test
@@ -3,6 +3,10 @@
 // RUN: llvm-cov report --show-branch-summary %S/Inputs/branch-templates.o32l -instr-profile %t.profdata -show-functions -path-equivalence=/tmp,%S/Inputs %S/Inputs/branch-templates.cpp | FileCheck %s -check-prefix=REPORT
 // RUN: llvm-cov report --show-branch-summary %S/Inputs/branch-templates.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs | FileCheck %s -check-prefix=REPORTFILE
 
+// RUN: yaml2obj %S/Inputs/branch-templates-single.yaml -o %t.o
+// RUN: llvm-profdata merge %S/Inputs/branch-templates-single.proftext -o %t.profdata
+// RUN: llvm-cov show --show-expansions --show-branches=count %t.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck %S/Inputs/branch-templates.cpp
+
 // REPORT:      Name                        Regions    Miss   Cover     Lines    Miss   Cover  Branches    Miss   Cover
 // REPORT-NEXT: ---
 // REPORT-NEXT: main                              7       1  85.71%        10       1  90.00%         6       3  50.00%
diff --git a/llvm/test/tools/llvm-cov/showLineExecutionCounts.test b/llvm/test/tools/llvm-cov/showLineExecutionCounts.test
index 997b16a0b8e94..2c0669a7cec42 100644
--- a/llvm/test/tools/llvm-cov/showLineExecutionCounts.test
+++ b/llvm/test/tools/llvm-cov/showLineExecutionCounts.test
@@ -41,3 +41,10 @@
 // HTML-INDEX: 72.73% (8/11)
 // HTML-INDEX: <tr class='light-row-bold'>
 // HTML-INDEX: Totals
+
+// Single byte
+// RUN: yaml2obj %S/Inputs/showLineExecutionCounts-single.yaml -o %t.o
+// RUN: llvm-profdata merge %S/Inputs/showLineExecutionCounts-single.proftext -o %t.profdata
+
+// RUN: llvm-cov show %t.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck -check-prefixes=TEXT,WHOLE-FILE %S/Inputs/showLineExecutionCounts.cpp
+// RUN: llvm-cov show %t.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs -name=main | FileCheck -check-prefixes=TEXT,FILTER %S/Inputs/showLineExecutionCounts.cpp

>From 5fc3408628a72560490c5271de171a636f5be50a Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Wed, 20 Nov 2024 23:46:58 +0900
Subject: [PATCH 21/72] Fix a test to fix linecount=1

---
 llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts.cpp b/llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts.cpp
index b14409f173849..b63247341a28e 100644
--- a/llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts.cpp
+++ b/llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts.cpp
@@ -12,8 +12,8 @@ int main() {                              // TEXT: [[@LINE]]|     [[C161:161|1]]
     x = 1;                                // TEXT: [[@LINE]]|           [[C161]]|    x = 1
   }                                       // TEXT: [[@LINE]]|           [[C161]]|  }
 
-  for (int i = 0; i < 100; ++i) {         // TEXT: [[@LINE]]| [[C16K2:16\.2k|161]]|  for (
-    x = 1;                                // TEXT: [[@LINE]]| [[C16K1:16\.1k|161]]|    x = 1
+  for (int i = 0; i < 100; ++i) {         // TEXT: [[@LINE]]| [[C16K2:16\.2k|1]]|  for (
+    x = 1;                                // TEXT: [[@LINE]]| [[C16K1:16\.1k|1]]|    x = 1
   }                                       // TEXT: [[@LINE]]|          [[C16K1]]|  }
 
   x = x < 10 ? x + 1 : x - 1;             // TEXT: [[@LINE]]|           [[C161]]|  x =

>From eb7fff9a3b8356851770d1b5c6a4f0a69a79af05 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Thu, 21 Nov 2024 07:57:37 +0900
Subject: [PATCH 22/72] threads.c: Fixup on the clean testdir

---
 llvm/test/tools/llvm-cov/threads.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/llvm/test/tools/llvm-cov/threads.c b/llvm/test/tools/llvm-cov/threads.c
index b162b6ac5a801..73dd82c3a7464 100644
--- a/llvm/test/tools/llvm-cov/threads.c
+++ b/llvm/test/tools/llvm-cov/threads.c
@@ -1,9 +1,10 @@
 // Coverage/profile data recycled from the showLineExecutionCounts.cpp test.
 //
+// RUN: rm -rf %t*.dir
 // RUN: llvm-profdata merge %S/Inputs/lineExecutionCounts.proftext -o %t.profdata
-// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -j 1 -o %t1.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S %S/showLineExecutionCounts.cpp
-// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -num-threads 2 -o %t2.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S %S/showLineExecutionCounts.cpp
-// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -o %t3.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S %S/showLineExecutionCounts.cpp
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -j 1 -o %t1.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -num-threads 2 -o %t2.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -o %t3.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs
 //
 // RUN: diff %t1.dir/index.txt %t2.dir/index.txt
 // RUN: diff %t1.dir/coverage/tmp/showLineExecutionCounts.cpp.txt %t2.dir/coverage/tmp/showLineExecutionCounts.cpp.txt

>From 75430950a1a347f4a1c3d9dc0804afe9a3f25aaa Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Thu, 21 Nov 2024 23:20:19 +0900
Subject: [PATCH 23/72] Rename threads.c to threads.test since it is no longer
 C source file.

---
 llvm/test/tools/llvm-cov/{threads.c => threads.test} | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename llvm/test/tools/llvm-cov/{threads.c => threads.test} (100%)

diff --git a/llvm/test/tools/llvm-cov/threads.c b/llvm/test/tools/llvm-cov/threads.test
similarity index 100%
rename from llvm/test/tools/llvm-cov/threads.c
rename to llvm/test/tools/llvm-cov/threads.test

>From 00ac90d232a5793a94f6863dcba2274f4e0126cb Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Thu, 21 Nov 2024 23:25:06 +0900
Subject: [PATCH 24/72] llvm/test/tools/llvm-cov/Inputs: Avoid wildcards `rm
 -rf %t*.dir`

---
 .../llvm-cov/showLineExecutionCounts.test     | 22 +++++++++----------
 llvm/test/tools/llvm-cov/threads.test         | 16 +++++++-------
 2 files changed, 19 insertions(+), 19 deletions(-)

diff --git a/llvm/test/tools/llvm-cov/showLineExecutionCounts.test b/llvm/test/tools/llvm-cov/showLineExecutionCounts.test
index 2c0669a7cec42..1c1e894922827 100644
--- a/llvm/test/tools/llvm-cov/showLineExecutionCounts.test
+++ b/llvm/test/tools/llvm-cov/showLineExecutionCounts.test
@@ -1,32 +1,32 @@
 // Basic handling of line counts.
-// RUN: rm -rf %t*.dir
+// RUN: rm -rf %t.dir
 // RUN: llvm-profdata merge %S/Inputs/lineExecutionCounts.proftext -o %t.profdata
 
 // RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs | FileCheck -check-prefixes=TEXT,WHOLE-FILE %S/Inputs/showLineExecutionCounts.cpp
 // RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs -name=main | FileCheck -check-prefixes=TEXT,FILTER %S/Inputs/showLineExecutionCounts.cpp
 
 // Test -output-dir.
-// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -o %t.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs
-// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -output-dir %t.filtered.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs -name=main
-// RUN: FileCheck -check-prefixes=TEXT,WHOLE-FILE -input-file %t.dir/coverage/tmp/showLineExecutionCounts.cpp.txt %S/Inputs/showLineExecutionCounts.cpp
-// RUN: FileCheck -check-prefixes=TEXT,FILTER -input-file %t.filtered.dir/coverage/tmp/showLineExecutionCounts.cpp.txt %S/Inputs/showLineExecutionCounts.cpp
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -o %t.dir/show -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -output-dir %t.dir/show.filtered -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs -name=main
+// RUN: FileCheck -check-prefixes=TEXT,WHOLE-FILE -input-file %t.dir/show/coverage/tmp/showLineExecutionCounts.cpp.txt %S/Inputs/showLineExecutionCounts.cpp
+// RUN: FileCheck -check-prefixes=TEXT,FILTER -input-file %t.dir/show.filtered/coverage/tmp/showLineExecutionCounts.cpp.txt %S/Inputs/showLineExecutionCounts.cpp
 //
 // RUN: llvm-cov export %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata 2>/dev/null -summary-only > %t.export-summary.json
 // RUN: not grep '"name":"main"' %t.export-summary.json
 //
 // Test html output.
-// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -format html -o %t.html.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs
-// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -format html -o %t.html.filtered.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs -name=main
-// RUN: FileCheck -check-prefixes=HTML,HTML-WHOLE-FILE -input-file %t.html.dir/coverage/tmp/showLineExecutionCounts.cpp.html %S/Inputs/showLineExecutionCounts.cpp
-// RUN: FileCheck -check-prefixes=HTML,HTML-FILTER -input-file %t.html.filtered.dir/coverage/tmp/showLineExecutionCounts.cpp.html %S/Inputs/showLineExecutionCounts.cpp
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -format html -o %t.dir/html -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -format html -o %t.dir/html.filtered -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs -name=main
+// RUN: FileCheck -check-prefixes=HTML,HTML-WHOLE-FILE -input-file %t.dir/html/coverage/tmp/showLineExecutionCounts.cpp.html %S/Inputs/showLineExecutionCounts.cpp
+// RUN: FileCheck -check-prefixes=HTML,HTML-FILTER -input-file %t.dir/html.filtered/coverage/tmp/showLineExecutionCounts.cpp.html %S/Inputs/showLineExecutionCounts.cpp
 //
 // Test index creation.
-// RUN: FileCheck -check-prefix=TEXT-INDEX -input-file %t.dir/index.txt %s
+// RUN: FileCheck -check-prefix=TEXT-INDEX -input-file %t.dir/show/index.txt %s
 // TEXT-INDEX: Filename
 // TEXT-INDEX-NEXT: ---
 // TEXT-INDEX-NEXT: {{.*}}showLineExecutionCounts.cpp
 //
-// RUN: FileCheck -check-prefix HTML-INDEX -input-file %t.html.dir/index.html %s
+// RUN: FileCheck -check-prefix HTML-INDEX -input-file %t.dir/html/index.html %s
 // HTML-INDEX-LABEL: <table>
 // HTML-INDEX: <td class='column-entry-bold'>Filename</td>
 // HTML-INDEX: <td class='column-entry-bold'>Function Coverage</td>
diff --git a/llvm/test/tools/llvm-cov/threads.test b/llvm/test/tools/llvm-cov/threads.test
index 73dd82c3a7464..a51406ca14efa 100644
--- a/llvm/test/tools/llvm-cov/threads.test
+++ b/llvm/test/tools/llvm-cov/threads.test
@@ -1,12 +1,12 @@
 // Coverage/profile data recycled from the showLineExecutionCounts.cpp test.
 //
-// RUN: rm -rf %t*.dir
+// RUN: rm -rf %t.dir
 // RUN: llvm-profdata merge %S/Inputs/lineExecutionCounts.proftext -o %t.profdata
-// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -j 1 -o %t1.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs
-// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -num-threads 2 -o %t2.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs
-// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -o %t3.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -j 1 -o %t.dir/1 -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -num-threads 2 -o %t.dir/2 -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -o %t.dir/3 -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs
 //
-// RUN: diff %t1.dir/index.txt %t2.dir/index.txt
-// RUN: diff %t1.dir/coverage/tmp/showLineExecutionCounts.cpp.txt %t2.dir/coverage/tmp/showLineExecutionCounts.cpp.txt
-// RUN: diff %t1.dir/index.txt %t3.dir/index.txt
-// RUN: diff %t1.dir/coverage/tmp/showLineExecutionCounts.cpp.txt %t3.dir/coverage/tmp/showLineExecutionCounts.cpp.txt
+// RUN: diff %t.dir/1/index.txt %t.dir/2/index.txt
+// RUN: diff %t.dir/1/coverage/tmp/showLineExecutionCounts.cpp.txt %t.dir/2/coverage/tmp/showLineExecutionCounts.cpp.txt
+// RUN: diff %t.dir/1/index.txt %t.dir/3/index.txt
+// RUN: diff %t.dir/1/coverage/tmp/showLineExecutionCounts.cpp.txt %t.dir/3/coverage/tmp/showLineExecutionCounts.cpp.txt

>From 5fa862ad60b75814c15f9317d6d59384524f5717 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Sat, 21 Dec 2024 17:30:24 +0900
Subject: [PATCH 25/72] Use `[[#min(C,n)]]` for tests

---
 .../tools/llvm-cov/Inputs/branch-c-general.c  | 120 +++++++++---------
 .../llvm-cov/Inputs/branch-logical-mixed.cpp  |  54 ++++----
 .../tools/llvm-cov/Inputs/branch-macros.cpp   |  22 ++--
 .../Inputs/showLineExecutionCounts.cpp        |  45 +++----
 .../test/tools/llvm-cov/branch-c-general.test |   2 +-
 .../tools/llvm-cov/branch-logical-mixed.test  |   4 +-
 llvm/test/tools/llvm-cov/branch-macros.test   |   4 +-
 .../llvm-cov/showLineExecutionCounts.test     |  12 +-
 8 files changed, 132 insertions(+), 131 deletions(-)

diff --git a/llvm/test/tools/llvm-cov/Inputs/branch-c-general.c b/llvm/test/tools/llvm-cov/Inputs/branch-c-general.c
index 5ea9ecb42b0ed..9660e857092bc 100644
--- a/llvm/test/tools/llvm-cov/Inputs/branch-c-general.c
+++ b/llvm/test/tools/llvm-cov/Inputs/branch-c-general.c
@@ -6,27 +6,27 @@
 
 void simple_loops() {           // CHECK: @LINE|{{.*}}simple_loops()
   int i;
-  for (i = 0; i < 100; ++i) {   // BRCOV: Branch ([[@LINE]]:15): [True: [[C100:100|1]], False: 1]
+  for (i = 0; i < 100; ++i) {   // BRCOV: Branch ([[@LINE]]:15): [True: [[#min(C,100)]], False: 1]
   }
-  while (i > 0)                 // BRCOV: Branch ([[@LINE]]:10): [True: [[C100]], False: 1]
+  while (i > 0)                 // BRCOV: Branch ([[@LINE]]:10): [True: [[#min(C,100)]], False: 1]
     i--;
-  do {} while (i++ < 75);       // BRCOV: Branch ([[@LINE]]:16): [True: [[C75:75|1]], False: 1]
+  do {} while (i++ < 75);       // BRCOV: Branch ([[@LINE]]:16): [True: [[#min(C,75)]], False: 1]
 
 }
 
 void conditionals() {           // CHECK: @LINE|{{.*}}conditionals()
-  for (int i = 0; i < 100; ++i) {//BRCOV: Branch ([[@LINE]]:19): [True: [[C100]], False: 1]
-    if (i % 2) {                // BRCOV: Branch ([[@LINE]]:9): [True: [[C50:50|1]], False: [[C50]]]
-      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: [[C50]], False: 0]
-    } else if (i % 3) {         // BRCOV: Branch ([[@LINE]]:16): [True: [[C33:33|1]], False: [[C17:17|1]]]
-      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: [[C33]], False: 0]
+  for (int i = 0; i < 100; ++i) {//BRCOV: Branch ([[@LINE]]:19): [True: [[#min(C,100)]], False: 1]
+    if (i % 2) {                // BRCOV: Branch ([[@LINE]]:9): [True: [[#min(C,50)]], False: [[#min(C,50)]]]
+      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: [[#min(C,50)]], False: 0]
+    } else if (i % 3) {         // BRCOV: Branch ([[@LINE]]:16): [True: [[#min(C,33)]], False: [[#min(C,17)]]]
+      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: [[#min(C,33)]], False: 0]
     } else {
-      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: [[C16:16|1]], False: 1]
+      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: [[#min(C,16)]], False: 1]
     }
-                                // BRCOV: Branch ([[@LINE+1]]:9): [True: [[C100]], Folded]
-    if (1 && i) {}              // BRCOV: Branch ([[@LINE]]:14): [True: [[C99:99|1]], False: 1]
-    if (0 || i) {}              // BRCOV: Branch ([[@LINE]]:9): [Folded, False: [[C100]]]
-  }                             // BRCOV: Branch ([[@LINE-1]]:14): [True: [[C99]], False: 1]
+                                // BRCOV: Branch ([[@LINE+1]]:9): [True: [[#min(C,100)]], Folded]
+    if (1 && i) {}              // BRCOV: Branch ([[@LINE]]:14): [True: [[#min(C,99)]], False: 1]
+    if (0 || i) {}              // BRCOV: Branch ([[@LINE]]:9): [Folded, False: [[#min(C,100)]]]
+  }                             // BRCOV: Branch ([[@LINE-1]]:14): [True: [[#min(C,99)]], False: 1]
 
 }
 
@@ -35,22 +35,22 @@ void early_exits() {            // CHECK: @LINE|{{.*}}early_exits()
 
   if (i) {}                     // BRCOV: Branch ([[@LINE]]:7): [True: 0, False: 1]
 
-  while (i < 100) {             // BRCOV: Branch ([[@LINE]]:10): [True: [[C51:51|1]], False: 0]
+  while (i < 100) {             // BRCOV: Branch ([[@LINE]]:10): [True: [[#min(C,51)]], False: 0]
     i++;
-    if (i > 50)                 // BRCOV: Branch ([[@LINE]]:9): [True: 1, False: [[C50]]]
+    if (i > 50)                 // BRCOV: Branch ([[@LINE]]:9): [True: 1, False: [[#min(C,50)]]]
       break;
-    if (i % 2)                  // BRCOV: Branch ([[@LINE]]:9): [True: [[C25:25|1]], False: [[C25]]]
+    if (i % 2)                  // BRCOV: Branch ([[@LINE]]:9): [True: [[#min(C,25)]], False: [[#min(C,25)]]]
       continue;
   }
 
   if (i) {}                     // BRCOV: Branch ([[@LINE]]:7): [True: 1, False: 0]
 
   do {
-    if (i > 75)                 // BRCOV: Branch ([[@LINE]]:9): [True: 1, False: [[C25]]]
+    if (i > 75)                 // BRCOV: Branch ([[@LINE]]:9): [True: 1, False: [[#min(C,25)]]]
       return;
     else
       i++;
-  } while (i < 100);            // BRCOV: Branch ([[@LINE]]:12): [True: [[C25]], False: 0]
+  } while (i < 100);            // BRCOV: Branch ([[@LINE]]:12): [True: [[#min(C,25)]], False: 0]
 
   if (i) {}                     // BRCOV: Branch ([[@LINE]]:7): [True: 0, False: 0]
 
@@ -80,7 +80,7 @@ void jumps() {                  // CHECK: @LINE|{{.*}}jumps()
 second:
 third:
   i++;
-  if (i < 3)                    // BRCOV: Branch ([[@LINE]]:7): [True: [[C2:2|1]], False: 1]
+  if (i < 3)                    // BRCOV: Branch ([[@LINE]]:7): [True: [[#min(C,2)]], False: 1]
     goto loop2;
 
   while (i < 3) {               // BRCOV: Branch ([[@LINE]]:10): [True: 0, False: 1]
@@ -95,12 +95,12 @@ void jumps() {                  // CHECK: @LINE|{{.*}}jumps()
     }
   }
 
-  for (i = 0; i < 10; ++i) {    // BRCOV: Branch ([[@LINE]]:15): [True: [[C10:10|1]], False: 1]
+  for (i = 0; i < 10; ++i) {    // BRCOV: Branch ([[@LINE]]:15): [True: [[#min(C,10)]], False: 1]
     goto withinloop;
                                 // never reached -> no weights
     if (i) {}                   // BRCOV: Branch ([[@LINE]]:9): [True: 0, False: 0]
   withinloop:
-    if (i) {}                   // BRCOV: Branch ([[@LINE]]:9): [True: [[C9:9|1]], False: 1]
+    if (i) {}                   // BRCOV: Branch ([[@LINE]]:9): [True: [[#min(C,9)]], False: 1]
   }
 
 }
@@ -113,28 +113,28 @@ void switches() {               // CHECK: @LINE|{{.*}}switches()
   default:                      // BRCOV: Branch ([[@LINE]]:3): [True: 1, Folded]
     break;
   }
-                                // BRCOV: Branch ([[@LINE+1]]:63): [True: [[C15:15|1]], False: 0]
+                                // BRCOV: Branch ([[@LINE+1]]:63): [True: [[#min(C,15)]], False: 0]
   for (int i = 0, len = sizeof(weights) / sizeof(weights[0]); i < len; ++i) {
     switch (i[weights]) {
     case 1:                     // BRCOV: Branch ([[@LINE]]:5): [True: 1, Folded]
       if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: 0, False: 1]
       // fallthrough
-    case 2:                     // BRCOV: Branch ([[@LINE]]:5): [True: [[C2]], Folded]
-      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: [[C2]], False: 1]
+    case 2:                     // BRCOV: Branch ([[@LINE]]:5): [True: [[#min(C,2)]], Folded]
+      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: [[#min(C,2)]], False: 1]
       break;
-    case 3:                     // BRCOV: Branch ([[@LINE]]:5): [True: [[C3:3|1]], Folded]
-      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: [[C3]], False: 0]
+    case 3:                     // BRCOV: Branch ([[@LINE]]:5): [True: [[#min(C,3)]], Folded]
+      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: [[#min(C,3)]], False: 0]
       continue;
-    case 4:                     // BRCOV: Branch ([[@LINE]]:5): [True: [[C4:4|1]], Folded]
-      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: [[C4]], False: 0]
+    case 4:                     // BRCOV: Branch ([[@LINE]]:5): [True: [[#min(C,4)]], Folded]
+      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: [[#min(C,4)]], False: 0]
       switch (i) {
-      case 6 ... 9:             // BRCOV: Branch ([[@LINE]]:7): [True: [[C4]], Folded]
-        if (i) {}               // BRCOV: Branch ([[@LINE]]:13): [True: [[C4]], False: 0]
+      case 6 ... 9:             // BRCOV: Branch ([[@LINE]]:7): [True: [[#min(C,4)]], Folded]
+        if (i) {}               // BRCOV: Branch ([[@LINE]]:13): [True: [[#min(C,4)]], False: 0]
         continue;
       }
 
-    default:                    // BRCOV: Branch ([[@LINE]]:5): [True: [[C5:5|1]], Folded]
-      if (i == len - 1)         // BRCOV: Branch ([[@LINE]]:11): [True: 1, False: [[C4]]]
+    default:                    // BRCOV: Branch ([[@LINE]]:5): [True: [[#min(C,5)]], Folded]
+      if (i == len - 1)         // BRCOV: Branch ([[@LINE]]:11): [True: 1, False: [[#min(C,4)]]]
         return;
     }
   }
@@ -145,7 +145,7 @@ void switches() {               // CHECK: @LINE|{{.*}}switches()
 }
 
 void big_switch() {             // CHECK: @LINE|{{.*}}big_switch()
-  for (int i = 0; i < 32; ++i) {// BRCOV: Branch ([[@LINE]]:19): [True: [[C32:32|1]], False: 1]
+  for (int i = 0; i < 32; ++i) {// BRCOV: Branch ([[@LINE]]:19): [True: [[#min(C,32)]], False: 1]
     switch (1 << i) {
     case (1 << 0):              // BRCOV: Branch ([[@LINE]]:5): [True: 1, Folded]
       if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: 0, False: 1]
@@ -153,24 +153,24 @@ void big_switch() {             // CHECK: @LINE|{{.*}}big_switch()
     case (1 << 1):              // BRCOV: Branch ([[@LINE]]:5): [True: 1, Folded]
       if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: 1, False: 1]
       break;
-    case (1 << 2) ... (1 << 12):// BRCOV: Branch ([[@LINE]]:5): [True: [[C11:11|1]], Folded]
-      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: [[C11]], False: 0]
+    case (1 << 2) ... (1 << 12):// BRCOV: Branch ([[@LINE]]:5): [True: [[#min(C,11)]], Folded]
+      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: [[#min(C,11)]], False: 0]
       break;
       // The branch for the large case range above appears after the case body.
 
     case (1 << 13):             // BRCOV: Branch ([[@LINE]]:5): [True: 1, Folded]
       if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: 1, False: 0]
       break;
-    case (1 << 14) ... (1 << 28)://BRCOV: Branch ([[@LINE]]:5): [True: [[C15]], Folded]
-      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: [[C15]], False: 0]
+    case (1 << 14) ... (1 << 28)://BRCOV: Branch ([[@LINE]]:5): [True: [[#min(C,15)]], Folded]
+      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: [[#min(C,15)]], False: 0]
       break;
     // The branch for the large case range above appears after the case body.
 
     case (1 << 29) ... ((1 << 29) + 1):
       if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: 1, False: 0]
       break;
-    default:                    // BRCOV: Branch ([[@LINE]]:5): [True: [[C2]], Folded]
-      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: [[C2]], False: 0]
+    default:                    // BRCOV: Branch ([[@LINE]]:5): [True: [[#min(C,2)]], Folded]
+      if (i) {}                 // BRCOV: Branch ([[@LINE]]:11): [True: [[#min(C,2)]], False: 0]
       break;
     }
   }
@@ -180,30 +180,30 @@ void big_switch() {             // CHECK: @LINE|{{.*}}big_switch()
 void boolean_operators() {      // CHECK: @LINE|{{.*}}boolean_operators()
   int v;
   for (int i = 0; i < 100; ++i) {
-    v = i % 3 || i;             // BRCOV: Branch ([[@LINE]]:9): [True: [[C66:66|1]], False: [[C34:34|1]]]
-                                // BRCOV: Branch ([[@LINE-1]]:18): [True: [[C33]], False: 1]
-    v = i % 3 && i;             // BRCOV: Branch ([[@LINE]]:9): [True: [[C66]], False: [[C34]]]
-                                // BRCOV: Branch ([[@LINE-1]]:18): [True: [[C66]], False: 0]
-    v = i % 3 || i % 2 || i;    // BRCOV: Branch ([[@LINE]]:9): [True: [[C66]], False: [[C34]]]
-                                // BRCOV: Branch ([[@LINE-1]]:18): [True: [[C17]], False: [[C17]]]
-    v = i % 2 && i % 3 && i;    // BRCOV: Branch ([[@LINE-2]]:27): [True: [[C16]], False: 1]
-  }                             // BRCOV: Branch ([[@LINE-1]]:9): [True: [[C50]], False: [[C50]]]
-                                // BRCOV: Branch ([[@LINE-2]]:18): [True: [[C33]], False: [[C17]]]
-}                               // BRCOV: Branch ([[@LINE-3]]:27): [True: [[C33]], False: 0]
+    v = i % 3 || i;             // BRCOV: Branch ([[@LINE]]:9): [True: [[#min(C,66)]], False: [[#min(C,34)]]]
+                                // BRCOV: Branch ([[@LINE-1]]:18): [True: [[#min(C,33)]], False: 1]
+    v = i % 3 && i;             // BRCOV: Branch ([[@LINE]]:9): [True: [[#min(C,66)]], False: [[#min(C,34)]]]
+                                // BRCOV: Branch ([[@LINE-1]]:18): [True: [[#min(C,66)]], False: 0]
+    v = i % 3 || i % 2 || i;    // BRCOV: Branch ([[@LINE]]:9): [True: [[#min(C,66)]], False: [[#min(C,34)]]]
+                                // BRCOV: Branch ([[@LINE-1]]:18): [True: [[#min(C,17)]], False: [[#min(C,17)]]]
+    v = i % 2 && i % 3 && i;    // BRCOV: Branch ([[@LINE-2]]:27): [True: [[#min(C,16)]], False: 1]
+  }                             // BRCOV: Branch ([[@LINE-1]]:9): [True: [[#min(C,50)]], False: [[#min(C,50)]]]
+                                // BRCOV: Branch ([[@LINE-2]]:18): [True: [[#min(C,33)]], False: [[#min(C,17)]]]
+}                               // BRCOV: Branch ([[@LINE-3]]:27): [True: [[#min(C,33)]], False: 0]
 
 void boolop_loops() {           // CHECK: @LINE|{{.*}}boolop_loops()
   int i = 100;
 
-  while (i && i > 50)           // BRCOV: Branch ([[@LINE]]:10): [True: [[C51]], False: 0]
-    i--;                        // BRCOV: Branch ([[@LINE-1]]:15): [True: [[C50]], False: 1]
+  while (i && i > 50)           // BRCOV: Branch ([[@LINE]]:10): [True: [[#min(C,51)]], False: 0]
+    i--;                        // BRCOV: Branch ([[@LINE-1]]:15): [True: [[#min(C,50)]], False: 1]
 
-  while ((i % 2) || (i > 0))    // BRCOV: Branch ([[@LINE]]:10): [True: [[C25]], False: [[C26:26|1]]]
-    i--;                        // BRCOV: Branch ([[@LINE-1]]:21): [True: [[C25]], False: 1]
+  while ((i % 2) || (i > 0))    // BRCOV: Branch ([[@LINE]]:10): [True: [[#min(C,25)]], False: [[#min(C,26)]]]
+    i--;                        // BRCOV: Branch ([[@LINE-1]]:21): [True: [[#min(C,25)]], False: 1]
 
-  for (i = 100; i && i > 50; --i);  // BRCOV: Branch ([[@LINE]]:17): [True: [[C51]], False: 0]
-                                    // BRCOV: Branch ([[@LINE-1]]:22): [True: [[C50]], False: 1]
-  for (; (i % 2) || (i > 0); --i);  // BRCOV: Branch ([[@LINE]]:10): [True: [[C25]], False: [[C26]]]
-                                    // BRCOV: Branch ([[@LINE-1]]:21): [True: [[C25]], False: 1]
+  for (i = 100; i && i > 50; --i);  // BRCOV: Branch ([[@LINE]]:17): [True: [[#min(C,51)]], False: 0]
+                                    // BRCOV: Branch ([[@LINE-1]]:22): [True: [[#min(C,50)]], False: 1]
+  for (; (i % 2) || (i > 0); --i);  // BRCOV: Branch ([[@LINE]]:10): [True: [[#min(C,25)]], False: [[#min(C,26)]]]
+                                    // BRCOV: Branch ([[@LINE-1]]:21): [True: [[#min(C,25)]], False: 1]
 }
 
 void conditional_operator() {   // CHECK: @LINE|{{.*}}conditional_operator()
@@ -216,7 +216,7 @@ void conditional_operator() {   // CHECK: @LINE|{{.*}}conditional_operator()
 }
 
 void do_fallthrough() {         // CHECK: @LINE|{{.*}}do_fallthrough()
-  for (int i = 0; i < 10; ++i) {// BRCOV: Branch ([[@LINE]]:19): [True: [[C10]], False: 1]
+  for (int i = 0; i < 10; ++i) {// BRCOV: Branch ([[@LINE]]:19): [True: [[#min(C,10)]], False: 1]
     int j = 0;
     do {
       // The number of exits out of this do-loop via the break statement
@@ -224,12 +224,12 @@ void do_fallthrough() {         // CHECK: @LINE|{{.*}}do_fallthrough()
       // fallthrough count). Make sure that does not violate any assertions.
       if (i < 8) break;
       j++;
-    } while (j < 2);            // BRCOV: Branch ([[@LINE]]:14): [True: [[C2]], False: [[C2]]]
+    } while (j < 2);            // BRCOV: Branch ([[@LINE]]:14): [True: [[#min(C,2)]], False: [[#min(C,2)]]]
   }
 }
 
 static void static_func() {     // CHECK: @LINE|{{.*}}static_func()
-  for (int i = 0; i < 10; ++i) {// BRCOV: Branch ([[@LINE]]:19): [True: [[C10]], False: 1]
+  for (int i = 0; i < 10; ++i) {// BRCOV: Branch ([[@LINE]]:19): [True: [[#min(C,10)]], False: 1]
   }
 }
 
diff --git a/llvm/test/tools/llvm-cov/Inputs/branch-logical-mixed.cpp b/llvm/test/tools/llvm-cov/Inputs/branch-logical-mixed.cpp
index 0eaf4c963ef9f..246b0389aa600 100644
--- a/llvm/test/tools/llvm-cov/Inputs/branch-logical-mixed.cpp
+++ b/llvm/test/tools/llvm-cov/Inputs/branch-logical-mixed.cpp
@@ -13,62 +13,62 @@ void func(int a, int b) {
   bool b4 = a > b;
   bool b5 = a != b;
 
-  bool c = b0 &&           // BRCOV: Branch ([[@LINE]]:12): [True: [[C3:3|1]], False: 1]
-           b1 &&           // BRCOV: Branch ([[@LINE]]:12): [True: [[C2:2|1]], False: 1]
-           b2 &&           // BRCOV: Branch ([[@LINE]]:12): [True: [[C2]], False: 0]
-           b3 &&           // BRCOV: Branch ([[@LINE]]:12): [True: 0, False: [[C2]]]
+  bool c = b0 &&           // BRCOV: Branch ([[@LINE]]:12): [True: [[#min(C,3)]], False: 1]
+           b1 &&           // BRCOV: Branch ([[@LINE]]:12): [True: [[#min(C,2)]], False: 1]
+           b2 &&           // BRCOV: Branch ([[@LINE]]:12): [True: [[#min(C,2)]], False: 0]
+           b3 &&           // BRCOV: Branch ([[@LINE]]:12): [True: 0, False: [[#min(C,2)]]]
            b4 &&           // BRCOV: Branch ([[@LINE]]:12): [True: 0, False: 0]
            b5;             // BRCOV: Branch ([[@LINE]]:12): [True: 0, False: 0]
 
-  bool d = b0 ||           // BRCOV: Branch ([[@LINE]]:12): [True: [[C3]], False: 1]
+  bool d = b0 ||           // BRCOV: Branch ([[@LINE]]:12): [True: [[#min(C,3)]], False: 1]
            b1 ||           // BRCOV: Branch ([[@LINE]]:12): [True: 0, False: 1]
            b2 ||           // BRCOV: Branch ([[@LINE]]:12): [True: 1, False: 0]
            b3 ||           // BRCOV: Branch ([[@LINE]]:12): [True: 0, False: 0]
            b4 ||           // BRCOV: Branch ([[@LINE]]:12): [True: 0, False: 0]
            b5;             // BRCOV: Branch ([[@LINE]]:12): [True: 0, False: 0]
 
-  bool e = (b0  &&         // BRCOV: Branch ([[@LINE]]:13): [True: [[C3]], False: 1]
-            b5) ||         // BRCOV: Branch ([[@LINE]]:13): [True: 1, False: [[C2]]]
-           (b1  &&         // BRCOV: Branch ([[@LINE]]:13): [True: [[C2]], False: 1]
-            b4) ||         // BRCOV: Branch ([[@LINE]]:13): [True: 0, False: [[C2]]]
-           (b2  &&         // BRCOV: Branch ([[@LINE]]:13): [True: [[C3]], False: 0]
-            b3) ||         // BRCOV: Branch ([[@LINE]]:13): [True: 0, False: [[C3]]]
-           (b3  &&         // BRCOV: Branch ([[@LINE]]:13): [True: 0, False: [[C3]]]
+  bool e = (b0  &&         // BRCOV: Branch ([[@LINE]]:13): [True: [[#min(C,3)]], False: 1]
+            b5) ||         // BRCOV: Branch ([[@LINE]]:13): [True: 1, False: [[#min(C,2)]]]
+           (b1  &&         // BRCOV: Branch ([[@LINE]]:13): [True: [[#min(C,2)]], False: 1]
+            b4) ||         // BRCOV: Branch ([[@LINE]]:13): [True: 0, False: [[#min(C,2)]]]
+           (b2  &&         // BRCOV: Branch ([[@LINE]]:13): [True: [[#min(C,3)]], False: 0]
+            b3) ||         // BRCOV: Branch ([[@LINE]]:13): [True: 0, False: [[#min(C,3)]]]
+           (b3  &&         // BRCOV: Branch ([[@LINE]]:13): [True: 0, False: [[#min(C,3)]]]
             b2) ||         // BRCOV: Branch ([[@LINE]]:13): [True: 0, False: 0]
-           (b4  &&         // BRCOV: Branch ([[@LINE]]:13): [True: 1, False: [[C2]]]
+           (b4  &&         // BRCOV: Branch ([[@LINE]]:13): [True: 1, False: [[#min(C,2)]]]
             b1) ||         // BRCOV: Branch ([[@LINE]]:13): [True: 0, False: 1]
-           (b5  &&         // BRCOV: Branch ([[@LINE]]:13): [True: 1, False: [[C2]]]
+           (b5  &&         // BRCOV: Branch ([[@LINE]]:13): [True: 1, False: [[#min(C,2)]]]
             b0);           // BRCOV: Branch ([[@LINE]]:13): [True: 0, False: 1]
 
-  bool f = (b0  ||         // BRCOV: Branch ([[@LINE]]:13): [True: [[C3]], False: 1]
+  bool f = (b0  ||         // BRCOV: Branch ([[@LINE]]:13): [True: [[#min(C,3)]], False: 1]
             b5) &&         // BRCOV: Branch ([[@LINE]]:13): [True: 1, False: 0]
-           (b1  ||         // BRCOV: Branch ([[@LINE]]:13): [True: [[C2]], False: [[C2]]]
+           (b1  ||         // BRCOV: Branch ([[@LINE]]:13): [True: [[#min(C,2)]], False: [[#min(C,2)]]]
             b4) &&         // BRCOV: Branch ([[@LINE]]:13): [True: 1, False: 1]
-           (b2  ||         // BRCOV: Branch ([[@LINE]]:13): [True: [[C3]], False: 0]
+           (b2  ||         // BRCOV: Branch ([[@LINE]]:13): [True: [[#min(C,3)]], False: 0]
             b3) &&         // BRCOV: Branch ([[@LINE]]:13): [True: 0, False: 0]
-           (b3  ||         // BRCOV: Branch ([[@LINE]]:13): [True: 0, False: [[C3]]]
-            b2) &&         // BRCOV: Branch ([[@LINE]]:13): [True: [[C3]], False: 0]
-           (b4  ||         // BRCOV: Branch ([[@LINE]]:13): [True: 1, False: [[C2]]]
-            b1) &&         // BRCOV: Branch ([[@LINE]]:13): [True: [[C2]], False: 0]
-           (b5  ||         // BRCOV: Branch ([[@LINE]]:13): [True: 1, False: [[C2]]]
-            b0);           // BRCOV: Branch ([[@LINE]]:13): [True: [[C2]], False: 0]
+           (b3  ||         // BRCOV: Branch ([[@LINE]]:13): [True: 0, False: [[#min(C,3)]]]
+            b2) &&         // BRCOV: Branch ([[@LINE]]:13): [True: [[#min(C,3)]], False: 0]
+           (b4  ||         // BRCOV: Branch ([[@LINE]]:13): [True: 1, False: [[#min(C,2)]]]
+            b1) &&         // BRCOV: Branch ([[@LINE]]:13): [True: [[#min(C,2)]], False: 0]
+           (b5  ||         // BRCOV: Branch ([[@LINE]]:13): [True: 1, False: [[#min(C,2)]]]
+            b0);           // BRCOV: Branch ([[@LINE]]:13): [True: [[#min(C,2)]], False: 0]
 
-  if (c)                   // BRCOV: Branch ([[@LINE]]:7): [True: 0, False: [[C4]]]
+  if (c)                   // BRCOV: Branch ([[@LINE]]:7): [True: 0, False: [[#min(C,4)]]]
     printf("case0\n");
   else
     printf("case1\n");
 
-  if (d)                   // BRCOV: Branch ([[@LINE]]:7): [True: [[C4]], False: 0]
+  if (d)                   // BRCOV: Branch ([[@LINE]]:7): [True: [[#min(C,4)]], False: 0]
     printf("case2\n");
   else
     printf("case3\n");
 
-  if (e)                   // BRCOV: Branch ([[@LINE]]:7): [True: 1, False: [[C3]]]
+  if (e)                   // BRCOV: Branch ([[@LINE]]:7): [True: 1, False: [[#min(C,3)]]]
     printf("case4\n");
   else
     printf("case5\n");
 
-  if (f)                   // BRCOV: Branch ([[@LINE]]:7): [True: [[C3]], False: 1]
+  if (f)                   // BRCOV: Branch ([[@LINE]]:7): [True: [[#min(C,3)]], False: 1]
     printf("case6\n");
   else
     printf("case7\n");
diff --git a/llvm/test/tools/llvm-cov/Inputs/branch-macros.cpp b/llvm/test/tools/llvm-cov/Inputs/branch-macros.cpp
index 5dc5dcefd2c3f..ad627106f32bd 100644
--- a/llvm/test/tools/llvm-cov/Inputs/branch-macros.cpp
+++ b/llvm/test/tools/llvm-cov/Inputs/branch-macros.cpp
@@ -5,27 +5,27 @@
 #define COND1 (a == b)
 #define COND2 (a != b)
 #define COND3 (COND1 && COND2)
-#define COND4 (COND3 ? COND2 : COND1) // BRCOV: | Branch ([[@LINE]]:15): [True: 1, False: 2]
+#define COND4 (COND3 ? COND2 : COND1) // BRCOV: | Branch ([[@LINE]]:15): [True: 1, False: [[#min(C,2)]]]
 #define MACRO1 COND3
 #define MACRO2 MACRO1
 #define MACRO3 MACRO2
 
 #include <stdlib.h>
 
-// CHECK: |{{ +}}[[C3:3|1]]|bool func(
+// CHECK: |{{ +}}[[#min(C,3)]]|bool func(
 bool func(int a, int b) {
-  bool c = COND1 && COND2; // BRCOV: |  |  |  Branch ([[@LINE-12]]:15): [True: 1, False: [[C2:2|1]]]
+  bool c = COND1 && COND2; // BRCOV: |  |  |  Branch ([[@LINE-12]]:15): [True: 1, False: [[#min(C,2)]]]
                            // BRCOV: |  |  |  Branch ([[@LINE-12]]:15): [True: 0, False: 1]
-  bool d = COND3;          // BRCOV: |  |  |  |  |  Branch ([[@LINE-14]]:15): [True: 1, False: [[C2]]]
+  bool d = COND3;          // BRCOV: |  |  |  |  |  Branch ([[@LINE-14]]:15): [True: 1, False: [[#min(C,2)]]]
                            // BRCOV: |  |  |  |  |  Branch ([[@LINE-14]]:15): [True: 0, False: 1]
-  bool e = MACRO1;         // BRCOV: |  |  |  |  |  |  |  Branch ([[@LINE-16]]:15): [True: 1, False: [[C2]]]
+  bool e = MACRO1;         // BRCOV: |  |  |  |  |  |  |  Branch ([[@LINE-16]]:15): [True: 1, False: [[#min(C,2)]]]
                            // BRCOV: |  |  |  |  |  |  |  Branch ([[@LINE-16]]:15): [True: 0, False: 1]
-  bool f = MACRO2;         // BRCOV: |  |  |  |  |  |  |  |  |  Branch ([[@LINE-18]]:15): [True: 1, False: [[C2]]]
+  bool f = MACRO2;         // BRCOV: |  |  |  |  |  |  |  |  |  Branch ([[@LINE-18]]:15): [True: 1, False: [[#min(C,2)]]]
                            // BRCOV: |  |  |  |  |  |  |  |  |  Branch ([[@LINE-18]]:15): [True: 0, False: 1]
-  bool g = MACRO3;         // BRCOV: |  |  |  |  |  |  |  |  |  |  |  Branch ([[@LINE-20]]:15): [True: 1, False: [[C2]]]
+  bool g = MACRO3;         // BRCOV: |  |  |  |  |  |  |  |  |  |  |  Branch ([[@LINE-20]]:15): [True: 1, False: [[#min(C,2)]]]
                            // BRCOV: |  |  |  |  |  |  |  |  |  |  |  Branch ([[@LINE-20]]:15): [True: 0, False: 1]
   return c && d && e && f && g;
-                           // BRCOV: |  Branch ([[@LINE-1]]:10): [True: 0, False: [[C3]]]
+                           // BRCOV: |  Branch ([[@LINE-1]]:10): [True: 0, False: [[#min(C,3)]]]
                            // BRCOV: |  Branch ([[@LINE-2]]:15): [True: 0, False: 0]
                            // BRCOV: |  Branch ([[@LINE-3]]:20): [True: 0, False: 0]
                            // BRCOV: |  Branch ([[@LINE-4]]:25): [True: 0, False: 0]
@@ -34,11 +34,11 @@ bool func(int a, int b) {
 
 
 bool func2(int a, int b) {
-    bool h = MACRO3 || COND4;  // BRCOV: |  |  |  |  |  |  |  |  |  |  |  Branch ([[@LINE-32]]:15): [True: 1, False: [[C2]]]
+    bool h = MACRO3 || COND4;  // BRCOV: |  |  |  |  |  |  |  |  |  |  |  Branch ([[@LINE-32]]:15): [True: 1, False: [[#min(C,2)]]]
                                // BRCOV: |  |  |  |  |  |  |  |  |  |  |  Branch ([[@LINE-32]]:15): [True: 0, False: 1]
-                               // BRCOV: |  |  |  |  |  |  |  Branch ([[@LINE-34]]:15): [True: 1, False: [[C2]]]
+                               // BRCOV: |  |  |  |  |  |  |  Branch ([[@LINE-34]]:15): [True: 1, False: [[#min(C,2)]]]
                                // BRCOV: |  |  |  |  |  |  |  Branch ([[@LINE-34]]:15): [True: 0, False: 1]
-                               // BRCOV: |  |  |  Branch ([[@LINE-33]]:15): [True: 1, False: [[C2]]]
+                               // BRCOV: |  |  |  Branch ([[@LINE-33]]:15): [True: 1, False: [[#min(C,2)]]]
   return h;
 }
 
diff --git a/llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts.cpp b/llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts.cpp
index b14409f173849..be780b45f279c 100644
--- a/llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts.cpp
+++ b/llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts.cpp
@@ -1,29 +1,30 @@
 // HTML-WHOLE-FILE: <td class='line-number'><a name='L[[@LINE+2]]' href='#L[[@LINE+2]]'><pre>[[@LINE+2]]</pre></a></td><td class='skipped-line'></td><td class='code'><pre>// before
 // HTML-FILTER-NOT: <td class='line-number'><a name='L[[@LINE+1]]' href='#L[[@LINE+1]]'><pre>[[@LINE+1]]</pre></a></td><td class='skipped-line'></td><td class='code'><pre>// before
-// before any coverage              // WHOLE-FILE: [[@LINE]]|      |// before
-                                    // FILTER-NOT: [[@LINE-1]]|    |// before
+// before any coverage              // WHOLE-FILE: [[@LINE]]|                     |// before
+                                    // FILTER-NOT: [[@LINE-1]]|                   |// before
 // HTML: <td class='line-number'><a name='L[[@LINE+1]]' href='#L[[@LINE+1]]'><pre>[[@LINE+1]]</pre></a></td><td class='covered-line'><pre>161</pre></td><td class='code'><pre>int main() {
-int main() {                              // TEXT: [[@LINE]]|     [[C161:161|1]]|int main(
-  int x = 0;                              // TEXT: [[@LINE]]|           [[C161]]|  int x
+int main() {                              // TEXT: [[@LINE]]| [[#C161:min(C,161)]]|int main(
+  int x = 0;                              // TEXT: [[@LINE]]|            [[#C161]]|  int x
 
-  if (x) {                                // TEXT: [[@LINE]]|           [[C161]]|  if (x)
-    x = 0;                                // TEXT: [[@LINE]]|                  0|    x = 0
-  } else {                                // TEXT: [[@LINE]]|           [[C161]]|  } else
-    x = 1;                                // TEXT: [[@LINE]]|           [[C161]]|    x = 1
-  }                                       // TEXT: [[@LINE]]|           [[C161]]|  }
+  if (x) {                                // TEXT: [[@LINE]]|            [[#C161]]|  if (x)
+    x = 0;                                // TEXT: [[@LINE]]|                    0|    x = 0
+  } else {                                // TEXT: [[@LINE]]|            [[#C161]]|  } else
+    x = 1;                                // TEXT: [[@LINE]]|            [[#C161]]|    x = 1
+  }                                       // TEXT: [[@LINE]]|            [[#C161]]|  }
 
-  for (int i = 0; i < 100; ++i) {         // TEXT: [[@LINE]]| [[C16K2:16\.2k|161]]|  for (
-    x = 1;                                // TEXT: [[@LINE]]| [[C16K1:16\.1k|161]]|    x = 1
-  }                                       // TEXT: [[@LINE]]|          [[C16K1]]|  }
+  for (int i = 0; i < 100; ++i) {         // TEXT: [[@LINE]]|            [[C16K2]]|  for (
+    x = 1;                                // TEXT: [[@LINE]]|            [[C16K1]]|    x = 1
+  }                                       // TEXT: [[@LINE]]|            [[C16K1]]|  }
 
-  x = x < 10 ? x + 1 : x - 1;             // TEXT: [[@LINE]]|           [[C161]]|  x =
-  x = x > 10 ?                            // TEXT: [[@LINE]]|           [[C161]]|  x =
-        x - 1:                            // TEXT: [[@LINE]]|                  0|        x
-        x + 1;                            // TEXT: [[@LINE]]|           [[C161]]|        x
+  x = x < 10 ? x + 1 : x - 1;             // TEXT: [[@LINE]]|            [[#C161]]|  x =
+  x = x > 10 ?                            // TEXT: [[@LINE]]|            [[#C161]]|  x =
+        x - 1:                            // TEXT: [[@LINE]]|                    0|        x
+        x + 1;                            // TEXT: [[@LINE]]|            [[#C161]]|        x
 
-  return 0;                               // TEXT: [[@LINE]]|           [[C161]]|  return
-}                                         // TEXT: [[@LINE]]|           [[C161]]|}
-// after coverage                   // WHOLE-FILE: [[@LINE]]|      |// after
-                                    // FILTER-NOT: [[@LINE-1]]|    |// after
-// HTML-WHOLE-FILE: <td class='line-number'><a name='L[[@LINE-2]]' href='#L[[@LINE-2]]'><pre>[[@LINE-2]]</pre></a></td><td class='skipped-line'></td><td class='code'><pre>// after
-// HTML-FILTER-NOT: <td class='line-number'><a name='L[[@LINE-3]]' href='#L[[@LINE-3]]'><pre>[[@LINE-3]]</pre></a></td><td class='skipped-line'></td><td class='code'><pre>// after
+  return 0;                               // TEXT: [[@LINE]]|            [[#C161]]|  return
+}                                         // TEXT: [[@LINE]]|            [[#C161]]|}
+// after coverage                   // WHOLE-FILE: [[@LINE]]|                     |// after
+                                    // FILTER-NOT: [[@LINE-1]]|                   |// after
+// HTML-BINARY-NOT: <td class='covered-line'><pre>16
+// HTML-WHOLE-FILE: <td class='line-number'><a name='L[[@LINE-3]]' href='#L[[@LINE-3]]'><pre>[[@LINE-3]]</pre></a></td><td class='skipped-line'></td><td class='code'><pre>// after
+// HTML-FILTER-NOT: <td class='line-number'><a name='L[[@LINE-4]]' href='#L[[@LINE-4]]'><pre>[[@LINE-4]]</pre></a></td><td class='skipped-line'></td><td class='code'><pre>// after
diff --git a/llvm/test/tools/llvm-cov/branch-c-general.test b/llvm/test/tools/llvm-cov/branch-c-general.test
index 3d0b7ee563222..3c163bf6de45c 100644
--- a/llvm/test/tools/llvm-cov/branch-c-general.test
+++ b/llvm/test/tools/llvm-cov/branch-c-general.test
@@ -167,4 +167,4 @@
 
 // RUN: yaml2obj %S/Inputs/branch-c-general-single.yaml -o %t.o
 // RUN: llvm-profdata merge %S/Inputs/branch-c-general-single.proftext -o %t.profdata
-// RUN: llvm-cov show --show-branches=count %t.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs %S/Inputs/branch-c-general.c | FileCheck %S/Inputs/branch-c-general.c
+// RUN: llvm-cov show --show-branches=count %t.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs %S/Inputs/branch-c-general.c | FileCheck %S/Inputs/branch-c-general.c -D#C=1
diff --git a/llvm/test/tools/llvm-cov/branch-logical-mixed.test b/llvm/test/tools/llvm-cov/branch-logical-mixed.test
index b03cabeb01855..2dfbbc53b93cf 100644
--- a/llvm/test/tools/llvm-cov/branch-logical-mixed.test
+++ b/llvm/test/tools/llvm-cov/branch-logical-mixed.test
@@ -1,11 +1,11 @@
 // RUN: llvm-profdata merge %S/Inputs/branch-logical-mixed.proftext -o %t.profdata
-// RUN: llvm-cov show --show-branches=count %S/Inputs/branch-logical-mixed.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs | FileCheck %S/Inputs/branch-logical-mixed.cpp -check-prefixes=CHECK,BRCOV
+// RUN: llvm-cov show --show-branches=count %S/Inputs/branch-logical-mixed.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs | FileCheck %S/Inputs/branch-logical-mixed.cpp -D#C=999
 // RUN: llvm-cov report --show-branch-summary %S/Inputs/branch-logical-mixed.o32l -instr-profile %t.profdata -show-functions -path-equivalence=/tmp,%S/Inputs %S/Inputs/branch-logical-mixed.cpp
 | FileCheck %s -check-prefix=REPORT
 
 // RUN: yaml2obj %S/Inputs/branch-logical-mixed-single.yaml -o %t.o
 // RUN: llvm-profdata merge %S/Inputs/branch-logical-mixed-single.proftext -o %t.profdata
-// RUN: llvm-cov show --show-branches=count %t.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck %S/Inputs/branch-logical-mixed.cpp
+// RUN: llvm-cov show --show-branches=count %t.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck %S/Inputs/branch-logical-mixed.cpp -D#C=1
 // RUN: llvm-cov report --show-branch-summary %t.o -instr-profile %t.profdata -show-functions -path-equivalence=.,%S/Inputs %S/Inputs/branch-logical-mixed.cpp
 | FileCheck %s -check-prefix=REPORT
 
diff --git a/llvm/test/tools/llvm-cov/branch-macros.test b/llvm/test/tools/llvm-cov/branch-macros.test
index a4790afc53422..0a94e63608227 100644
--- a/llvm/test/tools/llvm-cov/branch-macros.test
+++ b/llvm/test/tools/llvm-cov/branch-macros.test
@@ -1,10 +1,10 @@
 // RUN: llvm-profdata merge %S/Inputs/branch-macros.proftext -o %t.profdata
-// RUN: llvm-cov show --show-expansions --show-branches=count %S/Inputs/branch-macros.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs | FileCheck %S/Inputs/branch-macros.cpp -check-prefixes=CHECK,BRCOV
+// RUN: llvm-cov show --show-expansions --show-branches=count %S/Inputs/branch-macros.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs | FileCheck %S/Inputs/branch-macros.cpp -check-prefixes=CHECK,BRCOV -D#C=999
 // RUN: llvm-cov report --show-branch-summary %S/Inputs/branch-macros.o32l -instr-profile %t.profdata -show-functions -path-equivalence=/tmp,%S/Inputs %S/Inputs/branch-macros.cpp | FileCheck %s -check-prefix=REPORT
 
 // RUN: yaml2obj %S/Inputs/branch-macros-single.yaml -o %t.o
 // RUN: llvm-profdata merge %S/Inputs/branch-macros-single.proftext -o %t.profdata
-// RUN: llvm-cov show --show-expansions --show-branches=count %t.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck %S/Inputs/branch-macros.cpp
+// RUN: llvm-cov show --show-expansions --show-branches=count %t.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck %S/Inputs/branch-macros.cpp -D#C=999
 
 // REPORT:      Name                        Regions    Miss   Cover     Lines    Miss   Cover  Branches    Miss   Cover
 // REPORT-NEXT: ---
diff --git a/llvm/test/tools/llvm-cov/showLineExecutionCounts.test b/llvm/test/tools/llvm-cov/showLineExecutionCounts.test
index 1c1e894922827..63a49341e6c17 100644
--- a/llvm/test/tools/llvm-cov/showLineExecutionCounts.test
+++ b/llvm/test/tools/llvm-cov/showLineExecutionCounts.test
@@ -2,14 +2,14 @@
 // RUN: rm -rf %t.dir
 // RUN: llvm-profdata merge %S/Inputs/lineExecutionCounts.proftext -o %t.profdata
 
-// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs | FileCheck -check-prefixes=TEXT,WHOLE-FILE %S/Inputs/showLineExecutionCounts.cpp
-// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs -name=main | FileCheck -check-prefixes=TEXT,FILTER %S/Inputs/showLineExecutionCounts.cpp
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs | FileCheck -check-prefixes=TEXT,WHOLE-FILE -D#C=999 -DC16K2=16.2k -DC16K1=16.1k %S/Inputs/showLineExecutionCounts.cpp
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs -name=main | FileCheck -check-prefixes=TEXT,FILTER -D#C=999 -DC16K2=16.2k -DC16K1=16.1k %S/Inputs/showLineExecutionCounts.cpp
 
 // Test -output-dir.
 // RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -o %t.dir/show -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs
 // RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -output-dir %t.dir/show.filtered -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs -name=main
-// RUN: FileCheck -check-prefixes=TEXT,WHOLE-FILE -input-file %t.dir/show/coverage/tmp/showLineExecutionCounts.cpp.txt %S/Inputs/showLineExecutionCounts.cpp
-// RUN: FileCheck -check-prefixes=TEXT,FILTER -input-file %t.dir/show.filtered/coverage/tmp/showLineExecutionCounts.cpp.txt %S/Inputs/showLineExecutionCounts.cpp
+// RUN: FileCheck -check-prefixes=TEXT,WHOLE-FILE -D#C=999 -DC16K2=16.2k -DC16K1=16.1k -input-file %t.dir/show/coverage/tmp/showLineExecutionCounts.cpp.txt %S/Inputs/showLineExecutionCounts.cpp
+// RUN: FileCheck -check-prefixes=TEXT,FILTER -D#C=999 -DC16K2=16.2k -DC16K1=16.1k -input-file %t.dir/show.filtered/coverage/tmp/showLineExecutionCounts.cpp.txt %S/Inputs/showLineExecutionCounts.cpp
 //
 // RUN: llvm-cov export %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata 2>/dev/null -summary-only > %t.export-summary.json
 // RUN: not grep '"name":"main"' %t.export-summary.json
@@ -46,5 +46,5 @@
 // RUN: yaml2obj %S/Inputs/showLineExecutionCounts-single.yaml -o %t.o
 // RUN: llvm-profdata merge %S/Inputs/showLineExecutionCounts-single.proftext -o %t.profdata
 
-// RUN: llvm-cov show %t.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck -check-prefixes=TEXT,WHOLE-FILE %S/Inputs/showLineExecutionCounts.cpp
-// RUN: llvm-cov show %t.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs -name=main | FileCheck -check-prefixes=TEXT,FILTER %S/Inputs/showLineExecutionCounts.cpp
+// RUN: llvm-cov show %t.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck -check-prefixes=TEXT,WHOLE-FILE -D#C=161 -DC16K2=161 -DC16K1=161 %S/Inputs/showLineExecutionCounts.cpp
+// RUN: llvm-cov show %t.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs -name=main | FileCheck -check-prefixes=TEXT,FILTER -D#C=161 -DC16K2=161 -DC16K1=161 %S/Inputs/showLineExecutionCounts.cpp

>From 805e9a93093121a3cde6c569b0247be6f68601fb Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Sat, 21 Dec 2024 17:32:28 +0900
Subject: [PATCH 26/72] llvm-cov: Introduce `--binary-counters`

---
 .../tools/llvm-cov/Inputs/branch-macros.cpp   | 52 +++++++++++++
 .../Inputs/showLineExecutionCounts.cpp        | 30 ++++++++
 llvm/test/tools/llvm-cov/branch-macros.cpp    | 60 ---------------
 llvm/test/tools/llvm-cov/branch-macros.test   | 12 +++
 .../llvm-cov/showLineExecutionCounts.cpp      | 73 -------------------
 .../llvm-cov/showLineExecutionCounts.test     | 46 ++++++++++++
 llvm/tools/llvm-cov/CodeCoverage.cpp          |  6 ++
 llvm/tools/llvm-cov/CoverageViewOptions.h     |  1 +
 llvm/tools/llvm-cov/SourceCoverageView.h      |  9 ++-
 .../tools/llvm-cov/SourceCoverageViewHTML.cpp | 15 ++--
 .../tools/llvm-cov/SourceCoverageViewText.cpp |  6 +-
 11 files changed, 167 insertions(+), 143 deletions(-)
 create mode 100644 llvm/test/tools/llvm-cov/Inputs/branch-macros.cpp
 create mode 100644 llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts.cpp
 delete mode 100644 llvm/test/tools/llvm-cov/branch-macros.cpp
 create mode 100644 llvm/test/tools/llvm-cov/branch-macros.test
 delete mode 100644 llvm/test/tools/llvm-cov/showLineExecutionCounts.cpp
 create mode 100644 llvm/test/tools/llvm-cov/showLineExecutionCounts.test

diff --git a/llvm/test/tools/llvm-cov/Inputs/branch-macros.cpp b/llvm/test/tools/llvm-cov/Inputs/branch-macros.cpp
new file mode 100644
index 0000000000000..ad627106f32bd
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/branch-macros.cpp
@@ -0,0 +1,52 @@
+
+
+
+
+#define COND1 (a == b)
+#define COND2 (a != b)
+#define COND3 (COND1 && COND2)
+#define COND4 (COND3 ? COND2 : COND1) // BRCOV: | Branch ([[@LINE]]:15): [True: 1, False: [[#min(C,2)]]]
+#define MACRO1 COND3
+#define MACRO2 MACRO1
+#define MACRO3 MACRO2
+
+#include <stdlib.h>
+
+// CHECK: |{{ +}}[[#min(C,3)]]|bool func(
+bool func(int a, int b) {
+  bool c = COND1 && COND2; // BRCOV: |  |  |  Branch ([[@LINE-12]]:15): [True: 1, False: [[#min(C,2)]]]
+                           // BRCOV: |  |  |  Branch ([[@LINE-12]]:15): [True: 0, False: 1]
+  bool d = COND3;          // BRCOV: |  |  |  |  |  Branch ([[@LINE-14]]:15): [True: 1, False: [[#min(C,2)]]]
+                           // BRCOV: |  |  |  |  |  Branch ([[@LINE-14]]:15): [True: 0, False: 1]
+  bool e = MACRO1;         // BRCOV: |  |  |  |  |  |  |  Branch ([[@LINE-16]]:15): [True: 1, False: [[#min(C,2)]]]
+                           // BRCOV: |  |  |  |  |  |  |  Branch ([[@LINE-16]]:15): [True: 0, False: 1]
+  bool f = MACRO2;         // BRCOV: |  |  |  |  |  |  |  |  |  Branch ([[@LINE-18]]:15): [True: 1, False: [[#min(C,2)]]]
+                           // BRCOV: |  |  |  |  |  |  |  |  |  Branch ([[@LINE-18]]:15): [True: 0, False: 1]
+  bool g = MACRO3;         // BRCOV: |  |  |  |  |  |  |  |  |  |  |  Branch ([[@LINE-20]]:15): [True: 1, False: [[#min(C,2)]]]
+                           // BRCOV: |  |  |  |  |  |  |  |  |  |  |  Branch ([[@LINE-20]]:15): [True: 0, False: 1]
+  return c && d && e && f && g;
+                           // BRCOV: |  Branch ([[@LINE-1]]:10): [True: 0, False: [[#min(C,3)]]]
+                           // BRCOV: |  Branch ([[@LINE-2]]:15): [True: 0, False: 0]
+                           // BRCOV: |  Branch ([[@LINE-3]]:20): [True: 0, False: 0]
+                           // BRCOV: |  Branch ([[@LINE-4]]:25): [True: 0, False: 0]
+                           // BRCOV: |  Branch ([[@LINE-5]]:30): [True: 0, False: 0]
+}
+
+
+bool func2(int a, int b) {
+    bool h = MACRO3 || COND4;  // BRCOV: |  |  |  |  |  |  |  |  |  |  |  Branch ([[@LINE-32]]:15): [True: 1, False: [[#min(C,2)]]]
+                               // BRCOV: |  |  |  |  |  |  |  |  |  |  |  Branch ([[@LINE-32]]:15): [True: 0, False: 1]
+                               // BRCOV: |  |  |  |  |  |  |  Branch ([[@LINE-34]]:15): [True: 1, False: [[#min(C,2)]]]
+                               // BRCOV: |  |  |  |  |  |  |  Branch ([[@LINE-34]]:15): [True: 0, False: 1]
+                               // BRCOV: |  |  |  Branch ([[@LINE-33]]:15): [True: 1, False: [[#min(C,2)]]]
+  return h;
+}
+
+
+int main(int argc, char *argv[])
+{
+  func(atoi(argv[1]), atoi(argv[2]));
+  func2(atoi(argv[1]), atoi(argv[2]));
+  (void)0;
+  return 0;
+}
diff --git a/llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts.cpp b/llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts.cpp
new file mode 100644
index 0000000000000..be780b45f279c
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/showLineExecutionCounts.cpp
@@ -0,0 +1,30 @@
+// HTML-WHOLE-FILE: <td class='line-number'><a name='L[[@LINE+2]]' href='#L[[@LINE+2]]'><pre>[[@LINE+2]]</pre></a></td><td class='skipped-line'></td><td class='code'><pre>// before
+// HTML-FILTER-NOT: <td class='line-number'><a name='L[[@LINE+1]]' href='#L[[@LINE+1]]'><pre>[[@LINE+1]]</pre></a></td><td class='skipped-line'></td><td class='code'><pre>// before
+// before any coverage              // WHOLE-FILE: [[@LINE]]|                     |// before
+                                    // FILTER-NOT: [[@LINE-1]]|                   |// before
+// HTML: <td class='line-number'><a name='L[[@LINE+1]]' href='#L[[@LINE+1]]'><pre>[[@LINE+1]]</pre></a></td><td class='covered-line'><pre>161</pre></td><td class='code'><pre>int main() {
+int main() {                              // TEXT: [[@LINE]]| [[#C161:min(C,161)]]|int main(
+  int x = 0;                              // TEXT: [[@LINE]]|            [[#C161]]|  int x
+
+  if (x) {                                // TEXT: [[@LINE]]|            [[#C161]]|  if (x)
+    x = 0;                                // TEXT: [[@LINE]]|                    0|    x = 0
+  } else {                                // TEXT: [[@LINE]]|            [[#C161]]|  } else
+    x = 1;                                // TEXT: [[@LINE]]|            [[#C161]]|    x = 1
+  }                                       // TEXT: [[@LINE]]|            [[#C161]]|  }
+
+  for (int i = 0; i < 100; ++i) {         // TEXT: [[@LINE]]|            [[C16K2]]|  for (
+    x = 1;                                // TEXT: [[@LINE]]|            [[C16K1]]|    x = 1
+  }                                       // TEXT: [[@LINE]]|            [[C16K1]]|  }
+
+  x = x < 10 ? x + 1 : x - 1;             // TEXT: [[@LINE]]|            [[#C161]]|  x =
+  x = x > 10 ?                            // TEXT: [[@LINE]]|            [[#C161]]|  x =
+        x - 1:                            // TEXT: [[@LINE]]|                    0|        x
+        x + 1;                            // TEXT: [[@LINE]]|            [[#C161]]|        x
+
+  return 0;                               // TEXT: [[@LINE]]|            [[#C161]]|  return
+}                                         // TEXT: [[@LINE]]|            [[#C161]]|}
+// after coverage                   // WHOLE-FILE: [[@LINE]]|                     |// after
+                                    // FILTER-NOT: [[@LINE-1]]|                   |// after
+// HTML-BINARY-NOT: <td class='covered-line'><pre>16
+// HTML-WHOLE-FILE: <td class='line-number'><a name='L[[@LINE-3]]' href='#L[[@LINE-3]]'><pre>[[@LINE-3]]</pre></a></td><td class='skipped-line'></td><td class='code'><pre>// after
+// HTML-FILTER-NOT: <td class='line-number'><a name='L[[@LINE-4]]' href='#L[[@LINE-4]]'><pre>[[@LINE-4]]</pre></a></td><td class='skipped-line'></td><td class='code'><pre>// after
diff --git a/llvm/test/tools/llvm-cov/branch-macros.cpp b/llvm/test/tools/llvm-cov/branch-macros.cpp
deleted file mode 100644
index 7f3d1e8bffb82..0000000000000
--- a/llvm/test/tools/llvm-cov/branch-macros.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-// RUN: llvm-profdata merge %S/Inputs/branch-macros.proftext -o %t.profdata
-// RUN: llvm-cov show --show-expansions --show-branches=count %S/Inputs/branch-macros.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S %s | FileCheck %s
-// RUN: llvm-cov report --show-branch-summary %S/Inputs/branch-macros.o32l -instr-profile %t.profdata -show-functions -path-equivalence=/tmp,%S %s | FileCheck %s -check-prefix=REPORT
-
-#define COND1 (a == b)
-#define COND2 (a != b)
-#define COND3 (COND1 && COND2)
-#define COND4 (COND3 ? COND2 : COND1) // CHECK: | Branch ([[@LINE]]:15): [True: 1, False: 2]
-#define MACRO1 COND3
-#define MACRO2 MACRO1
-#define MACRO3 MACRO2
-
-#include <stdlib.h>
-
-
-bool func(int a, int b) {
-  bool c = COND1 && COND2; // CHECK: |  |  |  Branch ([[@LINE-12]]:15): [True: 1, False: 2]
-                           // CHECK: |  |  |  Branch ([[@LINE-12]]:15): [True: 0, False: 1]
-  bool d = COND3;          // CHECK: |  |  |  |  |  Branch ([[@LINE-14]]:15): [True: 1, False: 2]
-                           // CHECK: |  |  |  |  |  Branch ([[@LINE-14]]:15): [True: 0, False: 1]
-  bool e = MACRO1;         // CHECK: |  |  |  |  |  |  |  Branch ([[@LINE-16]]:15): [True: 1, False: 2]
-                           // CHECK: |  |  |  |  |  |  |  Branch ([[@LINE-16]]:15): [True: 0, False: 1]
-  bool f = MACRO2;         // CHECK: |  |  |  |  |  |  |  |  |  Branch ([[@LINE-18]]:15): [True: 1, False: 2]
-                           // CHECK: |  |  |  |  |  |  |  |  |  Branch ([[@LINE-18]]:15): [True: 0, False: 1]
-  bool g = MACRO3;         // CHECK: |  |  |  |  |  |  |  |  |  |  |  Branch ([[@LINE-20]]:15): [True: 1, False: 2]
-                           // CHECK: |  |  |  |  |  |  |  |  |  |  |  Branch ([[@LINE-20]]:15): [True: 0, False: 1]
-  return c && d && e && f && g;
-                           // CHECK: |  Branch ([[@LINE-1]]:10): [True: 0, False: 3]
-                           // CHECK: |  Branch ([[@LINE-2]]:15): [True: 0, False: 0]
-                           // CHECK: |  Branch ([[@LINE-3]]:20): [True: 0, False: 0]
-                           // CHECK: |  Branch ([[@LINE-4]]:25): [True: 0, False: 0]
-                           // CHECK: |  Branch ([[@LINE-5]]:30): [True: 0, False: 0]
-}
-
-
-bool func2(int a, int b) {
-    bool h = MACRO3 || COND4;  // CHECK: |  |  |  |  |  |  |  |  |  |  |  Branch ([[@LINE-32]]:15): [True: 1, False: 2]
-                               // CHECK: |  |  |  |  |  |  |  |  |  |  |  Branch ([[@LINE-32]]:15): [True: 0, False: 1]
-                               // CHECK: |  |  |  |  |  |  |  Branch ([[@LINE-34]]:15): [True: 1, False: 2]
-                               // CHECK: |  |  |  |  |  |  |  Branch ([[@LINE-34]]:15): [True: 0, False: 1]
-                               // CHECK: |  |  |  Branch ([[@LINE-33]]:15): [True: 1, False: 2]
-  return h;
-}
-
-extern "C" { extern void __llvm_profile_write_file(void); }
-int main(int argc, char *argv[])
-{
-  func(atoi(argv[1]), atoi(argv[2]));
-  func2(atoi(argv[1]), atoi(argv[2]));
-  __llvm_profile_write_file();
-  return 0;
-}
-
-// REPORT: Name                        Regions    Miss   Cover     Lines    Miss   Cover  Branches    Miss   Cover
-// REPORT-NEXT: ---
-// REPORT-NEXT: _Z4funcii                        28       4  85.71%        18       0 100.00%        30      14  53.33%
-// REPORT-NEXT: _Z5func2ii                       13       1  92.31%         8       0 100.00%        10       2  80.00%
-// REPORT-NEXT: main                              1       0 100.00%         6       0 100.00%         0       0   0.00%
-// REPORT-NEXT: ---
-// REPORT-NEXT: TOTAL                            42       5  88.10%        32       0 100.00% 40      16  60.00%
diff --git a/llvm/test/tools/llvm-cov/branch-macros.test b/llvm/test/tools/llvm-cov/branch-macros.test
new file mode 100644
index 0000000000000..547a79ff94124
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/branch-macros.test
@@ -0,0 +1,12 @@
+// RUN: llvm-profdata merge %S/Inputs/branch-macros.proftext -o %t.profdata
+// RUN: llvm-cov show --show-expansions --show-branches=count %S/Inputs/branch-macros.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs | FileCheck %S/Inputs/branch-macros.cpp -check-prefixes=CHECK,BRCOV -D#C=999
+// RUN: llvm-cov show --binary-counters=true --show-expansions --show-branches=count %S/Inputs/branch-macros.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs | FileCheck %S/Inputs/branch-macros.cpp -check-prefixes=CHECK,BRCOV -D#C=1
+// RUN: llvm-cov report --show-branch-summary %S/Inputs/branch-macros.o32l -instr-profile %t.profdata -show-functions -path-equivalence=/tmp,%S/Inputs %S/Inputs/branch-macros.cpp | FileCheck %s -check-prefix=REPORT
+
+// REPORT:      Name                        Regions    Miss   Cover     Lines    Miss   Cover  Branches    Miss   Cover
+// REPORT-NEXT: ---
+// REPORT-NEXT: _Z4funcii                        28       4  85.71%        18       0 100.00%        30      14  53.33%
+// REPORT-NEXT: _Z5func2ii                       13       1  92.31%         8       0 100.00%        10       2  80.00%
+// REPORT-NEXT: main                              1       0 100.00%         6       0 100.00%         0       0   0.00%
+// REPORT-NEXT: ---
+// REPORT-NEXT: TOTAL                            42       5  88.10%        32       0 100.00%        40      16  60.00%
diff --git a/llvm/test/tools/llvm-cov/showLineExecutionCounts.cpp b/llvm/test/tools/llvm-cov/showLineExecutionCounts.cpp
deleted file mode 100644
index f72a9978b8a73..0000000000000
--- a/llvm/test/tools/llvm-cov/showLineExecutionCounts.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-// Basic handling of line counts.
-// RUN: llvm-profdata merge %S/Inputs/lineExecutionCounts.proftext -o %t.profdata
-
-// before any coverage              // WHOLE-FILE: [[@LINE]]|      |// before
-                                    // FILTER-NOT: [[@LINE-1]]|    |// before
-int main() {                              // TEXT: [[@LINE]]|   161|int main(
-  int x = 0;                              // TEXT: [[@LINE]]|   161|  int x
-                                          // TEXT: [[@LINE]]|   161|
-  if (x) {                                // TEXT: [[@LINE]]|   161|  if (x)
-    x = 0;                                // TEXT: [[@LINE]]|     0|    x = 0
-  } else {                                // TEXT: [[@LINE]]|   161|  } else
-    x = 1;                                // TEXT: [[@LINE]]|   161|    x = 1
-  }                                       // TEXT: [[@LINE]]|   161|  }
-                                          // TEXT: [[@LINE]]|   161|
-  for (int i = 0; i < 100; ++i) {         // TEXT: [[@LINE]]| 16.2k|  for (
-    x = 1;                                // TEXT: [[@LINE]]| 16.1k|    x = 1
-  }                                       // TEXT: [[@LINE]]| 16.1k|  }
-                                          // TEXT: [[@LINE]]|   161|
-  x = x < 10 ? x + 1 : x - 1;             // TEXT: [[@LINE]]|   161|  x =
-  x = x > 10 ?                            // TEXT: [[@LINE]]|   161|  x =
-        x - 1:                            // TEXT: [[@LINE]]|     0|        x
-        x + 1;                            // TEXT: [[@LINE]]|   161|        x
-                                          // TEXT: [[@LINE]]|   161|
-  return 0;                               // TEXT: [[@LINE]]|   161|  return
-}                                         // TEXT: [[@LINE]]|   161|}
-// after coverage                   // WHOLE-FILE: [[@LINE]]|      |// after
-                                    // FILTER-NOT: [[@LINE-1]]|    |// after
-
-// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata -path-equivalence=/tmp,%S %s | FileCheck -check-prefixes=TEXT,WHOLE-FILE %s
-// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata -path-equivalence=/tmp,%S -name=main %s | FileCheck -check-prefixes=TEXT,FILTER %s
-
-// Test -output-dir.
-// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -o %t.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S %s
-// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -output-dir %t.filtered.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S -name=main %s
-// RUN: FileCheck -check-prefixes=TEXT,WHOLE-FILE -input-file %t.dir/coverage/tmp/showLineExecutionCounts.cpp.txt %s
-// RUN: FileCheck -check-prefixes=TEXT,FILTER -input-file %t.filtered.dir/coverage/tmp/showLineExecutionCounts.cpp.txt %s
-//
-// RUN: llvm-cov export %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata 2>/dev/null -summary-only > %t.export-summary.json
-// RUN: not grep '"name":"main"' %t.export-summary.json
-//
-// Test html output.
-// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -format html -o %t.html.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S %s
-// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -format html -o %t.html.filtered.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S -name=main %s
-// RUN: FileCheck -check-prefixes=HTML,HTML-WHOLE-FILE -input-file %t.html.dir/coverage/tmp/showLineExecutionCounts.cpp.html %s
-// RUN: FileCheck -check-prefixes=HTML,HTML-FILTER -input-file %t.html.filtered.dir/coverage/tmp/showLineExecutionCounts.cpp.html %s
-//
-// HTML-WHOLE-FILE: <td class='line-number'><a name='L4' href='#L4'><pre>4</pre></a></td><td class='skipped-line'></td><td class='code'><pre>// before
-// HTML-FILTER-NOT: <td class='line-number'><a name='L4' href='#L4'><pre>4</pre></a></td><td class='skipped-line'></td><td class='code'><pre>// before
-// HTML: <td class='line-number'><a name='L6' href='#L6'><pre>6</pre></a></td><td class='covered-line'><pre>161</pre></td><td class='code'><pre>int main() {
-// HTML-WHOLE-FILE: <td class='line-number'><a name='L26' href='#L26'><pre>26</pre></a></td><td class='skipped-line'></td><td class='code'><pre>// after
-// HTML-FILTER-NOT: <td class='line-number'><a name='L26' href='#L26'><pre>26</pre></a></td><td class='skipped-line'></td><td class='code'><pre>// after
-//
-// Test index creation.
-// RUN: FileCheck -check-prefix=TEXT-INDEX -input-file %t.dir/index.txt %s
-// TEXT-INDEX: Filename
-// TEXT-INDEX-NEXT: ---
-// TEXT-INDEX-NEXT: {{.*}}showLineExecutionCounts.cpp
-//
-// RUN: FileCheck -check-prefix HTML-INDEX -input-file %t.html.dir/index.html %s
-// HTML-INDEX-LABEL: <table>
-// HTML-INDEX: <td class='column-entry-bold'>Filename</td>
-// HTML-INDEX: <td class='column-entry-bold'>Function Coverage</td>
-// HTML-INDEX: <td class='column-entry-bold'>Line Coverage</td>
-// HTML-INDEX: <td class='column-entry-bold'>Region Coverage</td>
-// HTML-INDEX: <a href='coverage{{.*}}showLineExecutionCounts.cpp.html'{{.*}}showLineExecutionCounts.cpp</a>
-// HTML-INDEX: <td class='column-entry-green'>
-// HTML-INDEX: 100.00% (1/1)
-// HTML-INDEX: <td class='column-entry-yellow'>
-// HTML-INDEX: 90.00% (18/20)
-// HTML-INDEX: <td class='column-entry-red'>
-// HTML-INDEX: 72.73% (8/11)
-// HTML-INDEX: <tr class='light-row-bold'>
-// HTML-INDEX: Totals
diff --git a/llvm/test/tools/llvm-cov/showLineExecutionCounts.test b/llvm/test/tools/llvm-cov/showLineExecutionCounts.test
new file mode 100644
index 0000000000000..3c24ec2094c97
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/showLineExecutionCounts.test
@@ -0,0 +1,46 @@
+// Basic handling of line counts.
+// RUN: rm -rf %t.dir
+// RUN: llvm-profdata merge %S/Inputs/lineExecutionCounts.proftext -o %t.profdata
+
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs | FileCheck -check-prefixes=TEXT,WHOLE-FILE -D#C=999 -DC16K2=16.2k -DC16K1=16.1k %S/Inputs/showLineExecutionCounts.cpp
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -binary-counters=true -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs | FileCheck -check-prefixes=TEXT,WHOLE-FILE -D#C=1 -DC16K2=1 -DC16K1=1 %S/Inputs/showLineExecutionCounts.cpp
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs -name=main | FileCheck -check-prefixes=TEXT,FILTER -D#C=999 -DC16K2=16.2k -DC16K1=16.1k %S/Inputs/showLineExecutionCounts.cpp
+
+// Test -output-dir.
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -o %t.dir/show -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -output-dir %t.dir/show.filtered -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs -name=main
+// RUN: FileCheck -check-prefixes=TEXT,WHOLE-FILE -D#C=999 -DC16K2=16.2k -DC16K1=16.1k -input-file %t.dir/show/coverage/tmp/showLineExecutionCounts.cpp.txt %S/Inputs/showLineExecutionCounts.cpp
+// RUN: FileCheck -check-prefixes=TEXT,FILTER -D#C=999 -DC16K2=16.2k -DC16K1=16.1k -input-file %t.dir/show.filtered/coverage/tmp/showLineExecutionCounts.cpp.txt %S/Inputs/showLineExecutionCounts.cpp
+//
+// RUN: llvm-cov export %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata 2>/dev/null -summary-only > %t.export-summary.json
+// RUN: not grep '"name":"main"' %t.export-summary.json
+//
+// Test html output.
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -format html -o %t.dir/html -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -format html -o %t.dir/html.binary -binary-counters=true -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -format html -o %t.dir/html.filtered -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs -name=main
+// RUN: FileCheck -check-prefixes=HTML,HTML-WHOLE-FILE -input-file %t.dir/html/coverage/tmp/showLineExecutionCounts.cpp.html %S/Inputs/showLineExecutionCounts.cpp
+// RUN: FileCheck -check-prefixes=HTML-BINARY,HTML-WHOLE-FILE -input-file %t.dir/html.binary/coverage/tmp/showLineExecutionCounts.cpp.html %S/Inputs/showLineExecutionCounts.cpp
+// RUN: FileCheck -check-prefixes=HTML,HTML-FILTER -input-file %t.dir/html.filtered/coverage/tmp/showLineExecutionCounts.cpp.html %S/Inputs/showLineExecutionCounts.cpp
+//
+// Test index creation.
+// RUN: FileCheck -check-prefix=TEXT-INDEX -input-file %t.dir/show/index.txt %s
+// TEXT-INDEX: Filename
+// TEXT-INDEX-NEXT: ---
+// TEXT-INDEX-NEXT: {{.*}}showLineExecutionCounts.cpp
+//
+// RUN: FileCheck -check-prefix HTML-INDEX -input-file %t.dir/html/index.html %s
+// HTML-INDEX-LABEL: <table>
+// HTML-INDEX: <td class='column-entry-bold'>Filename</td>
+// HTML-INDEX: <td class='column-entry-bold'>Function Coverage</td>
+// HTML-INDEX: <td class='column-entry-bold'>Line Coverage</td>
+// HTML-INDEX: <td class='column-entry-bold'>Region Coverage</td>
+// HTML-INDEX: <a href='coverage{{.*}}showLineExecutionCounts.cpp.html'{{.*}}showLineExecutionCounts.cpp</a>
+// HTML-INDEX: <td class='column-entry-green'>
+// HTML-INDEX: 100.00% (1/1)
+// HTML-INDEX: <td class='column-entry-yellow'>
+// HTML-INDEX: 90.00% (18/20)
+// HTML-INDEX: <td class='column-entry-red'>
+// HTML-INDEX: 72.73% (8/11)
+// HTML-INDEX: <tr class='light-row-bold'>
+// HTML-INDEX: Totals
diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp
index 5db5c2e023541..0e8360a4ac6ed 100644
--- a/llvm/tools/llvm-cov/CodeCoverage.cpp
+++ b/llvm/tools/llvm-cov/CodeCoverage.cpp
@@ -1023,6 +1023,11 @@ int CodeCoverageTool::doShow(int argc, const char **argv,
   cl::alias ShowOutputDirectoryA("o", cl::desc("Alias for --output-dir"),
                                  cl::aliasopt(ShowOutputDirectory));
 
+  cl::opt<bool> BinaryCounters(
+      "binary-counters", cl::Optional,
+      cl::desc("Show 1/0 instead of actual counter values."),
+      cl::cat(ViewCategory));
+
   cl::opt<uint32_t> TabSize(
       "tab-size", cl::init(2),
       cl::desc(
@@ -1100,6 +1105,7 @@ int CodeCoverageTool::doShow(int argc, const char **argv,
   ViewOpts.ShowFunctionInstantiations = ShowInstantiations;
   ViewOpts.ShowDirectoryCoverage = ShowDirectoryCoverage;
   ViewOpts.ShowOutputDirectory = ShowOutputDirectory;
+  ViewOpts.BinaryCounters = BinaryCounters;
   ViewOpts.TabSize = TabSize;
   ViewOpts.ProjectTitle = ProjectTitle;
 
diff --git a/llvm/tools/llvm-cov/CoverageViewOptions.h b/llvm/tools/llvm-cov/CoverageViewOptions.h
index 6925cffd8246d..b8d1a8b2d7c9b 100644
--- a/llvm/tools/llvm-cov/CoverageViewOptions.h
+++ b/llvm/tools/llvm-cov/CoverageViewOptions.h
@@ -45,6 +45,7 @@ struct CoverageViewOptions {
   bool SkipExpansions;
   bool SkipFunctions;
   bool SkipBranches;
+  bool BinaryCounters;
   OutputFormat Format;
   BranchOutputType ShowBranches;
   std::string ShowOutputDirectory;
diff --git a/llvm/tools/llvm-cov/SourceCoverageView.h b/llvm/tools/llvm-cov/SourceCoverageView.h
index 2b1570d399dd0..9b72ca03c6d7f 100644
--- a/llvm/tools/llvm-cov/SourceCoverageView.h
+++ b/llvm/tools/llvm-cov/SourceCoverageView.h
@@ -180,6 +180,8 @@ class SourceCoverageView {
   /// on display.
   std::vector<InstantiationView> InstantiationSubViews;
 
+  bool BinaryCounters;
+
   /// Get the first uncovered line number for the source file.
   unsigned getFirstUncoveredLineNo();
 
@@ -266,6 +268,10 @@ class SourceCoverageView {
   /// digits.
   static std::string formatCount(uint64_t N);
 
+  uint64_t Count1(uint64_t N) const { return (N && BinaryCounters ? 1 : N); }
+
+  std::string formatCount1(uint64_t N) const { return formatCount(Count1(N)); }
+
   /// Check if region marker output is expected for a line.
   bool shouldRenderRegionMarkers(const LineCoverageStats &LCS) const;
 
@@ -276,7 +282,8 @@ class SourceCoverageView {
                      const CoverageViewOptions &Options,
                      CoverageData &&CoverageInfo)
       : SourceName(SourceName), File(File), Options(Options),
-        CoverageInfo(std::move(CoverageInfo)) {}
+        CoverageInfo(std::move(CoverageInfo)),
+        BinaryCounters(Options.BinaryCounters) {}
 
 public:
   static std::unique_ptr<SourceCoverageView>
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
index e2be576b93cda..f3aa7e801597c 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
@@ -1019,19 +1019,22 @@ void SourceCoverageViewHTML::renderLine(raw_ostream &OS, LineRef L,
     // Just consider the segments which start *and* end on this line.
     for (unsigned I = 0, E = Segments.size() - 1; I < E; ++I) {
       const auto *CurSeg = Segments[I];
+      auto CurSegCount = Count1(CurSeg->Count);
+      auto LCSCount = Count1(LCS.getExecutionCount());
       if (!CurSeg->IsRegionEntry)
         continue;
-      if (CurSeg->Count == LCS.getExecutionCount())
+      if (CurSegCount == LCSCount)
         continue;
 
       Snippets[I + 1] =
-          tag("div", Snippets[I + 1] + tag("span", formatCount(CurSeg->Count),
-                                           "tooltip-content"),
+          tag("div",
+              Snippets[I + 1] +
+                  tag("span", formatCount(CurSegCount), "tooltip-content"),
               "tooltip");
 
       if (getOptions().Debug)
         errs() << "Marker at " << CurSeg->Line << ":" << CurSeg->Col << " = "
-               << formatCount(CurSeg->Count) << "\n";
+               << formatCount(CurSegCount) << "\n";
     }
   }
 
@@ -1051,7 +1054,7 @@ void SourceCoverageViewHTML::renderLineCoverageColumn(
     raw_ostream &OS, const LineCoverageStats &Line) {
   std::string Count;
   if (Line.isMapped())
-    Count = tag("pre", formatCount(Line.getExecutionCount()));
+    Count = tag("pre", formatCount1(Line.getExecutionCount()));
   std::string CoverageClass =
       (Line.getExecutionCount() > 0)
           ? "covered-line"
@@ -1106,7 +1109,7 @@ void SourceCoverageViewHTML::renderBranchView(raw_ostream &OS, BranchView &BRV,
 
     OS << tag("span", Label, (Count ? "None" : "red branch")) << ": ";
     if (getOptions().ShowBranchCounts)
-      OS << tag("span", formatCount(Count),
+      OS << tag("span", formatCount1(Count),
                 (Count ? "covered-line" : "uncovered-line"));
     else
       OS << format("%0.2f", (Total != 0 ? 100.0 * Count / Total : 0.0)) << "%";
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
index 63f8248e3387b..f0c366e45c2c9 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
@@ -216,7 +216,7 @@ void SourceCoverageViewText::renderLineCoverageColumn(
     OS.indent(LineCoverageColumnWidth) << '|';
     return;
   }
-  std::string C = formatCount(Line.getExecutionCount());
+  std::string C = formatCount1(Line.getExecutionCount());
   OS.indent(LineCoverageColumnWidth - C.size());
   colored_ostream(OS, raw_ostream::MAGENTA,
                   Line.hasMultipleRegions() && getOptions().Colors)
@@ -263,7 +263,7 @@ void SourceCoverageViewText::renderRegionMarkers(raw_ostream &OS,
 
     if (getOptions().Debug)
       errs() << "Marker at " << S->Line << ":" << S->Col << " = "
-            << formatCount(S->Count) << "\n";
+             << formatCount1(S->Count) << "\n";
   }
   OS << '\n';
 }
@@ -307,7 +307,7 @@ void SourceCoverageViewText::renderBranchView(raw_ostream &OS, BranchView &BRV,
         << Label;
 
     if (getOptions().ShowBranchCounts)
-      OS << ": " << formatCount(Count);
+      OS << ": " << formatCount1(Count);
     else
       OS << ": " << format("%0.2f", (Total != 0 ? 100.0 * Count / Total : 0.0))
          << "%";

>From ed700c2cb5b7ceac1bcf5ac0414a11d3148b9990 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Sat, 21 Dec 2024 17:49:06 +0900
Subject: [PATCH 27/72] s/replace/subst/

---
 llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h | 6 +++---
 llvm/lib/ProfileData/Coverage/CoverageMapping.cpp        | 7 +++----
 2 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index a55ca997d47fd..dad5f1276f27c 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -215,10 +215,10 @@ class CounterExpressionBuilder {
   /// LHS.
   Counter subtract(Counter LHS, Counter RHS, bool Simplify = true);
 
-  using ReplaceMap = std::map<Counter, Counter>;
+  using SubstMap = std::map<Counter, Counter>;
 
-  /// Return a counter for each term in the expression replaced by ReplaceMap.
-  Counter replace(Counter C, const ReplaceMap &Map);
+  /// Return a counter for each term in the expression replaced by SubstMap.
+  Counter subst(Counter C, const SubstMap &Map);
 };
 
 using LineColPair = std::pair<unsigned, unsigned>;
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index 6d6f03c360639..3f89414bdbbb9 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -135,7 +135,7 @@ Counter CounterExpressionBuilder::subtract(Counter LHS, Counter RHS,
   return Simplify ? simplify(Cnt) : Cnt;
 }
 
-Counter CounterExpressionBuilder::replace(Counter C, const ReplaceMap &Map) {
+Counter CounterExpressionBuilder::subst(Counter C, const SubstMap &Map) {
   // Replace C with the value found in Map even if C is Expression.
   if (auto I = Map.find(C); I != Map.end())
     return I->second;
@@ -143,10 +143,9 @@ Counter CounterExpressionBuilder::replace(Counter C, const ReplaceMap &Map) {
   if (!C.isExpression())
     return C;
 
-  // Traverse both sides of Expression.
   auto CE = Expressions[C.getExpressionID()];
-  auto NewLHS = replace(CE.LHS, Map);
-  auto NewRHS = replace(CE.RHS, Map);
+  auto NewLHS = subst(CE.LHS, Map);
+  auto NewRHS = subst(CE.RHS, Map);
 
   // Reconstruct Expression with induced subexpressions.
   switch (CE.Kind) {

>From 5b6c0b02c00fb861877e8a35cdf9842b76e33f2c Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Sat, 21 Dec 2024 17:53:19 +0900
Subject: [PATCH 28/72] LLVMCoverage: Unify getCoverageForFile and
 getCoverageForFunction

---
 .../ProfileData/Coverage/CoverageMapping.h    |  3 +
 .../ProfileData/Coverage/CoverageMapping.cpp  | 77 ++++++++++---------
 2 files changed, 43 insertions(+), 37 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index 42da188fef34e..be902a20efc47 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -889,6 +889,7 @@ class InstantiationGroup {
 class CoverageData {
   friend class CoverageMapping;
 
+protected:
   std::string Filename;
   std::vector<CoverageSegment> Segments;
   std::vector<ExpansionRecord> Expansions;
@@ -900,6 +901,8 @@ class CoverageData {
 
   CoverageData(StringRef Filename) : Filename(Filename) {}
 
+  CoverageData(CoverageData &&RHS) = default;
+
   /// Get the name of the file this data covers.
   StringRef getFilename() const { return Filename; }
 
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index d51448567539f..c6756fafb268a 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -1343,6 +1343,36 @@ class SegmentBuilder {
   }
 };
 
+struct MergeableCoverageData : public CoverageData {
+  std::vector<CountedRegion> CodeRegions;
+
+  MergeableCoverageData(StringRef Filename) : CoverageData(Filename) {}
+
+  void addFunctionRegions(
+      const FunctionRecord &Function,
+      std::function<bool(const CounterMappingRegion &CR)> shouldProcess,
+      std::function<bool(const CountedRegion &CR)> shouldExpand) {
+    for (const auto &CR : Function.CountedRegions)
+      if (shouldProcess(CR)) {
+        CodeRegions.push_back(CR);
+        if (shouldExpand(CR))
+          Expansions.emplace_back(CR, Function);
+      }
+    // Capture branch regions specific to the function (excluding expansions).
+    for (const auto &CR : Function.CountedBranchRegions)
+      if (shouldProcess(CR))
+        BranchRegions.push_back(CR);
+    // Capture MCDC records specific to the function.
+    for (const auto &MR : Function.MCDCRecords)
+      if (shouldProcess(MR.getDecisionRegion()))
+        MCDCRecords.push_back(MR);
+  }
+
+  CoverageData buildSegments() {
+    Segments = SegmentBuilder::buildSegments(CodeRegions);
+    return CoverageData(std::move(*this));
+  }
+};
 } // end anonymous namespace
 
 std::vector<StringRef> CoverageMapping::getUniqueSourceFiles() const {
@@ -1393,8 +1423,7 @@ static bool isExpansion(const CountedRegion &R, unsigned FileID) {
 }
 
 CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) const {
-  CoverageData FileCoverage(Filename);
-  std::vector<CountedRegion> Regions;
+  MergeableCoverageData FileCoverage(Filename);
 
   // Look up the function records in the given file. Due to hash collisions on
   // the filename, we may get back some records that are not in the file.
@@ -1404,26 +1433,14 @@ CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) const {
     const FunctionRecord &Function = Functions[RecordIndex];
     auto MainFileID = findMainViewFileID(Filename, Function);
     auto FileIDs = gatherFileIDs(Filename, Function);
-    for (const auto &CR : Function.CountedRegions)
-      if (FileIDs.test(CR.FileID)) {
-        Regions.push_back(CR);
-        if (MainFileID && isExpansion(CR, *MainFileID))
-          FileCoverage.Expansions.emplace_back(CR, Function);
-      }
-    // Capture branch regions specific to the function (excluding expansions).
-    for (const auto &CR : Function.CountedBranchRegions)
-      if (FileIDs.test(CR.FileID))
-        FileCoverage.BranchRegions.push_back(CR);
-    // Capture MCDC records specific to the function.
-    for (const auto &MR : Function.MCDCRecords)
-      if (FileIDs.test(MR.getDecisionRegion().FileID))
-        FileCoverage.MCDCRecords.push_back(MR);
+    FileCoverage.addFunctionRegions(
+        Function, [&](auto &CR) { return FileIDs.test(CR.FileID); },
+        [&](auto &CR) { return (MainFileID && isExpansion(CR, *MainFileID)); });
   }
 
   LLVM_DEBUG(dbgs() << "Emitting segments for file: " << Filename << "\n");
-  FileCoverage.Segments = SegmentBuilder::buildSegments(Regions);
 
-  return FileCoverage;
+  return FileCoverage.buildSegments();
 }
 
 std::vector<InstantiationGroup>
@@ -1457,29 +1474,15 @@ CoverageMapping::getCoverageForFunction(const FunctionRecord &Function) const {
   if (!MainFileID)
     return CoverageData();
 
-  CoverageData FunctionCoverage(Function.Filenames[*MainFileID]);
-  std::vector<CountedRegion> Regions;
-  for (const auto &CR : Function.CountedRegions)
-    if (CR.FileID == *MainFileID) {
-      Regions.push_back(CR);
-      if (isExpansion(CR, *MainFileID))
-        FunctionCoverage.Expansions.emplace_back(CR, Function);
-    }
-  // Capture branch regions specific to the function (excluding expansions).
-  for (const auto &CR : Function.CountedBranchRegions)
-    if (CR.FileID == *MainFileID)
-      FunctionCoverage.BranchRegions.push_back(CR);
-
-  // Capture MCDC records specific to the function.
-  for (const auto &MR : Function.MCDCRecords)
-    if (MR.getDecisionRegion().FileID == *MainFileID)
-      FunctionCoverage.MCDCRecords.push_back(MR);
+  MergeableCoverageData FunctionCoverage(Function.Filenames[*MainFileID]);
+  FunctionCoverage.addFunctionRegions(
+      Function, [&](auto &CR) { return (CR.FileID == *MainFileID); },
+      [&](auto &CR) { return isExpansion(CR, *MainFileID); });
 
   LLVM_DEBUG(dbgs() << "Emitting segments for function: " << Function.Name
                     << "\n");
-  FunctionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
 
-  return FunctionCoverage;
+  return FunctionCoverage.buildSegments();
 }
 
 CoverageData CoverageMapping::getCoverageForExpansion(

>From dbcf896f38c4c950abd23bf5fe8b9dff75476fef Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Sat, 21 Dec 2024 18:06:25 +0900
Subject: [PATCH 29/72] getSwitchImplicitDefaultCounterPair

---
 clang/lib/CodeGen/CoverageMappingGen.cpp | 27 ++++++++++++------------
 1 file changed, 13 insertions(+), 14 deletions(-)

diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index e63c38fcd4ba2..dff804fbeee92 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -944,12 +944,18 @@ struct CounterCoverageMappingBuilder
     return {ExecCnt, Builder.subtract(ParentCnt, ExecCnt)};
   }
 
-  Counter getSwitchImplicitDefaultCounter(const Stmt *Cond, Counter ParentCount,
-                                          Counter CaseCountSum) {
-    if (llvm::EnableSingleByteCoverage)
-      CaseCountSum = Counter::getZero();
+  /// Returns {TrueCnt,FalseCnt} for "implicit default".
+  /// FalseCnt is considered as the False count on SwitchStmt.
+  std::pair<Counter, Counter>
+  getSwitchImplicitDefaultCounterPair(const Stmt *Cond, Counter ParentCount,
+                                      Counter CaseCountSum) {
+    // Simplify is skipped while building the counters above: it can get
+    // really slow on top of switches with thousands of cases. Instead,
+    // trigger simplification by adding zero to the last counter.
+    CaseCountSum =
+        addCounters(CaseCountSum, Counter::getZero(), /*Simplify=*/true);
 
-    return Builder.subtract(ParentCount, CaseCountSum);
+    return {CaseCountSum, Builder.subtract(ParentCount, CaseCountSum)};
   }
 
   bool IsCounterEqual(Counter OutCount, Counter ParentCount) {
@@ -1910,16 +1916,9 @@ struct CounterCoverageMappingBuilder
     // the hidden branch, which will be added later by the CodeGen. This region
     // will be associated with the switch statement's condition.
     if (!HasDefaultCase) {
-      // Simplify is skipped while building the counters above: it can get
-      // really slow on top of switches with thousands of cases. Instead,
-      // trigger simplification by adding zero to the last counter.
-      CaseCountSum =
-          addCounters(CaseCountSum, Counter::getZero(), /*Simplify=*/true);
-
-      // This is considered as the False count on SwitchStmt.
-      Counter SwitchFalse = getSwitchImplicitDefaultCounter(
+      auto Counters = getSwitchImplicitDefaultCounterPair(
           S->getCond(), ParentCount, CaseCountSum);
-      createBranchRegion(S->getCond(), CaseCountSum, SwitchFalse);
+      createBranchRegion(S->getCond(), Counters.first, Counters.second);
     }
   }
 

>From c0785e91103db81b53e000834ce748d8d448e5ef Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Sat, 21 Dec 2024 21:31:20 +0900
Subject: [PATCH 30/72] Fold either in switchcase

---
 clang/lib/CodeGen/CoverageMappingGen.cpp | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index 238235f72d731..c66280c98e80d 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -964,6 +964,10 @@ struct CounterCoverageMappingBuilder
   std::pair<Counter, Counter>
   getSwitchImplicitDefaultCounterPair(const Stmt *Cond, Counter ParentCount,
                                       Counter CaseCountSum) {
+    if (llvm::EnableSingleByteCoverage)
+      return {Counter::getZero(), // Folded
+              Counter::getCounter(CounterMap[Cond].second = NextCounterNum++)};
+
     // Simplify is skipped while building the counters above: it can get
     // really slow on top of switches with thousands of cases. Instead,
     // trigger simplification by adding zero to the last counter.
@@ -1195,12 +1199,14 @@ struct CounterCoverageMappingBuilder
   /// and add it to the function's SourceRegions.
   /// Returns Counter that corresponds to SC.
   Counter createSwitchCaseRegion(const SwitchCase *SC, Counter ParentCount) {
+    Counter TrueCnt = getRegionCounter(SC);
+    Counter FalseCnt = (llvm::EnableSingleByteCoverage
+                            ? Counter::getZero() // Folded
+                            : subtractCounters(ParentCount, TrueCnt));
     // Push region onto RegionStack but immediately pop it (which adds it to
     // the function's SourceRegions) because it doesn't apply to any other
     // source other than the SwitchCase.
-    Counter TrueCnt = getRegionCounter(SC);
-    popRegions(pushRegion(TrueCnt, getStart(SC), SC->getColonLoc(),
-                          subtractCounters(ParentCount, TrueCnt)));
+    popRegions(pushRegion(TrueCnt, getStart(SC), SC->getColonLoc(), FalseCnt));
     return TrueCnt;
   }
 

>From 24457a7236f5dc76e49c78817b5a0de6ce4f7f93 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Sun, 22 Dec 2024 00:42:02 +0900
Subject: [PATCH 31/72] Update tests

---
 llvm/test/tools/llvm-cov/Inputs/branch-logical-mixed.cpp | 2 +-
 llvm/test/tools/llvm-cov/branch-macros.test              | 2 +-
 llvm/test/tools/llvm-cov/showLineExecutionCounts.test    | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/test/tools/llvm-cov/Inputs/branch-logical-mixed.cpp b/llvm/test/tools/llvm-cov/Inputs/branch-logical-mixed.cpp
index 246b0389aa600..cce61784f9c48 100644
--- a/llvm/test/tools/llvm-cov/Inputs/branch-logical-mixed.cpp
+++ b/llvm/test/tools/llvm-cov/Inputs/branch-logical-mixed.cpp
@@ -4,7 +4,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-// CHECK: |{{ +}}[[C4:4|1]]|void func(
+// CHECK: | [[#min(C,4)]]|void func(
 void func(int a, int b) {
   bool b0 = a <= b;
   bool b1 = a == b;
diff --git a/llvm/test/tools/llvm-cov/branch-macros.test b/llvm/test/tools/llvm-cov/branch-macros.test
index 0a94e63608227..e4bd14ec14f16 100644
--- a/llvm/test/tools/llvm-cov/branch-macros.test
+++ b/llvm/test/tools/llvm-cov/branch-macros.test
@@ -4,7 +4,7 @@
 
 // RUN: yaml2obj %S/Inputs/branch-macros-single.yaml -o %t.o
 // RUN: llvm-profdata merge %S/Inputs/branch-macros-single.proftext -o %t.profdata
-// RUN: llvm-cov show --show-expansions --show-branches=count %t.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck %S/Inputs/branch-macros.cpp -D#C=999
+// RUN: llvm-cov show --show-expansions --show-branches=count %t.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck %S/Inputs/branch-macros.cpp -D#C=1
 
 // REPORT:      Name                        Regions    Miss   Cover     Lines    Miss   Cover  Branches    Miss   Cover
 // REPORT-NEXT: ---
diff --git a/llvm/test/tools/llvm-cov/showLineExecutionCounts.test b/llvm/test/tools/llvm-cov/showLineExecutionCounts.test
index 63a49341e6c17..4f505f9648eb8 100644
--- a/llvm/test/tools/llvm-cov/showLineExecutionCounts.test
+++ b/llvm/test/tools/llvm-cov/showLineExecutionCounts.test
@@ -46,5 +46,5 @@
 // RUN: yaml2obj %S/Inputs/showLineExecutionCounts-single.yaml -o %t.o
 // RUN: llvm-profdata merge %S/Inputs/showLineExecutionCounts-single.proftext -o %t.profdata
 
-// RUN: llvm-cov show %t.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck -check-prefixes=TEXT,WHOLE-FILE -D#C=161 -DC16K2=161 -DC16K1=161 %S/Inputs/showLineExecutionCounts.cpp
-// RUN: llvm-cov show %t.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs -name=main | FileCheck -check-prefixes=TEXT,FILTER -D#C=161 -DC16K2=161 -DC16K1=161 %S/Inputs/showLineExecutionCounts.cpp
+// RUN: llvm-cov show %t.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs | FileCheck -check-prefixes=TEXT,WHOLE-FILE -D#C=1 -DC16K2=1 -DC16K1=1 %S/Inputs/showLineExecutionCounts.cpp
+// RUN: llvm-cov show %t.o -instr-profile %t.profdata -path-equivalence=.,%S/Inputs -name=main | FileCheck -check-prefixes=TEXT,FILTER -D#C=1 -DC16K2=1 -DC16K1=1 %S/Inputs/showLineExecutionCounts.cpp

>From f96b435e3c762fd6ae94eced63862289538b2a21 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Sun, 22 Dec 2024 00:48:52 +0900
Subject: [PATCH 32/72] New SingleByteCoverage

---
 .../ProfileData/Coverage/CoverageMapping.h    | 34 +++++++++++--------
 .../ProfileData/Coverage/CoverageMapping.cpp  | 31 +++++++----------
 llvm/tools/llvm-cov/SourceCoverageView.h      |  3 +-
 3 files changed, 33 insertions(+), 35 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index 42da188fef34e..42aea623be165 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -364,19 +364,16 @@ struct CountedRegion : public CounterMappingRegion {
   uint64_t FalseExecutionCount;
   bool TrueFolded;
   bool FalseFolded;
-  bool HasSingleByteCoverage;
 
-  CountedRegion(const CounterMappingRegion &R, uint64_t ExecutionCount,
-                bool HasSingleByteCoverage)
+  CountedRegion(const CounterMappingRegion &R, uint64_t ExecutionCount)
       : CounterMappingRegion(R), ExecutionCount(ExecutionCount),
-        FalseExecutionCount(0), TrueFolded(false), FalseFolded(true),
-        HasSingleByteCoverage(HasSingleByteCoverage) {}
+        FalseExecutionCount(0), TrueFolded(false), FalseFolded(true) {}
 
   CountedRegion(const CounterMappingRegion &R, uint64_t ExecutionCount,
-                uint64_t FalseExecutionCount, bool HasSingleByteCoverage)
+                uint64_t FalseExecutionCount)
       : CounterMappingRegion(R), ExecutionCount(ExecutionCount),
         FalseExecutionCount(FalseExecutionCount), TrueFolded(false),
-        FalseFolded(false), HasSingleByteCoverage(HasSingleByteCoverage) {}
+        FalseFolded(false) {}
 };
 
 /// MCDC Record grouping all information together.
@@ -719,10 +716,9 @@ struct FunctionRecord {
   }
 
   void pushRegion(CounterMappingRegion Region, uint64_t Count,
-                  uint64_t FalseCount, bool HasSingleByteCoverage) {
+                  uint64_t FalseCount) {
     if (Region.isBranch()) {
-      CountedBranchRegions.emplace_back(Region, Count, FalseCount,
-                                        HasSingleByteCoverage);
+      CountedBranchRegions.emplace_back(Region, Count, FalseCount);
       // If either counter is hard-coded to zero, then this region represents a
       // constant-folded branch.
       CountedBranchRegions.back().TrueFolded = Region.Count.isZero();
@@ -731,8 +727,7 @@ struct FunctionRecord {
     }
     if (CountedRegions.empty())
       ExecutionCount = Count;
-    CountedRegions.emplace_back(Region, Count, FalseCount,
-                                HasSingleByteCoverage);
+    CountedRegions.emplace_back(Region, Count, FalseCount);
   }
 };
 
@@ -895,14 +890,19 @@ class CoverageData {
   std::vector<CountedRegion> BranchRegions;
   std::vector<MCDCRecord> MCDCRecords;
 
+  bool SingleByteCoverage;
+
 public:
-  CoverageData() = default;
+  CoverageData() = delete;
 
-  CoverageData(StringRef Filename) : Filename(Filename) {}
+  CoverageData(bool Single, StringRef Filename = StringRef())
+      : Filename(Filename), SingleByteCoverage(Single) {}
 
   /// Get the name of the file this data covers.
   StringRef getFilename() const { return Filename; }
 
+  bool getSingleByteCoverage() const { return SingleByteCoverage; }
+
   /// Get an iterator over the coverage segments for this object. The segments
   /// are guaranteed to be uniqued and sorted by location.
   std::vector<CoverageSegment>::const_iterator begin() const {
@@ -935,7 +935,9 @@ class CoverageMapping {
   DenseMap<size_t, SmallVector<unsigned, 0>> FilenameHash2RecordIndices;
   std::vector<std::pair<std::string, uint64_t>> FuncHashMismatches;
 
-  CoverageMapping() = default;
+  bool SingleByteCoverage;
+
+  CoverageMapping(bool Single) : SingleByteCoverage(Single) {}
 
   // Load coverage records from readers.
   static Error loadFromReaders(
@@ -979,6 +981,8 @@ class CoverageMapping {
        const object::BuildIDFetcher *BIDFetcher = nullptr,
        bool CheckBinaryIDs = false);
 
+  bool getSingleByteCoverage() const { return SingleByteCoverage; }
+
   /// The number of functions that couldn't have their profiles mapped.
   ///
   /// This is a count of functions whose profile is out of date or otherwise
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index 87d8bb1bbb79c..430e68ea94a02 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -805,7 +805,6 @@ Error CoverageMapping::loadFunctionRecord(
   else
     OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName, Record.Filenames[0]);
 
-  bool SingleByteCoverage = ProfileReader.hasSingleByteCoverage();
   CounterMappingContext Ctx(Record.Expressions);
 
   std::vector<uint64_t> Counts;
@@ -871,10 +870,7 @@ Error CoverageMapping::loadFunctionRecord(
       consumeError(std::move(E));
       return Error::success();
     }
-    Function.pushRegion(
-        Region, (SingleByteCoverage && *ExecutionCount ? 1 : *ExecutionCount),
-        (SingleByteCoverage && *AltExecutionCount ? 1 : *AltExecutionCount),
-        SingleByteCoverage);
+    Function.pushRegion(Region, *ExecutionCount, *AltExecutionCount);
 
     // Record ExpansionRegion.
     if (Region.Kind == CounterMappingRegion::ExpansionRegion) {
@@ -951,7 +947,8 @@ Error CoverageMapping::loadFromReaders(
 Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
     ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
     IndexedInstrProfReader &ProfileReader) {
-  auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping());
+  auto Coverage = std::unique_ptr<CoverageMapping>(
+      new CoverageMapping(ProfileReader.hasSingleByteCoverage()));
   if (Error E = loadFromReaders(CoverageReaders, ProfileReader, *Coverage))
     return std::move(E);
   return std::move(Coverage);
@@ -1013,7 +1010,8 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
   if (Error E = ProfileReaderOrErr.takeError())
     return createFileError(ProfileFilename, std::move(E));
   auto ProfileReader = std::move(ProfileReaderOrErr.get());
-  auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping());
+  auto Coverage = std::unique_ptr<CoverageMapping>(
+      new CoverageMapping(ProfileReader->hasSingleByteCoverage()));
   bool DataFound = false;
 
   auto GetArch = [&](size_t Idx) {
@@ -1296,14 +1294,8 @@ class SegmentBuilder {
       // value for that area.
       // We add counts of the regions of the same kind as the active region
       // to handle the both situations.
-      if (I->Kind == Active->Kind) {
-        assert(I->HasSingleByteCoverage == Active->HasSingleByteCoverage &&
-               "Regions are generated in different coverage modes");
-        if (I->HasSingleByteCoverage)
-          Active->ExecutionCount = Active->ExecutionCount || I->ExecutionCount;
-        else
-          Active->ExecutionCount += I->ExecutionCount;
-      }
+      if (I->Kind == Active->Kind)
+        Active->ExecutionCount += I->ExecutionCount;
     }
     return Regions.drop_back(std::distance(++Active, End));
   }
@@ -1396,7 +1388,7 @@ static bool isExpansion(const CountedRegion &R, unsigned FileID) {
 }
 
 CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) const {
-  CoverageData FileCoverage(Filename);
+  CoverageData FileCoverage(SingleByteCoverage, Filename);
   std::vector<CountedRegion> Regions;
 
   // Look up the function records in the given file. Due to hash collisions on
@@ -1458,9 +1450,10 @@ CoverageData
 CoverageMapping::getCoverageForFunction(const FunctionRecord &Function) const {
   auto MainFileID = findMainViewFileID(Function);
   if (!MainFileID)
-    return CoverageData();
+    return CoverageData(SingleByteCoverage);
 
-  CoverageData FunctionCoverage(Function.Filenames[*MainFileID]);
+  CoverageData FunctionCoverage(SingleByteCoverage,
+                                Function.Filenames[*MainFileID]);
   std::vector<CountedRegion> Regions;
   for (const auto &CR : Function.CountedRegions)
     if (CR.FileID == *MainFileID) {
@@ -1488,7 +1481,7 @@ CoverageMapping::getCoverageForFunction(const FunctionRecord &Function) const {
 CoverageData CoverageMapping::getCoverageForExpansion(
     const ExpansionRecord &Expansion) const {
   CoverageData ExpansionCoverage(
-      Expansion.Function.Filenames[Expansion.FileID]);
+      SingleByteCoverage, Expansion.Function.Filenames[Expansion.FileID]);
   std::vector<CountedRegion> Regions;
   for (const auto &CR : Expansion.Function.CountedRegions)
     if (CR.FileID == Expansion.FileID) {
diff --git a/llvm/tools/llvm-cov/SourceCoverageView.h b/llvm/tools/llvm-cov/SourceCoverageView.h
index 9b72ca03c6d7f..ed7e133d71e08 100644
--- a/llvm/tools/llvm-cov/SourceCoverageView.h
+++ b/llvm/tools/llvm-cov/SourceCoverageView.h
@@ -283,7 +283,8 @@ class SourceCoverageView {
                      CoverageData &&CoverageInfo)
       : SourceName(SourceName), File(File), Options(Options),
         CoverageInfo(std::move(CoverageInfo)),
-        BinaryCounters(Options.BinaryCounters) {}
+        BinaryCounters(Options.BinaryCounters ||
+                       CoverageInfo.getSingleByteCoverage()) {}
 
 public:
   static std::unique_ptr<SourceCoverageView>

>From 47550d1cc07ba6407020d2a9417bb48bdc3a5156 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Sun, 22 Dec 2024 11:32:00 +0900
Subject: [PATCH 33/72] threads.c => threads.test (following #113114)

---
 llvm/test/tools/llvm-cov/threads.c    | 11 -----------
 llvm/test/tools/llvm-cov/threads.test | 12 ++++++++++++
 2 files changed, 12 insertions(+), 11 deletions(-)
 delete mode 100644 llvm/test/tools/llvm-cov/threads.c
 create mode 100644 llvm/test/tools/llvm-cov/threads.test

diff --git a/llvm/test/tools/llvm-cov/threads.c b/llvm/test/tools/llvm-cov/threads.c
deleted file mode 100644
index b162b6ac5a801..0000000000000
--- a/llvm/test/tools/llvm-cov/threads.c
+++ /dev/null
@@ -1,11 +0,0 @@
-// Coverage/profile data recycled from the showLineExecutionCounts.cpp test.
-//
-// RUN: llvm-profdata merge %S/Inputs/lineExecutionCounts.proftext -o %t.profdata
-// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -j 1 -o %t1.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S %S/showLineExecutionCounts.cpp
-// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -num-threads 2 -o %t2.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S %S/showLineExecutionCounts.cpp
-// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -o %t3.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S %S/showLineExecutionCounts.cpp
-//
-// RUN: diff %t1.dir/index.txt %t2.dir/index.txt
-// RUN: diff %t1.dir/coverage/tmp/showLineExecutionCounts.cpp.txt %t2.dir/coverage/tmp/showLineExecutionCounts.cpp.txt
-// RUN: diff %t1.dir/index.txt %t3.dir/index.txt
-// RUN: diff %t1.dir/coverage/tmp/showLineExecutionCounts.cpp.txt %t3.dir/coverage/tmp/showLineExecutionCounts.cpp.txt
diff --git a/llvm/test/tools/llvm-cov/threads.test b/llvm/test/tools/llvm-cov/threads.test
new file mode 100644
index 0000000000000..a51406ca14efa
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/threads.test
@@ -0,0 +1,12 @@
+// Coverage/profile data recycled from the showLineExecutionCounts.cpp test.
+//
+// RUN: rm -rf %t.dir
+// RUN: llvm-profdata merge %S/Inputs/lineExecutionCounts.proftext -o %t.profdata
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -j 1 -o %t.dir/1 -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -num-threads 2 -o %t.dir/2 -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs
+// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -o %t.dir/3 -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs
+//
+// RUN: diff %t.dir/1/index.txt %t.dir/2/index.txt
+// RUN: diff %t.dir/1/coverage/tmp/showLineExecutionCounts.cpp.txt %t.dir/2/coverage/tmp/showLineExecutionCounts.cpp.txt
+// RUN: diff %t.dir/1/index.txt %t.dir/3/index.txt
+// RUN: diff %t.dir/1/coverage/tmp/showLineExecutionCounts.cpp.txt %t.dir/3/coverage/tmp/showLineExecutionCounts.cpp.txt

>From bd1d96bb23b264f4976ce800470dd7ed7f74a709 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Mon, 23 Dec 2024 12:26:29 +0900
Subject: [PATCH 34/72] Introduce CounterMappingRegion::isBranch(). NFC.

Conflicts:
	clang/lib/CodeGen/CoverageMappingGen.cpp
	llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
---
 llvm/lib/ProfileData/Coverage/CoverageMapping.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index 63be03f231841..b2f4087465308 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -637,8 +637,7 @@ static unsigned getMaxCounterID(const CounterMappingContext &Ctx,
   unsigned MaxCounterID = 0;
   for (const auto &Region : Record.MappingRegions) {
     MaxCounterID = std::max(MaxCounterID, Ctx.getMaxCounterID(Region.Count));
-    if (Region.Kind == CounterMappingRegion::BranchRegion ||
-        Region.Kind == CounterMappingRegion::MCDCBranchRegion)
+    if (Region.isBranch())
       MaxCounterID =
           std::max(MaxCounterID, Ctx.getMaxCounterID(Region.FalseCount));
   }

>From f4dc4ebfd585869455be0e9f37294b7037ca9a65 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Mon, 23 Dec 2024 15:57:36 +0900
Subject: [PATCH 35/72] s/Count1/BinaryCount/

---
 llvm/tools/llvm-cov/SourceCoverageView.h       | 8 ++++++--
 llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp | 8 ++++----
 llvm/tools/llvm-cov/SourceCoverageViewText.cpp | 6 +++---
 3 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/llvm/tools/llvm-cov/SourceCoverageView.h b/llvm/tools/llvm-cov/SourceCoverageView.h
index 9b72ca03c6d7f..0b4e3978a4ba9 100644
--- a/llvm/tools/llvm-cov/SourceCoverageView.h
+++ b/llvm/tools/llvm-cov/SourceCoverageView.h
@@ -268,9 +268,13 @@ class SourceCoverageView {
   /// digits.
   static std::string formatCount(uint64_t N);
 
-  uint64_t Count1(uint64_t N) const { return (N && BinaryCounters ? 1 : N); }
+  uint64_t BinaryCount(uint64_t N) const {
+    return (N && BinaryCounters ? 1 : N);
+  }
 
-  std::string formatCount1(uint64_t N) const { return formatCount(Count1(N)); }
+  std::string formatBinaryCount(uint64_t N) const {
+    return formatCount(BinaryCount(N));
+  }
 
   /// Check if region marker output is expected for a line.
   bool shouldRenderRegionMarkers(const LineCoverageStats &LCS) const;
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
index f3aa7e801597c..c94d3853fc014 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
@@ -1019,8 +1019,8 @@ void SourceCoverageViewHTML::renderLine(raw_ostream &OS, LineRef L,
     // Just consider the segments which start *and* end on this line.
     for (unsigned I = 0, E = Segments.size() - 1; I < E; ++I) {
       const auto *CurSeg = Segments[I];
-      auto CurSegCount = Count1(CurSeg->Count);
-      auto LCSCount = Count1(LCS.getExecutionCount());
+      auto CurSegCount = BinaryCount(CurSeg->Count);
+      auto LCSCount = BinaryCount(LCS.getExecutionCount());
       if (!CurSeg->IsRegionEntry)
         continue;
       if (CurSegCount == LCSCount)
@@ -1054,7 +1054,7 @@ void SourceCoverageViewHTML::renderLineCoverageColumn(
     raw_ostream &OS, const LineCoverageStats &Line) {
   std::string Count;
   if (Line.isMapped())
-    Count = tag("pre", formatCount1(Line.getExecutionCount()));
+    Count = tag("pre", formatBinaryCount(Line.getExecutionCount()));
   std::string CoverageClass =
       (Line.getExecutionCount() > 0)
           ? "covered-line"
@@ -1109,7 +1109,7 @@ void SourceCoverageViewHTML::renderBranchView(raw_ostream &OS, BranchView &BRV,
 
     OS << tag("span", Label, (Count ? "None" : "red branch")) << ": ";
     if (getOptions().ShowBranchCounts)
-      OS << tag("span", formatCount1(Count),
+      OS << tag("span", formatBinaryCount(Count),
                 (Count ? "covered-line" : "uncovered-line"));
     else
       OS << format("%0.2f", (Total != 0 ? 100.0 * Count / Total : 0.0)) << "%";
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
index f0c366e45c2c9..765f8bbbd8d1b 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp
@@ -216,7 +216,7 @@ void SourceCoverageViewText::renderLineCoverageColumn(
     OS.indent(LineCoverageColumnWidth) << '|';
     return;
   }
-  std::string C = formatCount1(Line.getExecutionCount());
+  std::string C = formatBinaryCount(Line.getExecutionCount());
   OS.indent(LineCoverageColumnWidth - C.size());
   colored_ostream(OS, raw_ostream::MAGENTA,
                   Line.hasMultipleRegions() && getOptions().Colors)
@@ -263,7 +263,7 @@ void SourceCoverageViewText::renderRegionMarkers(raw_ostream &OS,
 
     if (getOptions().Debug)
       errs() << "Marker at " << S->Line << ":" << S->Col << " = "
-             << formatCount1(S->Count) << "\n";
+             << formatBinaryCount(S->Count) << "\n";
   }
   OS << '\n';
 }
@@ -307,7 +307,7 @@ void SourceCoverageViewText::renderBranchView(raw_ostream &OS, BranchView &BRV,
         << Label;
 
     if (getOptions().ShowBranchCounts)
-      OS << ": " << formatCount1(Count);
+      OS << ": " << formatBinaryCount(Count);
     else
       OS << ": " << format("%0.2f", (Total != 0 ? 100.0 * Count / Total : 0.0))
          << "%";

>From 822620bea235792675202045b2b7d138aa069f0e Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Mon, 23 Dec 2024 15:55:49 +0900
Subject: [PATCH 36/72] Update desc

---
 llvm/tools/llvm-cov/CodeCoverage.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp
index 0e8360a4ac6ed..2d6da7efc6979 100644
--- a/llvm/tools/llvm-cov/CodeCoverage.cpp
+++ b/llvm/tools/llvm-cov/CodeCoverage.cpp
@@ -1025,7 +1025,8 @@ int CodeCoverageTool::doShow(int argc, const char **argv,
 
   cl::opt<bool> BinaryCounters(
       "binary-counters", cl::Optional,
-      cl::desc("Show 1/0 instead of actual counter values."),
+      cl::desc("Show when lines/branches are covered (1) or uncovered (0) "
+               "instead of showing actual counter values."),
       cl::cat(ViewCategory));
 
   cl::opt<uint32_t> TabSize(

>From 4e41b99fdf41094a85bf473d27d57c527b91a0d8 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Tue, 24 Dec 2024 15:53:14 +0900
Subject: [PATCH 37/72] Introduce BranchCounterPair

---
 clang/lib/CodeGen/CoverageMappingGen.cpp | 24 ++++++++++++++----------
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index dff804fbeee92..df29c2cb4ee17 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -938,8 +938,12 @@ struct CounterCoverageMappingBuilder
     return Counter::getCounter(CounterMap[S]);
   }
 
-  std::pair<Counter, Counter> getBranchCounterPair(const Stmt *S,
-                                                   Counter ParentCnt) {
+  struct BranchCounterPair {
+    Counter Executed;
+    Counter Skipped;
+  };
+
+  BranchCounterPair getBranchCounterPair(const Stmt *S, Counter ParentCnt) {
     Counter ExecCnt = getRegionCounter(S);
     return {ExecCnt, Builder.subtract(ParentCnt, ExecCnt)};
   }
@@ -1617,7 +1621,7 @@ struct CounterCoverageMappingBuilder
             : addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
     auto [ExecCount, ExitCount] =
         (llvm::EnableSingleByteCoverage
-             ? std::make_pair(getRegionCounter(S), Counter::getZero())
+             ? BranchCounterPair{getRegionCounter(S), Counter::getZero()}
              : getBranchCounterPair(S, CondCount));
     if (!llvm::EnableSingleByteCoverage) {
       assert(ExecCount.isZero() || ExecCount == BodyCount);
@@ -1674,7 +1678,7 @@ struct CounterCoverageMappingBuilder
                             : addCounters(BackedgeCount, BC.ContinueCount);
     auto [ExecCount, ExitCount] =
         (llvm::EnableSingleByteCoverage
-             ? std::make_pair(getRegionCounter(S), Counter::getZero())
+             ? BranchCounterPair{getRegionCounter(S), Counter::getZero()}
              : getBranchCounterPair(S, CondCount));
     if (!llvm::EnableSingleByteCoverage) {
       assert(ExecCount.isZero() || ExecCount == BodyCount);
@@ -1742,7 +1746,7 @@ struct CounterCoverageMappingBuilder
                   IncrementBC.ContinueCount);
     auto [ExecCount, ExitCount] =
         (llvm::EnableSingleByteCoverage
-             ? std::make_pair(getRegionCounter(S), Counter::getZero())
+             ? BranchCounterPair{getRegionCounter(S), Counter::getZero()}
              : getBranchCounterPair(S, CondCount));
     if (!llvm::EnableSingleByteCoverage) {
       assert(ExecCount.isZero() || ExecCount == BodyCount);
@@ -2049,9 +2053,9 @@ struct CounterCoverageMappingBuilder
     Counter ParentCount = getRegion().getCounter();
     auto [ThenCount, ElseCount] =
         (llvm::EnableSingleByteCoverage
-             ? std::make_pair(getRegionCounter(S->getThen()),
-                              (S->getElse() ? getRegionCounter(S->getElse())
-                                            : Counter::getZero()))
+             ? BranchCounterPair{getRegionCounter(S->getThen()),
+                                 (S->getElse() ? getRegionCounter(S->getElse())
+                                               : Counter::getZero())}
              : getBranchCounterPair(S, ParentCount));
 
     // Emitting a counter for the condition makes it easier to interpret the
@@ -2124,8 +2128,8 @@ struct CounterCoverageMappingBuilder
     Counter ParentCount = getRegion().getCounter();
     auto [TrueCount, FalseCount] =
         (llvm::EnableSingleByteCoverage
-             ? std::make_pair(getRegionCounter(E->getTrueExpr()),
-                              getRegionCounter(E->getFalseExpr()))
+             ? BranchCounterPair{getRegionCounter(E->getTrueExpr()),
+                                 getRegionCounter(E->getFalseExpr())}
              : getBranchCounterPair(E, ParentCount));
     Counter OutCount;
 

>From 306d77f3d9afdbb832f920e920008c719a3a3533 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Tue, 24 Dec 2024 15:58:13 +0900
Subject: [PATCH 38/72] void verifyCounterMap() const

---
 clang/lib/CodeGen/CodeGenPGO.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CodeGenPGO.h b/clang/lib/CodeGen/CodeGenPGO.h
index 83f35785e5327..9429b6b465207 100644
--- a/clang/lib/CodeGen/CodeGenPGO.h
+++ b/clang/lib/CodeGen/CodeGenPGO.h
@@ -131,7 +131,7 @@ class CodeGenPGO {
     // Do nothing.
   }
 
-  void verifyCounterMap() {
+  void verifyCounterMap() const {
     // Do nothing.
   }
 

>From a4f05c7a5ca60b8ed2eaf5337cdd04bab25e8170 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Tue, 24 Dec 2024 15:58:13 +0900
Subject: [PATCH 39/72] Introduce the dedicated class CounterPair instead of
 std::pair

---
 clang/lib/CodeGen/CodeGenFunction.h      |  4 +-
 clang/lib/CodeGen/CodeGenModule.h        | 53 +++++++++++++++++-------
 clang/lib/CodeGen/CodeGenPGO.cpp         | 11 +++--
 clang/lib/CodeGen/CodeGenPGO.h           |  2 +-
 clang/lib/CodeGen/CoverageMappingGen.cpp |  2 +-
 5 files changed, 50 insertions(+), 22 deletions(-)

diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 0396fa5bef136..87d016a0729ad 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -1620,9 +1620,7 @@ class CodeGenFunction : public CodeGenTypeCache {
                                             uint64_t LoopCount) const;
 
 public:
-  std::pair<bool, bool> getIsCounterPair(const Stmt *S) const {
-    return PGO.getIsCounterPair(S);
-  }
+  auto getIsCounterPair(const Stmt *S) const { return PGO.getIsCounterPair(S); }
 
   void markStmtAsUsed(bool Skipped, const Stmt *S) {
     PGO.markStmtAsUsed(Skipped, S);
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index 8990ee13991e9..d5ef1a710eb40 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -102,23 +102,48 @@ enum ForDefinition_t : bool {
   ForDefinition = true
 };
 
-class CounterPair : public std::pair<uint32_t, uint32_t> {
-private:
-  static constexpr uint32_t None = (1u << 31); /// None is set
-
+/// The Counter with an optional additional Counter for
+/// branches. `Skipped` counter can be calculated with `Executed` and
+/// a common Counter (like `Parent`) as `(Parent-Executed)`.
+///
+/// In SingleByte mode, Counters are binary. Subtraction is not
+/// applicable (but addition is capable). In this case, both
+/// `Executed` and `Skipped` counters are required.  `Skipped` is
+/// `None` by default. It is allocated in the coverage mapping.
+///
+/// There might be cases that `Parent` could be induced with
+/// `(Executed+Skipped)`. This is not always applicable.
+class CounterPair {
 public:
-  static constexpr uint32_t Mask = None - 1;
+  /// Optional value.
+  class ValueOpt {
+  private:
+    static constexpr uint32_t None = (1u << 31); /// None is allocated.
+    static constexpr uint32_t Mask = None - 1;
 
-public:
-  CounterPair(unsigned Val = 0) {
-    assert(!(Val & ~Mask));
-    first = Val;
-    second = None;
-  }
+    uint32_t Val;
 
-  std::pair<bool, bool> getIsCounterPair() const {
-    return {!(first & None), !(second & None)};
-  }
+  public:
+    ValueOpt() : Val(None) {}
+
+    ValueOpt(unsigned InitVal) {
+      assert(!(InitVal & ~Mask));
+      Val = InitVal;
+    }
+
+    bool hasValue() const { return !(Val & None); }
+
+    operator uint32_t() const { return Val; }
+  };
+
+  ValueOpt Executed;
+  ValueOpt Skipped; /// May be None.
+
+  /// Initialized with Skipped=None.
+  CounterPair(unsigned Val) : Executed(Val) {}
+
+  // FIXME: Should work with {None, None}
+  CounterPair() : Executed(0) {}
 };
 
 struct OrderGlobalInitsOrStermFinalizers {
diff --git a/clang/lib/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp
index 75191f86d231c..792373839107f 100644
--- a/clang/lib/CodeGen/CodeGenPGO.cpp
+++ b/clang/lib/CodeGen/CodeGenPGO.cpp
@@ -1186,9 +1186,14 @@ CodeGenPGO::applyFunctionAttributes(llvm::IndexedInstrProfReader *PGOReader,
 }
 
 std::pair<bool, bool> CodeGenPGO::getIsCounterPair(const Stmt *S) const {
-  if (!RegionCounterMap || RegionCounterMap->count(S) == 0)
+  if (!RegionCounterMap)
     return {false, false};
-  return (*RegionCounterMap)[S].getIsCounterPair();
+
+  auto I = RegionCounterMap->find(S);
+  if (I == RegionCounterMap->end())
+    return {false, false};
+
+  return {I->second.Executed.hasValue(), I->second.Skipped.hasValue()};
 }
 
 void CodeGenPGO::emitCounterSetOrIncrement(CGBuilderTy &Builder, const Stmt *S,
@@ -1196,7 +1201,7 @@ void CodeGenPGO::emitCounterSetOrIncrement(CGBuilderTy &Builder, const Stmt *S,
   if (!RegionCounterMap || !Builder.GetInsertBlock())
     return;
 
-  unsigned Counter = (*RegionCounterMap)[S].first;
+  unsigned Counter = (*RegionCounterMap)[S].Executed;
 
   // Make sure that pointer to global is passed in with zero addrspace
   // This is relevant during GPU profiling
diff --git a/clang/lib/CodeGen/CodeGenPGO.h b/clang/lib/CodeGen/CodeGenPGO.h
index 9429b6b465207..1944b640951d5 100644
--- a/clang/lib/CodeGen/CodeGenPGO.h
+++ b/clang/lib/CodeGen/CodeGenPGO.h
@@ -143,7 +143,7 @@ class CodeGenPGO {
       return 0;
     // With profiles from a differing version of clang we can have mismatched
     // decl counts. Don't crash in such a case.
-    auto Index = (*RegionCounterMap)[S].first;
+    auto Index = (*RegionCounterMap)[S].Executed;
     if (Index >= RegionCounts.size())
       return 0;
     return RegionCounts[Index];
diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index 9c191e9394769..6433f930ae41e 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -935,7 +935,7 @@ struct CounterCoverageMappingBuilder
   ///
   /// This should only be called on statements that have a dedicated counter.
   Counter getRegionCounter(const Stmt *S) {
-    return Counter::getCounter(CounterMap[S].first);
+    return Counter::getCounter(CounterMap[S].Executed);
   }
 
   /// Push a region onto the stack.

>From f6c5f4017cc48534d2c3adc68a7c3d97ad45d156 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Tue, 24 Dec 2024 16:13:54 +0900
Subject: [PATCH 40/72] Catch up the merge

---
 clang/lib/CodeGen/CodeGenPGO.cpp         | 24 +++++++++++++++-------
 clang/lib/CodeGen/CoverageMappingGen.cpp | 26 +++++++++++++++++++++---
 2 files changed, 40 insertions(+), 10 deletions(-)

diff --git a/clang/lib/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp
index 03856795ca51a..ffb1df9ec2cc6 100644
--- a/clang/lib/CodeGen/CodeGenPGO.cpp
+++ b/clang/lib/CodeGen/CodeGenPGO.cpp
@@ -1140,13 +1140,10 @@ void CodeGenPGO::emitCounterRegionMapping(const Decl *D) {
   // Scan max(FalseCnt) and update NumRegionCounters.
   unsigned MaxNumCounters = NumRegionCounters;
   for (const auto [_, V] : *RegionCounterMap) {
-    auto HasCounters = V.getIsCounterPair();
-    assert((!HasCounters.first ||
-            MaxNumCounters > (V.first & CounterPair::Mask)) &&
+    assert((!V.Executed.hasValue() || MaxNumCounters > V.Executed) &&
            "TrueCnt should not be reassigned");
-    if (HasCounters.second)
-      MaxNumCounters =
-          std::max(MaxNumCounters, (V.second & CounterPair::Mask) + 1);
+    if (V.Skipped.hasValue())
+      MaxNumCounters = std::max(MaxNumCounters, V.Skipped + 1);
   }
   NumRegionCounters = MaxNumCounters;
 
@@ -1215,7 +1212,20 @@ void CodeGenPGO::emitCounterSetOrIncrement(CGBuilderTy &Builder, const Stmt *S,
   if (!RegionCounterMap)
     return;
 
-  unsigned Counter = (*RegionCounterMap)[S].Executed;
+  unsigned Counter;
+  auto &TheMap = (*RegionCounterMap)[S];
+  if (!UseSkipPath) {
+    if (!TheMap.Executed.hasValue())
+      return;
+    Counter = TheMap.Executed;
+  } else {
+    if (!TheMap.Skipped.hasValue())
+      return;
+    Counter = TheMap.Skipped;
+  }
+
+  if (!Builder.GetInsertBlock())
+    return;
 
   // Make sure that pointer to global is passed in with zero addrspace
   // This is relevant during GPU profiling
diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index e0aa752bcbe9a..0764345af0b32 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -943,8 +943,27 @@ struct CounterCoverageMappingBuilder
   };
 
   BranchCounterPair getBranchCounterPair(const Stmt *S, Counter ParentCnt) {
-    Counter ExecCnt = getRegionCounter(S);
-    return {ExecCnt, Builder.subtract(ParentCnt, ExecCnt)};
+    auto &TheMap = CounterMap[S];
+    auto ExecCnt = Counter::getCounter(TheMap.Executed);
+    BranchCounterPair Counters = {ExecCnt,
+                                  Builder.subtract(ParentCnt, ExecCnt)};
+
+    if (!llvm::EnableSingleByteCoverage || !Counters.Skipped.isExpression()) {
+      assert(
+          !TheMap.Skipped.hasValue() &&
+          "SkipCnt shouldn't be allocated but refer to an existing counter.");
+      return Counters;
+    }
+
+    // Assign second if second is not assigned yet.
+    if (!TheMap.Skipped.hasValue())
+      TheMap.Skipped = NextCounterNum++;
+
+    // Replace an expression (ParentCnt - ExecCnt) with SkipCnt.
+    Counter SkipCnt = Counter::getCounter(TheMap.Skipped);
+    MapToExpand[SkipCnt] = Counters.Skipped;
+    Counters.Skipped = SkipCnt;
+    return Counters;
   }
 
   /// Returns {TrueCnt,FalseCnt} for "implicit default".
@@ -953,8 +972,9 @@ struct CounterCoverageMappingBuilder
   getSwitchImplicitDefaultCounterPair(const Stmt *Cond, Counter ParentCount,
                                       Counter CaseCountSum) {
     if (llvm::EnableSingleByteCoverage)
+      // Allocate the new Counter since `subtract(Parent - Sum)` is unavailable.
       return {Counter::getZero(), // Folded
-              Counter::getCounter(CounterMap[Cond].second = NextCounterNum++)};
+              Counter::getCounter(CounterMap[Cond].Skipped = NextCounterNum++)};
 
     // Simplify is skipped while building the counters above: it can get
     // really slow on top of switches with thousands of cases. Instead,

>From aca86d451ab886951a260c171c63c313522266d2 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Tue, 24 Dec 2024 16:13:54 +0900
Subject: [PATCH 41/72] Introduce {UseExecPath, UseSkipPath} instead of {false,
 true}

---
 clang/lib/CodeGen/CodeGenFunction.h | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 425fce241b983..6145c6a627fc8 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -1627,20 +1627,31 @@ class CodeGenFunction : public CodeGenTypeCache {
   }
   void markStmtMaybeUsed(const Stmt *S) { PGO.markStmtMaybeUsed(S); }
 
+  enum CounterForIncrement {
+    UseExecPath = 0,
+    UseSkipPath,
+  };
+
   /// Increment the profiler's counter for the given statement by \p StepV.
   /// If \p StepV is null, the default increment is 1.
   void incrementProfileCounter(const Stmt *S, llvm::Value *StepV = nullptr) {
-    incrementProfileCounter(false, S, false, StepV);
+    incrementProfileCounter(UseExecPath, S, false, StepV);
   }
 
-  void incrementProfileCounter(bool UseSkipPath, const Stmt *S,
+  /// Emit increment of Counter.
+  /// \param ExecSkip Use `Skipped` Counter if UseSkipPath is specified.
+  /// \param S The Stmt that Counter is associated.
+  /// \param UseBoth Mark both Exec/Skip as used. (for verification)
+  /// \param StepV The offset Value for adding to Counter.
+  void incrementProfileCounter(CounterForIncrement ExecSkip, const Stmt *S,
                                bool UseBoth = false,
                                llvm::Value *StepV = nullptr) {
     if (CGM.getCodeGenOpts().hasProfileClangInstr() &&
         !CurFn->hasFnAttribute(llvm::Attribute::NoProfile) &&
         !CurFn->hasFnAttribute(llvm::Attribute::SkipProfile)) {
       auto AL = ApplyDebugLocation::CreateArtificial(*this);
-      PGO.emitCounterSetOrIncrement(Builder, S, UseSkipPath, UseBoth, StepV);
+      PGO.emitCounterSetOrIncrement(Builder, S, (ExecSkip == UseSkipPath),
+                                    UseBoth, StepV);
     }
     PGO.setCurrentStmt(S);
   }

>From dfc99bad0fd0baa6e0d9a39554da041dd02d6568 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Tue, 24 Dec 2024 17:29:27 +0900
Subject: [PATCH 42/72] Fix wrong merge resolutions

---
 llvm/lib/ProfileData/Coverage/CoverageMapping.cpp | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index 21a296d89d214..430e68ea94a02 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -805,7 +805,6 @@ Error CoverageMapping::loadFunctionRecord(
   else
     OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName, Record.Filenames[0]);
 
-  bool SingleByteCoverage = ProfileReader.hasSingleByteCoverage();
   CounterMappingContext Ctx(Record.Expressions);
 
   std::vector<uint64_t> Counts;
@@ -871,10 +870,7 @@ Error CoverageMapping::loadFunctionRecord(
       consumeError(std::move(E));
       return Error::success();
     }
-    Function.pushRegion(
-        Region, (SingleByteCoverage && *ExecutionCount ? 1 : *ExecutionCount),
-        (SingleByteCoverage && *AltExecutionCount ? 1 : *AltExecutionCount),
-        SingleByteCoverage);
+    Function.pushRegion(Region, *ExecutionCount, *AltExecutionCount);
 
     // Record ExpansionRegion.
     if (Region.Kind == CounterMappingRegion::ExpansionRegion) {

>From f3c9593037e8dbc4a5c9c5e5a5d5801e801019c4 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Wed, 25 Dec 2024 08:40:39 +0900
Subject: [PATCH 43/72] Reorganize CoverageMapping::SingleByteCoverage

---
 .../ProfileData/Coverage/CoverageMapping.h    | 12 +++++------
 .../ProfileData/Coverage/CoverageMapping.cpp  | 20 +++++++++++--------
 2 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index 42aea623be165..705a9f28c1241 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -890,12 +890,12 @@ class CoverageData {
   std::vector<CountedRegion> BranchRegions;
   std::vector<MCDCRecord> MCDCRecords;
 
-  bool SingleByteCoverage;
+  bool SingleByteCoverage = false;
 
 public:
-  CoverageData() = delete;
+  CoverageData() = default;
 
-  CoverageData(bool Single, StringRef Filename = StringRef())
+  CoverageData(bool Single, StringRef Filename)
       : Filename(Filename), SingleByteCoverage(Single) {}
 
   /// Get the name of the file this data covers.
@@ -935,9 +935,9 @@ class CoverageMapping {
   DenseMap<size_t, SmallVector<unsigned, 0>> FilenameHash2RecordIndices;
   std::vector<std::pair<std::string, uint64_t>> FuncHashMismatches;
 
-  bool SingleByteCoverage;
+  std::optional<bool> SingleByteCoverage;
 
-  CoverageMapping(bool Single) : SingleByteCoverage(Single) {}
+  CoverageMapping() = default;
 
   // Load coverage records from readers.
   static Error loadFromReaders(
@@ -981,7 +981,7 @@ class CoverageMapping {
        const object::BuildIDFetcher *BIDFetcher = nullptr,
        bool CheckBinaryIDs = false);
 
-  bool getSingleByteCoverage() const { return SingleByteCoverage; }
+  // bool getSingleByteCoverage() const { return SingleByteCoverage; }
 
   /// The number of functions that couldn't have their profiles mapped.
   ///
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index 430e68ea94a02..1bf2e8d627bc4 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -932,6 +932,9 @@ Error CoverageMapping::loadFunctionRecord(
 Error CoverageMapping::loadFromReaders(
     ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
     IndexedInstrProfReader &ProfileReader, CoverageMapping &Coverage) {
+  assert(!Coverage.SingleByteCoverage ||
+         *Coverage.SingleByteCoverage == ProfileReader.hasSingleByteCoverage());
+  Coverage.SingleByteCoverage = ProfileReader.hasSingleByteCoverage();
   for (const auto &CoverageReader : CoverageReaders) {
     for (auto RecordOrErr : *CoverageReader) {
       if (Error E = RecordOrErr.takeError())
@@ -947,8 +950,7 @@ Error CoverageMapping::loadFromReaders(
 Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
     ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders,
     IndexedInstrProfReader &ProfileReader) {
-  auto Coverage = std::unique_ptr<CoverageMapping>(
-      new CoverageMapping(ProfileReader.hasSingleByteCoverage()));
+  auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping());
   if (Error E = loadFromReaders(CoverageReaders, ProfileReader, *Coverage))
     return std::move(E);
   return std::move(Coverage);
@@ -1010,8 +1012,7 @@ Expected<std::unique_ptr<CoverageMapping>> CoverageMapping::load(
   if (Error E = ProfileReaderOrErr.takeError())
     return createFileError(ProfileFilename, std::move(E));
   auto ProfileReader = std::move(ProfileReaderOrErr.get());
-  auto Coverage = std::unique_ptr<CoverageMapping>(
-      new CoverageMapping(ProfileReader->hasSingleByteCoverage()));
+  auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping());
   bool DataFound = false;
 
   auto GetArch = [&](size_t Idx) {
@@ -1388,7 +1389,8 @@ static bool isExpansion(const CountedRegion &R, unsigned FileID) {
 }
 
 CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) const {
-  CoverageData FileCoverage(SingleByteCoverage, Filename);
+  assert(SingleByteCoverage);
+  CoverageData FileCoverage(*SingleByteCoverage, Filename);
   std::vector<CountedRegion> Regions;
 
   // Look up the function records in the given file. Due to hash collisions on
@@ -1450,9 +1452,10 @@ CoverageData
 CoverageMapping::getCoverageForFunction(const FunctionRecord &Function) const {
   auto MainFileID = findMainViewFileID(Function);
   if (!MainFileID)
-    return CoverageData(SingleByteCoverage);
+    return CoverageData();
 
-  CoverageData FunctionCoverage(SingleByteCoverage,
+  assert(SingleByteCoverage);
+  CoverageData FunctionCoverage(*SingleByteCoverage,
                                 Function.Filenames[*MainFileID]);
   std::vector<CountedRegion> Regions;
   for (const auto &CR : Function.CountedRegions)
@@ -1480,8 +1483,9 @@ CoverageMapping::getCoverageForFunction(const FunctionRecord &Function) const {
 
 CoverageData CoverageMapping::getCoverageForExpansion(
     const ExpansionRecord &Expansion) const {
+  assert(SingleByteCoverage);
   CoverageData ExpansionCoverage(
-      SingleByteCoverage, Expansion.Function.Filenames[Expansion.FileID]);
+      *SingleByteCoverage, Expansion.Function.Filenames[Expansion.FileID]);
   std::vector<CountedRegion> Regions;
   for (const auto &CR : Expansion.Function.CountedRegions)
     if (CR.FileID == Expansion.FileID) {

>From 3780e07c41b54c07e2cd61bee8a7c451e4f2cbf5 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Wed, 25 Dec 2024 08:43:24 +0900
Subject: [PATCH 44/72] Prune commented-out line

---
 llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h | 2 --
 1 file changed, 2 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index 705a9f28c1241..0ad6f07bde989 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -981,8 +981,6 @@ class CoverageMapping {
        const object::BuildIDFetcher *BIDFetcher = nullptr,
        bool CheckBinaryIDs = false);
 
-  // bool getSingleByteCoverage() const { return SingleByteCoverage; }
-
   /// The number of functions that couldn't have their profiles mapped.
   ///
   /// This is a count of functions whose profile is out of date or otherwise

>From 36b4aaf0248c85c3e3cf621f75b26e2734efafba Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Fri, 27 Dec 2024 15:31:05 +0900
Subject: [PATCH 45/72] [Coverage] Make `MCDCRecord::Folded` as `[false/true]`
 with BitVector. NFC.

---
 .../llvm/ProfileData/Coverage/CoverageMapping.h       |  6 ++++--
 llvm/lib/ProfileData/Coverage/CoverageMapping.cpp     | 11 ++++++-----
 2 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index 42da188fef34e..5caba07f8ad43 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -442,7 +442,7 @@ struct MCDCRecord {
   };
 
   using TestVectors = llvm::SmallVector<std::pair<TestVector, CondState>>;
-  using BoolVector = llvm::SmallVector<bool>;
+  using BoolVector = std::array<BitVector, 2>;
   using TVRowPair = std::pair<unsigned, unsigned>;
   using TVPairMap = llvm::DenseMap<unsigned, TVRowPair>;
   using CondIDMap = llvm::DenseMap<unsigned, unsigned>;
@@ -470,7 +470,9 @@ struct MCDCRecord {
     return Region.getDecisionParams().NumConditions;
   }
   unsigned getNumTestVectors() const { return TV.size(); }
-  bool isCondFolded(unsigned Condition) const { return Folded[Condition]; }
+  bool isCondFolded(unsigned Condition) const {
+    return Folded[false][Condition] || Folded[true][Condition];
+  }
 
   /// Return the evaluation of a condition (indicated by Condition) in an
   /// executed test vector (indicated by TestVectorIndex), which will be True,
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index 87d8bb1bbb79c..2eba1667306d1 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -392,8 +392,9 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
       : NextIDsBuilder(Branches), TVIdxBuilder(this->NextIDs), Bitmap(Bitmap),
         Region(Region), DecisionParams(Region.getDecisionParams()),
         Branches(Branches), NumConditions(DecisionParams.NumConditions),
-        Folded(NumConditions, false), IndependencePairs(NumConditions),
-        ExecVectors(ExecVectorsByCond[false]), IsVersion11(IsVersion11) {}
+        Folded{{BitVector(NumConditions), BitVector(NumConditions)}},
+        IndependencePairs(NumConditions), ExecVectors(ExecVectorsByCond[false]),
+        IsVersion11(IsVersion11) {}
 
 private:
   // Walk the binary decision diagram and try assigning both false and true to
@@ -485,7 +486,6 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
   /// location is also tracked, as well as whether it is constant folded (in
   /// which case it is excuded from the metric).
   MCDCRecord processMCDCRecord() {
-    unsigned I = 0;
     MCDCRecord::CondIDMap PosToID;
     MCDCRecord::LineColPairMap CondLoc;
 
@@ -499,11 +499,12 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
     //   visualize where the condition is.
     // - Record whether the condition is constant folded so that we exclude it
     //   from being measured.
-    for (const auto *B : Branches) {
+    for (auto [I, B] : enumerate(Branches)) {
       const auto &BranchParams = B->getBranchParams();
       PosToID[I] = BranchParams.ID;
       CondLoc[I] = B->startLoc();
-      Folded[I++] = (B->Count.isZero() || B->FalseCount.isZero());
+      Folded[false][I] = B->FalseCount.isZero();
+      Folded[true][I] = B->Count.isZero();
     }
 
     // Using Profile Bitmap from runtime, mark the executed test vectors.

>From 978070d6aca594a49dc2ef0558e1e28e883ac1b0 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Fri, 27 Dec 2024 15:34:16 +0900
Subject: [PATCH 46/72] [Coverage] MCDC: Move `findIndependencePairs` into
 `MCDCRecord`

---
 .../ProfileData/Coverage/CoverageMapping.h    | 27 +++++---
 .../ProfileData/Coverage/CoverageMapping.cpp  | 67 ++++++++++---------
 2 files changed, 51 insertions(+), 43 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index 42da188fef34e..4f28f5da6cf81 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -35,6 +35,7 @@
 #include <cstdint>
 #include <iterator>
 #include <memory>
+#include <optional>
 #include <sstream>
 #include <string>
 #include <system_error>
@@ -451,19 +452,22 @@ struct MCDCRecord {
 private:
   CounterMappingRegion Region;
   TestVectors TV;
-  TVPairMap IndependencePairs;
+  std::optional<TVPairMap> IndependencePairs;
   BoolVector Folded;
   CondIDMap PosToID;
   LineColPairMap CondLoc;
 
 public:
   MCDCRecord(const CounterMappingRegion &Region, TestVectors &&TV,
-             TVPairMap &&IndependencePairs, BoolVector &&Folded,
-             CondIDMap &&PosToID, LineColPairMap &&CondLoc)
-      : Region(Region), TV(std::move(TV)),
-        IndependencePairs(std::move(IndependencePairs)),
-        Folded(std::move(Folded)), PosToID(std::move(PosToID)),
-        CondLoc(std::move(CondLoc)){};
+             BoolVector &&Folded, CondIDMap &&PosToID, LineColPairMap &&CondLoc)
+      : Region(Region), TV(std::move(TV)), Folded(std::move(Folded)),
+        PosToID(std::move(PosToID)), CondLoc(std::move(CondLoc)) {
+    findIndependencePairs();
+  }
+
+  // Compare executed test vectors against each other to find an independence
+  // pairs for each condition.  This processing takes the most time.
+  void findIndependencePairs();
 
   const CounterMappingRegion &getDecisionRegion() const { return Region; }
   unsigned getNumConditions() const {
@@ -494,10 +498,10 @@ struct MCDCRecord {
   /// TestVectors requires a translation from a ordinal position to actual
   /// condition ID. This is done via PosToID[].
   bool isConditionIndependencePairCovered(unsigned Condition) const {
+    assert(IndependencePairs);
     auto It = PosToID.find(Condition);
-    if (It != PosToID.end())
-      return IndependencePairs.contains(It->second);
-    llvm_unreachable("Condition ID without an Ordinal mapping");
+    assert(It != PosToID.end() && "Condition ID without an Ordinal mapping");
+    return IndependencePairs->contains(It->second);
   }
 
   /// Return the Independence Pair that covers the given condition. Because
@@ -507,7 +511,8 @@ struct MCDCRecord {
   /// via PosToID[].
   TVRowPair getConditionIndependencePair(unsigned Condition) {
     assert(isConditionIndependencePairCovered(Condition));
-    return IndependencePairs[PosToID[Condition]];
+    assert(IndependencePairs);
+    return (*IndependencePairs)[PosToID[Condition]];
   }
 
   float getPercentCovered() const {
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index 87d8bb1bbb79c..2c7a77bac0932 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -221,6 +221,40 @@ Expected<int64_t> CounterMappingContext::evaluate(const Counter &C) const {
   return LastPoppedValue;
 }
 
+// Find an independence pair for each condition:
+// - The condition is true in one test and false in the other.
+// - The decision outcome is true one test and false in the other.
+// - All other conditions' values must be equal or marked as "don't care".
+void MCDCRecord::findIndependencePairs() {
+  if (IndependencePairs)
+    return;
+
+  IndependencePairs.emplace();
+
+  unsigned NumTVs = TV.size();
+  // Will be replaced to shorter expr.
+  unsigned TVTrueIdx = std::distance(
+      TV.begin(),
+      std::find_if(TV.begin(), TV.end(),
+                   [&](auto I) { return (I.second == MCDCRecord::MCDC_True); })
+
+  );
+  for (unsigned I = TVTrueIdx; I < NumTVs; ++I) {
+    const auto &[A, ACond] = TV[I];
+    assert(ACond == MCDCRecord::MCDC_True);
+    for (unsigned J = 0; J < TVTrueIdx; ++J) {
+      const auto &[B, BCond] = TV[J];
+      assert(BCond == MCDCRecord::MCDC_False);
+      // If the two vectors differ in exactly one condition, ignoring DontCare
+      // conditions, we have found an independence pair.
+      auto AB = A.getDifferences(B);
+      if (AB.count() == 1)
+        IndependencePairs->insert(
+            {AB.find_first(), std::make_pair(J + 1, I + 1)});
+    }
+  }
+}
+
 mcdc::TVIdxBuilder::TVIdxBuilder(const SmallVectorImpl<ConditionIDs> &NextIDs,
                                  int Offset)
     : Indices(NextIDs.size()) {
@@ -375,9 +409,6 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
   /// ExecutedTestVectorBitmap.
   MCDCRecord::TestVectors &ExecVectors;
 
-  /// Number of False items in ExecVectors
-  unsigned NumExecVectorsF;
-
 #ifndef NDEBUG
   DenseSet<unsigned> TVIdxs;
 #endif
@@ -446,34 +477,11 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
     // Fill ExecVectors order by False items and True items.
     // ExecVectors is the alias of ExecVectorsByCond[false], so
     // Append ExecVectorsByCond[true] on it.
-    NumExecVectorsF = ExecVectors.size();
     auto &ExecVectorsT = ExecVectorsByCond[true];
     ExecVectors.append(std::make_move_iterator(ExecVectorsT.begin()),
                        std::make_move_iterator(ExecVectorsT.end()));
   }
 
-  // Find an independence pair for each condition:
-  // - The condition is true in one test and false in the other.
-  // - The decision outcome is true one test and false in the other.
-  // - All other conditions' values must be equal or marked as "don't care".
-  void findIndependencePairs() {
-    unsigned NumTVs = ExecVectors.size();
-    for (unsigned I = NumExecVectorsF; I < NumTVs; ++I) {
-      const auto &[A, ACond] = ExecVectors[I];
-      assert(ACond == MCDCRecord::MCDC_True);
-      for (unsigned J = 0; J < NumExecVectorsF; ++J) {
-        const auto &[B, BCond] = ExecVectors[J];
-        assert(BCond == MCDCRecord::MCDC_False);
-        // If the two vectors differ in exactly one condition, ignoring DontCare
-        // conditions, we have found an independence pair.
-        auto AB = A.getDifferences(B);
-        if (AB.count() == 1)
-          IndependencePairs.insert(
-              {AB.find_first(), std::make_pair(J + 1, I + 1)});
-      }
-    }
-  }
-
 public:
   /// Process the MC/DC Record in order to produce a result for a boolean
   /// expression. This process includes tracking the conditions that comprise
@@ -509,13 +517,8 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
     // Using Profile Bitmap from runtime, mark the executed test vectors.
     findExecutedTestVectors();
 
-    // Compare executed test vectors against each other to find an independence
-    // pairs for each condition.  This processing takes the most time.
-    findIndependencePairs();
-
     // Record Test vectors, executed vectors, and independence pairs.
-    return MCDCRecord(Region, std::move(ExecVectors),
-                      std::move(IndependencePairs), std::move(Folded),
+    return MCDCRecord(Region, std::move(ExecVectors), std::move(Folded),
                       std::move(PosToID), std::move(CondLoc));
   }
 };

>From 3abe2ac361822bf6513e5f3ef9fead37842af862 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Fri, 27 Dec 2024 15:40:47 +0900
Subject: [PATCH 47/72] [Coverage] Sort `MCDCRecord::ExecVectors` order by
 Bitmap index

---
 .../ProfileData/Coverage/CoverageMapping.cpp  | 40 +++++++++++++------
 llvm/test/tools/llvm-cov/mcdc-const.test      | 32 +++++++--------
 llvm/test/tools/llvm-cov/mcdc-general.test    |  8 ++--
 3 files changed, 47 insertions(+), 33 deletions(-)

diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index 3bbee70be0fe9..53445b1030c9f 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -401,13 +401,27 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
   /// Mapping of calculated MC/DC Independence Pairs for each condition.
   MCDCRecord::TVPairMap IndependencePairs;
 
-  /// Storage for ExecVectors
-  /// ExecVectors is the alias of its 0th element.
-  std::array<MCDCRecord::TestVectors, 2> ExecVectorsByCond;
+  /// Helper for sorting ExecVectors.
+  struct TVIdxTuple {
+    MCDCRecord::CondState MCDCCond; /// True/False
+    unsigned BIdx;                  /// Bitmap Index
+    unsigned Ord;                   /// Last position on ExecVectors
+
+    TVIdxTuple(MCDCRecord::CondState MCDCCond, unsigned BIdx, unsigned Ord)
+        : MCDCCond(MCDCCond), BIdx(BIdx), Ord(Ord) {}
+
+    bool operator<(const TVIdxTuple &RHS) const {
+      return (std::tie(this->MCDCCond, this->BIdx, this->Ord) <
+              std::tie(RHS.MCDCCond, RHS.BIdx, RHS.Ord));
+    }
+  };
+
+  // Indices for sorted TestVectors;
+  std::vector<TVIdxTuple> ExecVectorIdxs;
 
   /// Actual executed Test Vectors for the boolean expression, based on
   /// ExecutedTestVectorBitmap.
-  MCDCRecord::TestVectors &ExecVectors;
+  MCDCRecord::TestVectors ExecVectors;
 
 #ifndef NDEBUG
   DenseSet<unsigned> TVIdxs;
@@ -424,8 +438,7 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
         Region(Region), DecisionParams(Region.getDecisionParams()),
         Branches(Branches), NumConditions(DecisionParams.NumConditions),
         Folded{{BitVector(NumConditions), BitVector(NumConditions)}},
-        IndependencePairs(NumConditions), ExecVectors(ExecVectorsByCond[false]),
-        IsVersion11(IsVersion11) {}
+        IndependencePairs(NumConditions), IsVersion11(IsVersion11) {}
 
 private:
   // Walk the binary decision diagram and try assigning both false and true to
@@ -453,10 +466,12 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
                       : DecisionParams.BitmapIdx - NumTestVectors + NextTVIdx])
         continue;
 
+      ExecVectorIdxs.emplace_back(MCDCCond, NextTVIdx, ExecVectors.size());
+
       // Copy the completed test vector to the vector of testvectors.
       // The final value (T,F) is equal to the last non-dontcare state on the
       // path (in a short-circuiting system).
-      ExecVectorsByCond[MCDCCond].push_back({TV, MCDCCond});
+      ExecVectors.push_back({TV, MCDCCond});
     }
 
     // Reset back to DontCare.
@@ -475,12 +490,11 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
     assert(TVIdxs.size() == unsigned(NumTestVectors) &&
            "TVIdxs wasn't fulfilled");
 
-    // Fill ExecVectors order by False items and True items.
-    // ExecVectors is the alias of ExecVectorsByCond[false], so
-    // Append ExecVectorsByCond[true] on it.
-    auto &ExecVectorsT = ExecVectorsByCond[true];
-    ExecVectors.append(std::make_move_iterator(ExecVectorsT.begin()),
-                       std::make_move_iterator(ExecVectorsT.end()));
+    llvm::sort(ExecVectorIdxs);
+    MCDCRecord::TestVectors NewTestVectors;
+    for (const auto &IdxTuple : ExecVectorIdxs)
+      NewTestVectors.push_back(std::move(ExecVectors[IdxTuple.Ord]));
+    ExecVectors = std::move(NewTestVectors);
   }
 
 public:
diff --git a/llvm/test/tools/llvm-cov/mcdc-const.test b/llvm/test/tools/llvm-cov/mcdc-const.test
index 5424625cf6a6b..76eb7cf706d73 100644
--- a/llvm/test/tools/llvm-cov/mcdc-const.test
+++ b/llvm/test/tools/llvm-cov/mcdc-const.test
@@ -61,8 +61,8 @@
 //      CHECKFULLCASE: |  C1-Pair: constant folded
 // CHECKFULLCASE-NEXT: |  C2-Pair: not covered
 //      CHECKFULLCASE: |  MC/DC Coverage for Decision: 0.00%
-//      CHECKFULLCASE: |  1 { F,  C  = T      }
-// CHECKFULLCASE-NEXT: |  2 { T,  C  = T      }
+//      CHECKFULLCASE: |  1 { T,  C  = T      }
+// CHECKFULLCASE-NEXT: |  2 { F,  C  = T      }
 //      CHECKFULLCASE: |  C1-Pair: not covered
 // CHECKFULLCASE-NEXT: |  C2-Pair: constant folded
 //      CHECKFULLCASE: |  MC/DC Coverage for Decision: 0.00%
@@ -106,20 +106,20 @@
 // CHECKFULLCASE-NEXT: |  C2-Pair: not covered
 // CHECKFULLCASE-NEXT: |  C3-Pair: not covered
 //      CHECKFULLCASE: |  MC/DC Coverage for Decision: 0.00%
-//      CHECKFULLCASE: |  1 { F,  C,  -  = T      }
-// CHECKFULLCASE-NEXT: |  2 { T,  C,  -  = T      }
+//      CHECKFULLCASE: |  1 { T,  C,  -  = T      }
+// CHECKFULLCASE-NEXT: |  2 { F,  C,  -  = T      }
 //      CHECKFULLCASE: |  C1-Pair: not covered
 // CHECKFULLCASE-NEXT: |  C2-Pair: constant folded
 // CHECKFULLCASE-NEXT: |  C3-Pair: not covered
 //      CHECKFULLCASE: |  MC/DC Coverage for Decision: 0.00%
-//      CHECKFULLCASE: |  1 { C,  F,  T  = T      }
-// CHECKFULLCASE-NEXT: |  2 { C,  T,  -  = T      }
+//      CHECKFULLCASE: |  1 { C,  T,  -  = T      }
+// CHECKFULLCASE-NEXT: |  2 { C,  F,  T  = T      }
 //      CHECKFULLCASE: |  C1-Pair: constant folded
 // CHECKFULLCASE-NEXT: |  C2-Pair: not covered
 // CHECKFULLCASE-NEXT: |  C3-Pair: not covered
 //      CHECKFULLCASE: |  MC/DC Coverage for Decision: 0.00%
-//      CHECKFULLCASE: |  1 { F,  C,  T  = T      }
-// CHECKFULLCASE-NEXT: |  2 { T,  C,  -  = T      }
+//      CHECKFULLCASE: |  1 { T,  C,  -  = T      }
+// CHECKFULLCASE-NEXT: |  2 { F,  C,  T  = T      }
 //      CHECKFULLCASE: |  C1-Pair: not covered
 // CHECKFULLCASE-NEXT: |  C2-Pair: constant folded
 // CHECKFULLCASE-NEXT: |  C3-Pair: not covered
@@ -151,26 +151,26 @@
 // CHECKFULLCASE-NEXT: |  C2-Pair: constant folded
 // CHECKFULLCASE-NEXT: |  C3-Pair: covered: (2,3)
 //      CHECKFULLCASE: |  MC/DC Coverage for Decision: 100.00%
-//      CHECKFULLCASE: |  1 { F,  T,  C  = T      }
-// CHECKFULLCASE-NEXT: |  2 { T,  -,  C  = T      }
+//      CHECKFULLCASE: |  1 { T,  -,  C  = T      }
+// CHECKFULLCASE-NEXT: |  2 { F,  T,  C  = T      }
 //      CHECKFULLCASE: |  C1-Pair: not covered
 // CHECKFULLCASE-NEXT: |  C2-Pair: not covered
 // CHECKFULLCASE-NEXT: |  C3-Pair: constant folded
 //      CHECKFULLCASE: |  MC/DC Coverage for Decision: 0.00%
-//      CHECKFULLCASE: |  1 { F,  C,  -  = T      }
-// CHECKFULLCASE-NEXT: |  2 { T,  C,  -  = T      }
+//      CHECKFULLCASE: |  1 { T,  C,  -  = T      }
+// CHECKFULLCASE-NEXT: |  2 { F,  C,  -  = T      }
 //      CHECKFULLCASE: |  C1-Pair: not covered
 // CHECKFULLCASE-NEXT: |  C2-Pair: constant folded
 // CHECKFULLCASE-NEXT: |  C3-Pair: not covered
 //      CHECKFULLCASE: |  MC/DC Coverage for Decision: 0.00%
-//      CHECKFULLCASE: |  1 { F,  T,  C  = T      }
-// CHECKFULLCASE-NEXT: |  2 { T,  -,  C  = T      }
+//      CHECKFULLCASE: |  1 { T,  -,  C  = T      }
+// CHECKFULLCASE-NEXT: |  2 { F,  T,  C  = T      }
 //      CHECKFULLCASE: |  C1-Pair: not covered
 // CHECKFULLCASE-NEXT: |  C2-Pair: not covered
 // CHECKFULLCASE-NEXT: |  C3-Pair: constant folded
 //      CHECKFULLCASE: |  MC/DC Coverage for Decision: 0.00%
-//      CHECKFULLCASE: |  1 { F,  C,  T  = T      }
-// CHECKFULLCASE-NEXT: |  2 { T,  C,  -  = T      }
+//      CHECKFULLCASE: |  1 { T,  C,  -  = T      }
+// CHECKFULLCASE-NEXT: |  2 { F,  C,  T  = T      }
 //      CHECKFULLCASE: |  C1-Pair: not covered
 // CHECKFULLCASE-NEXT: |  C2-Pair: constant folded
 // CHECKFULLCASE-NEXT: |  C3-Pair: not covered
diff --git a/llvm/test/tools/llvm-cov/mcdc-general.test b/llvm/test/tools/llvm-cov/mcdc-general.test
index c1e95cb2bd92a..1835af9a4c6b5 100644
--- a/llvm/test/tools/llvm-cov/mcdc-general.test
+++ b/llvm/test/tools/llvm-cov/mcdc-general.test
@@ -19,15 +19,15 @@
 // CHECK-NEXT:  |
 // CHECK-NEXT:  |     C1, C2, C3, C4    Result
 // CHECK-NEXT:  |  1 { F,  -,  F,  -  = F      }
-// CHECK-NEXT:  |  2 { F,  -,  T,  F  = F      }
-// CHECK-NEXT:  |  3 { T,  F,  F,  -  = F      }
+// CHECK-NEXT:  |  2 { T,  F,  F,  -  = F      }
+// CHECK-NEXT:  |  3 { F,  -,  T,  F  = F      }
 // CHECK-NEXT:  |  4 { T,  F,  T,  F  = F      }
 // CHECK-NEXT:  |  5 { T,  F,  T,  T  = T      }
 // CHECK-NEXT:  |  6 { T,  T,  -,  -  = T      }
 // CHECK-NEXT:  |
 // CHECK-NEXT:  |  C1-Pair: covered: (1,6)
-// CHECK-NEXT:  |  C2-Pair: covered: (3,6)
-// CHECK-NEXT:  |  C3-Pair: covered: (3,5)
+// CHECK-NEXT:  |  C2-Pair: covered: (2,6)
+// CHECK-NEXT:  |  C3-Pair: covered: (2,5)
 // CHECK-NEXT:  |  C4-Pair: covered: (4,5)
 // CHECK-NEXT:  |  MC/DC Coverage for Decision: 100.00%
 // CHECK-NEXT:  |

>From f86c537e2c9224cddf10d0b05333e35bdc169361 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Fri, 27 Dec 2024 15:42:07 +0900
Subject: [PATCH 48/72] llvm-cov: Refactor CoverageSummaryInfo. NFC.

---
 llvm/tools/llvm-cov/CoverageSummaryInfo.cpp | 51 +++++++++++----------
 llvm/tools/llvm-cov/CoverageSummaryInfo.h   | 45 +++++++++---------
 2 files changed, 50 insertions(+), 46 deletions(-)

diff --git a/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp b/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
index ad7561d3dc62c..5c002a694f66a 100644
--- a/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
+++ b/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
@@ -16,8 +16,9 @@
 using namespace llvm;
 using namespace coverage;
 
-static void sumBranches(size_t &NumBranches, size_t &CoveredBranches,
-                        const ArrayRef<CountedRegion> &Branches) {
+static auto sumBranches(const ArrayRef<CountedRegion> &Branches) {
+  size_t NumBranches = 0;
+  size_t CoveredBranches = 0;
   for (const auto &BR : Branches) {
     if (!BR.TrueFolded) {
       // "True" Condition Branches.
@@ -32,20 +33,22 @@ static void sumBranches(size_t &NumBranches, size_t &CoveredBranches,
         ++CoveredBranches;
     }
   }
+  return BranchCoverageInfo(CoveredBranches, NumBranches);
 }
 
-static void sumBranchExpansions(size_t &NumBranches, size_t &CoveredBranches,
-                                const CoverageMapping &CM,
-                                ArrayRef<ExpansionRecord> Expansions) {
+static BranchCoverageInfo
+sumBranchExpansions(const CoverageMapping &CM,
+                    ArrayRef<ExpansionRecord> Expansions) {
+  BranchCoverageInfo BranchCoverage;
   for (const auto &Expansion : Expansions) {
     auto CE = CM.getCoverageForExpansion(Expansion);
-    sumBranches(NumBranches, CoveredBranches, CE.getBranches());
-    sumBranchExpansions(NumBranches, CoveredBranches, CM, CE.getExpansions());
+    BranchCoverage += sumBranches(CE.getBranches());
+    BranchCoverage += sumBranchExpansions(CM, CE.getExpansions());
   }
+  return BranchCoverage;
 }
 
-static std::pair<size_t, size_t>
-sumMCDCPairs(const ArrayRef<MCDCRecord> &Records) {
+auto sumMCDCPairs(const ArrayRef<MCDCRecord> &Records) {
   size_t NumPairs = 0, CoveredPairs = 0;
   for (const auto &Record : Records) {
     const auto NumConditions = Record.getNumConditions();
@@ -56,7 +59,7 @@ sumMCDCPairs(const ArrayRef<MCDCRecord> &Records) {
         ++CoveredPairs;
     }
   }
-  return {NumPairs, CoveredPairs};
+  return MCDCCoverageInfo(CoveredPairs, NumPairs);
 }
 
 static std::pair<RegionCoverageInfo, LineCoverageInfo>
@@ -85,24 +88,27 @@ sumRegions(ArrayRef<CountedRegion> CodeRegions, const CoverageData &CD) {
           LineCoverageInfo(CoveredLines, NumLines)};
 }
 
+CoverageDataSummary::CoverageDataSummary(const CoverageData &CD,
+                                         ArrayRef<CountedRegion> CodeRegions) {
+  std::tie(RegionCoverage, LineCoverage) = sumRegions(CodeRegions, CD);
+  BranchCoverage = sumBranches(CD.getBranches());
+  MCDCCoverage = sumMCDCPairs(CD.getMCDCRecords());
+}
+
 FunctionCoverageSummary
 FunctionCoverageSummary::get(const CoverageMapping &CM,
                              const coverage::FunctionRecord &Function) {
   CoverageData CD = CM.getCoverageForFunction(Function);
-  auto [RegionCoverage, LineCoverage] = sumRegions(Function.CountedRegions, CD);
 
-  // Compute the branch coverage, including branches from expansions.
-  size_t NumBranches = 0, CoveredBranches = 0;
-  sumBranches(NumBranches, CoveredBranches, CD.getBranches());
-  sumBranchExpansions(NumBranches, CoveredBranches, CM, CD.getExpansions());
+  auto Summary =
+      FunctionCoverageSummary(Function.Name, Function.ExecutionCount);
 
-  size_t NumPairs = 0, CoveredPairs = 0;
-  std::tie(NumPairs, CoveredPairs) = sumMCDCPairs(CD.getMCDCRecords());
+  Summary += CoverageDataSummary(CD, Function.CountedRegions);
 
-  return FunctionCoverageSummary(
-      Function.Name, Function.ExecutionCount, RegionCoverage, LineCoverage,
-      BranchCoverageInfo(CoveredBranches, NumBranches),
-      MCDCCoverageInfo(CoveredPairs, NumPairs));
+  // Compute the branch coverage, including branches from expansions.
+  Summary.BranchCoverage += sumBranchExpansions(CM, CD.getExpansions());
+
+  return Summary;
 }
 
 FunctionCoverageSummary
@@ -117,8 +123,7 @@ FunctionCoverageSummary::get(const InstantiationGroup &Group,
        << Group.getColumn();
   }
 
-  FunctionCoverageSummary Summary(Name);
-  Summary.ExecutionCount = Group.getTotalExecutionCount();
+  FunctionCoverageSummary Summary(Name, Group.getTotalExecutionCount());
   Summary.RegionCoverage = Summaries[0].RegionCoverage;
   Summary.LineCoverage = Summaries[0].LineCoverage;
   Summary.BranchCoverage = Summaries[0].BranchCoverage;
diff --git a/llvm/tools/llvm-cov/CoverageSummaryInfo.h b/llvm/tools/llvm-cov/CoverageSummaryInfo.h
index 64c2c8406cf3e..d9210676c41bf 100644
--- a/llvm/tools/llvm-cov/CoverageSummaryInfo.h
+++ b/llvm/tools/llvm-cov/CoverageSummaryInfo.h
@@ -223,26 +223,32 @@ class FunctionCoverageInfo {
   }
 };
 
-/// A summary of function's code coverage.
-struct FunctionCoverageSummary {
-  std::string Name;
-  uint64_t ExecutionCount;
+struct CoverageDataSummary {
   RegionCoverageInfo RegionCoverage;
   LineCoverageInfo LineCoverage;
   BranchCoverageInfo BranchCoverage;
   MCDCCoverageInfo MCDCCoverage;
 
-  FunctionCoverageSummary(const std::string &Name)
-      : Name(Name), ExecutionCount(0) {}
+  CoverageDataSummary() = default;
+  CoverageDataSummary(const coverage::CoverageData &CD,
+                      ArrayRef<coverage::CountedRegion> CodeRegions);
 
-  FunctionCoverageSummary(const std::string &Name, uint64_t ExecutionCount,
-                          const RegionCoverageInfo &RegionCoverage,
-                          const LineCoverageInfo &LineCoverage,
-                          const BranchCoverageInfo &BranchCoverage,
-                          const MCDCCoverageInfo &MCDCCoverage)
-      : Name(Name), ExecutionCount(ExecutionCount),
-        RegionCoverage(RegionCoverage), LineCoverage(LineCoverage),
-        BranchCoverage(BranchCoverage), MCDCCoverage(MCDCCoverage) {}
+  auto &operator+=(const CoverageDataSummary &RHS) {
+    RegionCoverage += RHS.RegionCoverage;
+    LineCoverage += RHS.LineCoverage;
+    BranchCoverage += RHS.BranchCoverage;
+    MCDCCoverage += RHS.MCDCCoverage;
+    return *this;
+  }
+};
+
+/// A summary of function's code coverage.
+struct FunctionCoverageSummary : CoverageDataSummary {
+  std::string Name;
+  uint64_t ExecutionCount;
+
+  FunctionCoverageSummary(const std::string &Name, uint64_t ExecutionCount = 0)
+      : Name(Name), ExecutionCount(ExecutionCount) {}
 
   /// Compute the code coverage summary for the given function coverage
   /// mapping record.
@@ -257,12 +263,8 @@ struct FunctionCoverageSummary {
 };
 
 /// A summary of file's code coverage.
-struct FileCoverageSummary {
+struct FileCoverageSummary : CoverageDataSummary {
   StringRef Name;
-  RegionCoverageInfo RegionCoverage;
-  LineCoverageInfo LineCoverage;
-  BranchCoverageInfo BranchCoverage;
-  MCDCCoverageInfo MCDCCoverage;
   FunctionCoverageInfo FunctionCoverage;
   FunctionCoverageInfo InstantiationCoverage;
 
@@ -270,11 +272,8 @@ struct FileCoverageSummary {
   FileCoverageSummary(StringRef Name) : Name(Name) {}
 
   FileCoverageSummary &operator+=(const FileCoverageSummary &RHS) {
-    RegionCoverage += RHS.RegionCoverage;
-    LineCoverage += RHS.LineCoverage;
+    *static_cast<CoverageDataSummary *>(this) += RHS;
     FunctionCoverage += RHS.FunctionCoverage;
-    BranchCoverage += RHS.BranchCoverage;
-    MCDCCoverage += RHS.MCDCCoverage;
     InstantiationCoverage += RHS.InstantiationCoverage;
     return *this;
   }

>From 28c568ad84edbfb4eb4bc7841c8c6b39e9722094 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Mon, 6 Jan 2025 23:37:50 +0900
Subject: [PATCH 49/72] Add a test

---
 .../ProfileData/CoverageMappingTest.cpp       | 39 +++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/llvm/unittests/ProfileData/CoverageMappingTest.cpp b/llvm/unittests/ProfileData/CoverageMappingTest.cpp
index ef147674591c5..46f881ecddb5f 100644
--- a/llvm/unittests/ProfileData/CoverageMappingTest.cpp
+++ b/llvm/unittests/ProfileData/CoverageMappingTest.cpp
@@ -291,6 +291,45 @@ struct CoverageMappingTest : ::testing::TestWithParam<std::tuple<bool, bool>> {
   }
 };
 
+TEST(CoverageMappingTest, expression_subst) {
+  CounterExpressionBuilder Builder;
+  CounterExpressionBuilder::SubstMap MapToExpand;
+
+  auto C = [](unsigned ID) { return Counter::getCounter(ID); };
+  auto A = [&](Counter LHS, Counter RHS) { return Builder.add(LHS, RHS); };
+  // returns {E, N} in clangCodeGen
+  auto getBranchCounterPair = [&](Counter E, Counter P, Counter N) {
+    auto Skipped = Builder.subtract(P, E);
+    MapToExpand[N] = Builder.subst(Skipped, MapToExpand);
+  };
+
+  auto E18 = C(5);
+  auto P18 = C(2);
+  auto S18 = C(18);
+  // #18 => (#2 - #5)
+  getBranchCounterPair(E18, P18, S18);
+
+  auto E22 = S18;
+  auto P22 = C(0);
+  auto S22 = C(22);
+  // #22 => #0 - (#2 - #5)
+  getBranchCounterPair(E22, P22, S22);
+
+  auto E28 = A(A(C(9), C(11)), C(14));
+  auto P28 = S22;
+  auto S28 = C(28);
+  // #28 => (((((#0 + #5) - #2) - #9) - #11) - #14)
+  getBranchCounterPair(E28, P28, S28);
+
+  auto LHS = A(E28, A(S28, S18));
+  auto RHS = C(0);
+
+  // W/o subst, LHS cannot be reduced.
+  ASSERT_FALSE(Builder.subtract(LHS, RHS).isZero());
+  // W/ subst, C(18) and C(28) in LHS will be reduced.
+  ASSERT_TRUE(Builder.subst(Builder.subtract(LHS, RHS), MapToExpand).isZero());
+}
+
 TEST_P(CoverageMappingTest, basic_write_read) {
   startFunction("func", 0x1234);
   addCMR(Counter::getCounter(0), "foo", 1, 1, 1, 1);

>From d92a9d9c74814fc48c1ff5523d5215115021ac40 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Mon, 6 Jan 2025 23:38:11 +0900
Subject: [PATCH 50/72] Prune redundant logic

---
 llvm/lib/ProfileData/Coverage/CoverageMapping.cpp | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index 3f89414bdbbb9..87d305fc53636 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -157,10 +157,6 @@ Counter CounterExpressionBuilder::subst(Counter C, const SubstMap &Map) {
     break;
   }
 
-  // Reconfirm if the reconstructed expression would hit the Map.
-  if (auto I = Map.find(C); I != Map.end())
-    return I->second;
-
   return C;
 }
 

>From 82f2e92642fc00e0c07ed3c6506769319c39609a Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Tue, 7 Jan 2025 00:06:11 +0900
Subject: [PATCH 51/72] Expand RHS of MapToExpand. This will prevent recursion.

---
 clang/lib/CodeGen/CoverageMappingGen.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index 0764345af0b32..a00166881caaa 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -961,7 +961,7 @@ struct CounterCoverageMappingBuilder
 
     // Replace an expression (ParentCnt - ExecCnt) with SkipCnt.
     Counter SkipCnt = Counter::getCounter(TheMap.Skipped);
-    MapToExpand[SkipCnt] = Counters.Skipped;
+    MapToExpand[SkipCnt] = Builder.subst(Counters.Skipped, MapToExpand);
     Counters.Skipped = SkipCnt;
     return Counters;
   }

>From b90fdf61748ad0d585dc48987e5545878da98c59 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Tue, 7 Jan 2025 00:06:11 +0900
Subject: [PATCH 52/72] Append an explanation in the comment

---
 clang/lib/CodeGen/CoverageMappingGen.cpp | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index a00166881caaa..bd495f84793f6 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -990,6 +990,14 @@ struct CounterCoverageMappingBuilder
       return true;
 
     // Try comaparison with pre-replaced expressions.
+    //
+    // For example, getBranchCounterPair(#0) returns {#1, #0 - #1}.
+    // The sum of the pair should be equivalent to the Parent, #0.
+    // OTOH when (#0 - #1) is replaced with the new counter #2,
+    // The sum is (#1 + #2). If the reverse substitution #2 => (#0 - #1)
+    // can be applied, the sum can be transformed to (#1 + (#0 - #1)).
+    // To apply substitutions to both hand expressions, transform (LHS - RHS)
+    // and check isZero.
     if (Builder.subst(Builder.subtract(OutCount, ParentCount), MapToExpand)
             .isZero())
       return true;

>From 694a772457b2999b7bd68625a16bf0755e95dcdb Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Tue, 7 Jan 2025 11:26:52 +0900
Subject: [PATCH 53/72] Revert "Merge branch 'users/chapuni/cov/single/unify'
 into users/chapuni/cov/merge/mcdcsort-base"

This reverts commit c33e8987289f2775792977ee279c4e458f8091d5, reversing
changes made to ad6726dbfac5074c856f41adadb3b5bc14580311.
---
 .../ProfileData/Coverage/CoverageMapping.h    |  3 -
 .../ProfileData/Coverage/CoverageMapping.cpp  | 80 +++++++++----------
 2 files changed, 38 insertions(+), 45 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index a9ad258716a1c..504c24c27d84c 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -891,7 +891,6 @@ class InstantiationGroup {
 class CoverageData {
   friend class CoverageMapping;
 
-protected:
   std::string Filename;
   std::vector<CoverageSegment> Segments;
   std::vector<ExpansionRecord> Expansions;
@@ -906,8 +905,6 @@ class CoverageData {
   CoverageData(bool Single, StringRef Filename)
       : Filename(Filename), SingleByteCoverage(Single) {}
 
-  CoverageData(CoverageData &&RHS) = default;
-
   /// Get the name of the file this data covers.
   StringRef getFilename() const { return Filename; }
 
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index a8e13d5c73fb5..c196dbaab6694 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -1357,37 +1357,6 @@ class SegmentBuilder {
   }
 };
 
-struct MergeableCoverageData : public CoverageData {
-  std::vector<CountedRegion> CodeRegions;
-
-  MergeableCoverageData(bool Single, StringRef Filename)
-      : CoverageData(Single, Filename) {}
-
-  void addFunctionRegions(
-      const FunctionRecord &Function,
-      std::function<bool(const CounterMappingRegion &CR)> shouldProcess,
-      std::function<bool(const CountedRegion &CR)> shouldExpand) {
-    for (const auto &CR : Function.CountedRegions)
-      if (shouldProcess(CR)) {
-        CodeRegions.push_back(CR);
-        if (shouldExpand(CR))
-          Expansions.emplace_back(CR, Function);
-      }
-    // Capture branch regions specific to the function (excluding expansions).
-    for (const auto &CR : Function.CountedBranchRegions)
-      if (shouldProcess(CR))
-        BranchRegions.push_back(CR);
-    // Capture MCDC records specific to the function.
-    for (const auto &MR : Function.MCDCRecords)
-      if (shouldProcess(MR.getDecisionRegion()))
-        MCDCRecords.push_back(MR);
-  }
-
-  CoverageData buildSegments() {
-    Segments = SegmentBuilder::buildSegments(CodeRegions);
-    return CoverageData(std::move(*this));
-  }
-};
 } // end anonymous namespace
 
 std::vector<StringRef> CoverageMapping::getUniqueSourceFiles() const {
@@ -1439,7 +1408,8 @@ static bool isExpansion(const CountedRegion &R, unsigned FileID) {
 
 CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) const {
   assert(SingleByteCoverage);
-  MergeableCoverageData FileCoverage(*SingleByteCoverage, Filename);
+  CoverageData FileCoverage(*SingleByteCoverage, Filename);
+  std::vector<CountedRegion> Regions;
 
   // Look up the function records in the given file. Due to hash collisions on
   // the filename, we may get back some records that are not in the file.
@@ -1449,14 +1419,26 @@ CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) const {
     const FunctionRecord &Function = Functions[RecordIndex];
     auto MainFileID = findMainViewFileID(Filename, Function);
     auto FileIDs = gatherFileIDs(Filename, Function);
-    FileCoverage.addFunctionRegions(
-        Function, [&](auto &CR) { return FileIDs.test(CR.FileID); },
-        [&](auto &CR) { return (MainFileID && isExpansion(CR, *MainFileID)); });
+    for (const auto &CR : Function.CountedRegions)
+      if (FileIDs.test(CR.FileID)) {
+        Regions.push_back(CR);
+        if (MainFileID && isExpansion(CR, *MainFileID))
+          FileCoverage.Expansions.emplace_back(CR, Function);
+      }
+    // Capture branch regions specific to the function (excluding expansions).
+    for (const auto &CR : Function.CountedBranchRegions)
+      if (FileIDs.test(CR.FileID))
+        FileCoverage.BranchRegions.push_back(CR);
+    // Capture MCDC records specific to the function.
+    for (const auto &MR : Function.MCDCRecords)
+      if (FileIDs.test(MR.getDecisionRegion().FileID))
+        FileCoverage.MCDCRecords.push_back(MR);
   }
 
   LLVM_DEBUG(dbgs() << "Emitting segments for file: " << Filename << "\n");
+  FileCoverage.Segments = SegmentBuilder::buildSegments(Regions);
 
-  return FileCoverage.buildSegments();
+  return FileCoverage;
 }
 
 std::vector<InstantiationGroup>
@@ -1491,16 +1473,30 @@ CoverageMapping::getCoverageForFunction(const FunctionRecord &Function) const {
     return CoverageData();
 
   assert(SingleByteCoverage);
-  MergeableCoverageData FunctionCoverage(*SingleByteCoverage,
-                                         Function.Filenames[*MainFileID]);
-  FunctionCoverage.addFunctionRegions(
-      Function, [&](auto &CR) { return (CR.FileID == *MainFileID); },
-      [&](auto &CR) { return isExpansion(CR, *MainFileID); });
+  CoverageData FunctionCoverage(*SingleByteCoverage,
+                                Function.Filenames[*MainFileID]);
+  std::vector<CountedRegion> Regions;
+  for (const auto &CR : Function.CountedRegions)
+    if (CR.FileID == *MainFileID) {
+      Regions.push_back(CR);
+      if (isExpansion(CR, *MainFileID))
+        FunctionCoverage.Expansions.emplace_back(CR, Function);
+    }
+  // Capture branch regions specific to the function (excluding expansions).
+  for (const auto &CR : Function.CountedBranchRegions)
+    if (CR.FileID == *MainFileID)
+      FunctionCoverage.BranchRegions.push_back(CR);
+
+  // Capture MCDC records specific to the function.
+  for (const auto &MR : Function.MCDCRecords)
+    if (MR.getDecisionRegion().FileID == *MainFileID)
+      FunctionCoverage.MCDCRecords.push_back(MR);
 
   LLVM_DEBUG(dbgs() << "Emitting segments for function: " << Function.Name
                     << "\n");
+  FunctionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
 
-  return FunctionCoverage.buildSegments();
+  return FunctionCoverage;
 }
 
 CoverageData CoverageMapping::getCoverageForExpansion(

>From d854fb123be0449e83093f11e9f826c9baa3b766 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Wed, 8 Jan 2025 08:32:58 +0900
Subject: [PATCH 54/72] Rewind switch DefaultCase. (to #113112)

---
 clang/lib/CodeGen/CoverageMappingGen.cpp | 26 ++++++++----------------
 1 file changed, 9 insertions(+), 17 deletions(-)

diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index df29c2cb4ee17..d1968c5861c95 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -948,20 +948,6 @@ struct CounterCoverageMappingBuilder
     return {ExecCnt, Builder.subtract(ParentCnt, ExecCnt)};
   }
 
-  /// Returns {TrueCnt,FalseCnt} for "implicit default".
-  /// FalseCnt is considered as the False count on SwitchStmt.
-  std::pair<Counter, Counter>
-  getSwitchImplicitDefaultCounterPair(const Stmt *Cond, Counter ParentCount,
-                                      Counter CaseCountSum) {
-    // Simplify is skipped while building the counters above: it can get
-    // really slow on top of switches with thousands of cases. Instead,
-    // trigger simplification by adding zero to the last counter.
-    CaseCountSum =
-        addCounters(CaseCountSum, Counter::getZero(), /*Simplify=*/true);
-
-    return {CaseCountSum, Builder.subtract(ParentCount, CaseCountSum)};
-  }
-
   bool IsCounterEqual(Counter OutCount, Counter ParentCount) {
     if (OutCount == ParentCount)
       return true;
@@ -1920,9 +1906,15 @@ struct CounterCoverageMappingBuilder
     // the hidden branch, which will be added later by the CodeGen. This region
     // will be associated with the switch statement's condition.
     if (!HasDefaultCase) {
-      auto Counters = getSwitchImplicitDefaultCounterPair(
-          S->getCond(), ParentCount, CaseCountSum);
-      createBranchRegion(S->getCond(), Counters.first, Counters.second);
+      // Simplify is skipped while building the counters above: it can get
+      // really slow on top of switches with thousands of cases. Instead,
+      // trigger simplification by adding zero to the last counter.
+      CaseCountSum =
+          addCounters(CaseCountSum, Counter::getZero(), /*Simplify=*/true);
+
+      // This is considered as the False count on SwitchStmt.
+      Counter SwitchFalse = subtractCounters(ParentCount, CaseCountSum);
+      createBranchRegion(S->getCond(), CaseCountSum, SwitchFalse);
     }
   }
 

>From bac29679dcc3d1e2f4b01270d8b1abb0858c549e Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Wed, 8 Jan 2025 08:42:38 +0900
Subject: [PATCH 55/72] Enable addCounters

---
 clang/lib/CodeGen/CoverageMappingGen.cpp | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index d1968c5861c95..a973bcbb3f765 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -919,15 +919,11 @@ struct CounterCoverageMappingBuilder
 
   /// Return a counter for the sum of \c LHS and \c RHS.
   Counter addCounters(Counter LHS, Counter RHS, bool Simplify = true) {
-    assert(!llvm::EnableSingleByteCoverage &&
-           "cannot add counters when single byte coverage mode is enabled");
     return Builder.add(LHS, RHS, Simplify);
   }
 
   Counter addCounters(Counter C1, Counter C2, Counter C3,
                       bool Simplify = true) {
-    assert(!llvm::EnableSingleByteCoverage &&
-           "cannot add counters when single byte coverage mode is enabled");
     return addCounters(addCounters(C1, C2, Simplify), C3, Simplify);
   }
 

>From 6bae87d6193a88ab093ab472ff4a2d27f9e5e288 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Wed, 8 Jan 2025 09:05:46 +0900
Subject: [PATCH 56/72] Get rid of structual bindings

---
 clang/lib/CodeGen/CoverageMappingGen.cpp | 41 +++++++++++++-----------
 1 file changed, 23 insertions(+), 18 deletions(-)

diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index a973bcbb3f765..c03eb6a55af5e 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -1601,12 +1601,13 @@ struct CounterCoverageMappingBuilder
         llvm::EnableSingleByteCoverage
             ? getRegionCounter(S->getCond())
             : addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
-    auto [ExecCount, ExitCount] =
+    auto BranchCount =
         (llvm::EnableSingleByteCoverage
              ? BranchCounterPair{getRegionCounter(S), Counter::getZero()}
              : getBranchCounterPair(S, CondCount));
     if (!llvm::EnableSingleByteCoverage) {
-      assert(ExecCount.isZero() || ExecCount == BodyCount);
+      assert(BranchCount.Executed.isZero() ||
+             BranchCount.Executed == BodyCount);
     }
     propagateCounts(CondCount, S->getCond());
     adjustForOutOfOrderTraversal(getEnd(S));
@@ -1618,7 +1619,7 @@ struct CounterCoverageMappingBuilder
 
     Counter OutCount = llvm::EnableSingleByteCoverage
                            ? getRegionCounter(S)
-                           : addCounters(BC.BreakCount, ExitCount);
+                           : addCounters(BC.BreakCount, BranchCount.Skipped);
 
     if (!IsCounterEqual(OutCount, ParentCount)) {
       pushRegion(OutCount);
@@ -1629,7 +1630,7 @@ struct CounterCoverageMappingBuilder
 
     // Create Branch Region around condition.
     if (!llvm::EnableSingleByteCoverage)
-      createBranchRegion(S->getCond(), BodyCount, ExitCount);
+      createBranchRegion(S->getCond(), BodyCount, BranchCount.Skipped);
   }
 
   void VisitDoStmt(const DoStmt *S) {
@@ -1658,18 +1659,19 @@ struct CounterCoverageMappingBuilder
     Counter CondCount = llvm::EnableSingleByteCoverage
                             ? getRegionCounter(S->getCond())
                             : addCounters(BackedgeCount, BC.ContinueCount);
-    auto [ExecCount, ExitCount] =
+    auto BranchCount =
         (llvm::EnableSingleByteCoverage
              ? BranchCounterPair{getRegionCounter(S), Counter::getZero()}
              : getBranchCounterPair(S, CondCount));
     if (!llvm::EnableSingleByteCoverage) {
-      assert(ExecCount.isZero() || ExecCount == BodyCount);
+      assert(BranchCount.Executed.isZero() ||
+             BranchCount.Executed == BodyCount);
     }
     propagateCounts(CondCount, S->getCond());
 
     Counter OutCount = llvm::EnableSingleByteCoverage
                            ? getRegionCounter(S)
-                           : addCounters(BC.BreakCount, ExitCount);
+                           : addCounters(BC.BreakCount, BranchCount.Skipped);
     if (!IsCounterEqual(OutCount, ParentCount)) {
       pushRegion(OutCount);
       GapRegionCounter = OutCount;
@@ -1677,7 +1679,7 @@ struct CounterCoverageMappingBuilder
 
     // Create Branch Region around condition.
     if (!llvm::EnableSingleByteCoverage)
-      createBranchRegion(S->getCond(), BodyCount, ExitCount);
+      createBranchRegion(S->getCond(), BodyCount, BranchCount.Skipped);
 
     if (BodyHasTerminateStmt)
       HasTerminateStmt = true;
@@ -1726,12 +1728,13 @@ struct CounterCoverageMappingBuilder
             : addCounters(
                   addCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount),
                   IncrementBC.ContinueCount);
-    auto [ExecCount, ExitCount] =
+    auto BranchCount =
         (llvm::EnableSingleByteCoverage
              ? BranchCounterPair{getRegionCounter(S), Counter::getZero()}
              : getBranchCounterPair(S, CondCount));
     if (!llvm::EnableSingleByteCoverage) {
-      assert(ExecCount.isZero() || ExecCount == BodyCount);
+      assert(BranchCount.Executed.isZero() ||
+             BranchCount.Executed == BodyCount);
     }
 
     if (const Expr *Cond = S->getCond()) {
@@ -1747,7 +1750,8 @@ struct CounterCoverageMappingBuilder
     Counter OutCount =
         llvm::EnableSingleByteCoverage
             ? getRegionCounter(S)
-            : addCounters(BodyBC.BreakCount, IncrementBC.BreakCount, ExitCount);
+            : addCounters(BodyBC.BreakCount, IncrementBC.BreakCount,
+                          BranchCount.Skipped);
     if (!IsCounterEqual(OutCount, ParentCount)) {
       pushRegion(OutCount);
       GapRegionCounter = OutCount;
@@ -1757,7 +1761,7 @@ struct CounterCoverageMappingBuilder
 
     // Create Branch Region around condition.
     if (!llvm::EnableSingleByteCoverage)
-      createBranchRegion(S->getCond(), BodyCount, ExitCount);
+      createBranchRegion(S->getCond(), BodyCount, BranchCount.Skipped);
   }
 
   void VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
@@ -1792,9 +1796,10 @@ struct CounterCoverageMappingBuilder
       OutCount = getRegionCounter(S);
     else {
       LoopCount = addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
-      auto [ExecCount, SkipCount] = getBranchCounterPair(S, LoopCount);
-      ExitCount = SkipCount;
-      assert(ExecCount.isZero() || ExecCount == BodyCount);
+      auto BranchCount = getBranchCounterPair(S, LoopCount);
+      ExitCount = BranchCount.Skipped;
+      assert(BranchCount.Executed.isZero() ||
+             BranchCount.Executed == BodyCount);
       OutCount = addCounters(BC.BreakCount, ExitCount);
     }
     if (!IsCounterEqual(OutCount, ParentCount)) {
@@ -1828,9 +1833,9 @@ struct CounterCoverageMappingBuilder
 
     Counter LoopCount =
         addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
-    auto [ExecCount, ExitCount] = getBranchCounterPair(S, LoopCount);
-    assert(ExecCount.isZero() || ExecCount == BodyCount);
-    Counter OutCount = addCounters(BC.BreakCount, ExitCount);
+    auto BranchCount = getBranchCounterPair(S, LoopCount);
+    assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount);
+    Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
     if (!IsCounterEqual(OutCount, ParentCount)) {
       pushRegion(OutCount);
       GapRegionCounter = OutCount;

>From c8edf58d644e80281e00577920125fa1d7618f47 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Wed, 8 Jan 2025 09:22:58 +0900
Subject: [PATCH 57/72] Flatten with getBranchCounterPair(SkipCntForOld)

---
 clang/lib/CodeGen/CoverageMappingGen.cpp | 95 +++++++++++-------------
 1 file changed, 44 insertions(+), 51 deletions(-)

diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index c03eb6a55af5e..0495a60e53c24 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -939,8 +939,17 @@ struct CounterCoverageMappingBuilder
     Counter Skipped;
   };
 
-  BranchCounterPair getBranchCounterPair(const Stmt *S, Counter ParentCnt) {
+  BranchCounterPair
+  getBranchCounterPair(const Stmt *S, Counter ParentCnt,
+                       std::optional<Counter> SkipCntForOld = std::nullopt) {
     Counter ExecCnt = getRegionCounter(S);
+
+    // The old behavior of SingleByte shouldn't emit Branches.
+    if (llvm::EnableSingleByteCoverage) {
+      assert(SkipCntForOld);
+      return {ExecCnt, *SkipCntForOld};
+    }
+
     return {ExecCnt, Builder.subtract(ParentCnt, ExecCnt)};
   }
 
@@ -1601,14 +1610,10 @@ struct CounterCoverageMappingBuilder
         llvm::EnableSingleByteCoverage
             ? getRegionCounter(S->getCond())
             : addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
-    auto BranchCount =
-        (llvm::EnableSingleByteCoverage
-             ? BranchCounterPair{getRegionCounter(S), Counter::getZero()}
-             : getBranchCounterPair(S, CondCount));
-    if (!llvm::EnableSingleByteCoverage) {
-      assert(BranchCount.Executed.isZero() ||
-             BranchCount.Executed == BodyCount);
-    }
+    auto BranchCount = getBranchCounterPair(S, CondCount, getRegionCounter(S));
+    assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount ||
+           llvm::EnableSingleByteCoverage);
+
     propagateCounts(CondCount, S->getCond());
     adjustForOutOfOrderTraversal(getEnd(S));
 
@@ -1617,10 +1622,10 @@ struct CounterCoverageMappingBuilder
     if (Gap)
       fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
 
-    Counter OutCount = llvm::EnableSingleByteCoverage
-                           ? getRegionCounter(S)
-                           : addCounters(BC.BreakCount, BranchCount.Skipped);
-
+    assert(
+        !llvm::EnableSingleByteCoverage ||
+        (BC.BreakCount.isZero() && BranchCount.Skipped == getRegionCounter(S)));
+    Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
     if (!IsCounterEqual(OutCount, ParentCount)) {
       pushRegion(OutCount);
       GapRegionCounter = OutCount;
@@ -1659,19 +1664,16 @@ struct CounterCoverageMappingBuilder
     Counter CondCount = llvm::EnableSingleByteCoverage
                             ? getRegionCounter(S->getCond())
                             : addCounters(BackedgeCount, BC.ContinueCount);
-    auto BranchCount =
-        (llvm::EnableSingleByteCoverage
-             ? BranchCounterPair{getRegionCounter(S), Counter::getZero()}
-             : getBranchCounterPair(S, CondCount));
-    if (!llvm::EnableSingleByteCoverage) {
-      assert(BranchCount.Executed.isZero() ||
-             BranchCount.Executed == BodyCount);
-    }
+    auto BranchCount = getBranchCounterPair(S, CondCount, getRegionCounter(S));
+    assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount ||
+           llvm::EnableSingleByteCoverage);
+
     propagateCounts(CondCount, S->getCond());
 
-    Counter OutCount = llvm::EnableSingleByteCoverage
-                           ? getRegionCounter(S)
-                           : addCounters(BC.BreakCount, BranchCount.Skipped);
+    assert(
+        !llvm::EnableSingleByteCoverage ||
+        (BC.BreakCount.isZero() && BranchCount.Skipped == getRegionCounter(S)));
+    Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
     if (!IsCounterEqual(OutCount, ParentCount)) {
       pushRegion(OutCount);
       GapRegionCounter = OutCount;
@@ -1728,14 +1730,9 @@ struct CounterCoverageMappingBuilder
             : addCounters(
                   addCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount),
                   IncrementBC.ContinueCount);
-    auto BranchCount =
-        (llvm::EnableSingleByteCoverage
-             ? BranchCounterPair{getRegionCounter(S), Counter::getZero()}
-             : getBranchCounterPair(S, CondCount));
-    if (!llvm::EnableSingleByteCoverage) {
-      assert(BranchCount.Executed.isZero() ||
-             BranchCount.Executed == BodyCount);
-    }
+    auto BranchCount = getBranchCounterPair(S, CondCount, getRegionCounter(S));
+    assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount ||
+           llvm::EnableSingleByteCoverage);
 
     if (const Expr *Cond = S->getCond()) {
       propagateCounts(CondCount, Cond);
@@ -1747,11 +1744,10 @@ struct CounterCoverageMappingBuilder
     if (Gap)
       fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
 
-    Counter OutCount =
-        llvm::EnableSingleByteCoverage
-            ? getRegionCounter(S)
-            : addCounters(BodyBC.BreakCount, IncrementBC.BreakCount,
-                          BranchCount.Skipped);
+    assert(!llvm::EnableSingleByteCoverage ||
+           (BodyBC.BreakCount.isZero() && IncrementBC.BreakCount.isZero()));
+    Counter OutCount = addCounters(BodyBC.BreakCount, IncrementBC.BreakCount,
+                                   BranchCount.Skipped);
     if (!IsCounterEqual(OutCount, ParentCount)) {
       pushRegion(OutCount);
       GapRegionCounter = OutCount;
@@ -1789,19 +1785,16 @@ struct CounterCoverageMappingBuilder
     if (Gap)
       fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
 
-    Counter OutCount;
-    Counter ExitCount;
-    Counter LoopCount;
-    if (llvm::EnableSingleByteCoverage)
-      OutCount = getRegionCounter(S);
-    else {
-      LoopCount = addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
-      auto BranchCount = getBranchCounterPair(S, LoopCount);
-      ExitCount = BranchCount.Skipped;
-      assert(BranchCount.Executed.isZero() ||
-             BranchCount.Executed == BodyCount);
-      OutCount = addCounters(BC.BreakCount, ExitCount);
-    }
+    Counter LoopCount =
+        addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
+    auto BranchCount = getBranchCounterPair(S, LoopCount, getRegionCounter(S));
+    assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount ||
+           llvm::EnableSingleByteCoverage);
+    assert(
+        !llvm::EnableSingleByteCoverage ||
+        (BC.BreakCount.isZero() && BranchCount.Skipped == getRegionCounter(S)));
+
+    Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
     if (!IsCounterEqual(OutCount, ParentCount)) {
       pushRegion(OutCount);
       GapRegionCounter = OutCount;
@@ -1811,7 +1804,7 @@ struct CounterCoverageMappingBuilder
 
     // Create Branch Region around condition.
     if (!llvm::EnableSingleByteCoverage)
-      createBranchRegion(S->getCond(), BodyCount, ExitCount);
+      createBranchRegion(S->getCond(), BodyCount, BranchCount.Skipped);
   }
 
   void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) {

>From f2ba2192053cd335f8f848071b1e08fc6f071808 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Wed, 8 Jan 2025 18:10:52 +0900
Subject: [PATCH 58/72] Update comments

---
 clang/lib/CodeGen/CoverageMappingGen.cpp | 22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index 0495a60e53c24..8bc5d73bbd0ce 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -935,16 +935,32 @@ struct CounterCoverageMappingBuilder
   }
 
   struct BranchCounterPair {
-    Counter Executed;
-    Counter Skipped;
+    Counter Executed; ///< The Counter previously assigned.
+    Counter Skipped;  ///< An expression (Parent-Executed), or equivalent to it.
   };
 
+  /// Retrieve or assign the pair of Counter(s).
+  ///
+  /// This returns BranchCounterPair {Executed, Skipped}.
+  /// Executed is the Counter associated with S assigned by an earlier
+  /// CounterMapping pass.
+  /// Skipped may be an expression (Executed - ParentCnt) or newly
+  /// assigned Counter in EnableSingleByteCoverage, as subtract
+  /// expressions are not available in this mode.
+  ///
+  /// \param S Key to the CounterMap
+  /// \param ParentCnt The Counter representing how many times S is evaluated.
+  /// \param SkipCntForOld (To be removed later) Optional fake Counter
+  ///                      to override Skipped for adjustment of
+  ///                      expressions in the old behavior of
+  ///                      EnableSingleByteCoverage that is unaware of
+  ///                      Branch coverage.
   BranchCounterPair
   getBranchCounterPair(const Stmt *S, Counter ParentCnt,
                        std::optional<Counter> SkipCntForOld = std::nullopt) {
     Counter ExecCnt = getRegionCounter(S);
 
-    // The old behavior of SingleByte shouldn't emit Branches.
+    // The old behavior of SingleByte is unaware of Branches.
     if (llvm::EnableSingleByteCoverage) {
       assert(SkipCntForOld);
       return {ExecCnt, *SkipCntForOld};

>From 97015cb5e015a517d83bf67e3e8f65310f51bc55 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Wed, 8 Jan 2025 18:11:02 +0900
Subject: [PATCH 59/72] Decorate the mock

---
 clang/lib/CodeGen/CoverageMappingGen.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index 8bc5d73bbd0ce..72c027fa8e566 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -962,7 +962,8 @@ struct CounterCoverageMappingBuilder
 
     // The old behavior of SingleByte is unaware of Branches.
     if (llvm::EnableSingleByteCoverage) {
-      assert(SkipCntForOld);
+      assert(SkipCntForOld &&
+             "SingleByte must provide SkipCntForOld as a fake Skipped count.");
       return {ExecCnt, *SkipCntForOld};
     }
 

>From 9a40d20d0c468f7da49d156fd4c7752e9902033b Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Thu, 9 Jan 2025 14:11:45 +0900
Subject: [PATCH 60/72] Will be pruned after the migration of SingleByte.

---
 clang/lib/CodeGen/CoverageMappingGen.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index 72c027fa8e566..dfffa12b639f2 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -961,6 +961,7 @@ struct CounterCoverageMappingBuilder
     Counter ExecCnt = getRegionCounter(S);
 
     // The old behavior of SingleByte is unaware of Branches.
+    // Will be pruned after the migration of SingleByte.
     if (llvm::EnableSingleByteCoverage) {
       assert(SkipCntForOld &&
              "SingleByte must provide SkipCntForOld as a fake Skipped count.");

>From b548e71a3cf55167d5b49e010cc76c8c82f29280 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Thu, 9 Jan 2025 15:19:00 +0900
Subject: [PATCH 61/72] Add comments

---
 llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index dad5f1276f27c..edae71491191e 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -215,9 +215,12 @@ class CounterExpressionBuilder {
   /// LHS.
   Counter subtract(Counter LHS, Counter RHS, bool Simplify = true);
 
+  /// K to V map. K will be Counter in most cases. V may be Counter or
+  /// Expression.
   using SubstMap = std::map<Counter, Counter>;
 
-  /// Return a counter for each term in the expression replaced by SubstMap.
+  /// \return A counter equivalent to \C, with each term in its
+  /// expression replaced with term from \p Map.
   Counter subst(Counter C, const SubstMap &Map);
 };
 

>From a6d4be0e4b05b411c7160385485cfed0f173965c Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Sun, 2 Feb 2025 21:55:43 +0900
Subject: [PATCH 62/72] [MC/DC] Update CoverageMapping tests

To resolve the error, rename mcdc-error-nests.cpp -> mcdc-nested-expr.cpp at first.

- `func_condop`
  A corner case that contains close decisions.
- `func_expect`
  Uses `__builtin_expect`. (#124565)
- `func_lnot`
  Contains logical not(s) `!` among MC/DC binary operators. (#124563)

mcdc-single-cond.cpp is for #95336.
---
 .../test/CoverageMapping/mcdc-error-nests.cpp | 10 --
 .../test/CoverageMapping/mcdc-nested-expr.cpp | 34 +++++++
 .../test/CoverageMapping/mcdc-single-cond.cpp | 97 +++++++++++++++++++
 3 files changed, 131 insertions(+), 10 deletions(-)
 delete mode 100644 clang/test/CoverageMapping/mcdc-error-nests.cpp
 create mode 100644 clang/test/CoverageMapping/mcdc-nested-expr.cpp
 create mode 100644 clang/test/CoverageMapping/mcdc-single-cond.cpp

diff --git a/clang/test/CoverageMapping/mcdc-error-nests.cpp b/clang/test/CoverageMapping/mcdc-error-nests.cpp
deleted file mode 100644
index 3add2b9ccd3fb..0000000000000
--- a/clang/test/CoverageMapping/mcdc-error-nests.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++11 -fcoverage-mcdc -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only %s 2>&1| FileCheck %s
-
-// "Split-nest" -- boolean expressions within boolean expressions.
-extern bool bar(bool);
-bool func_split_nest(bool a, bool b, bool c, bool d, bool e, bool f, bool g) {
-  bool res = a && b && c && bar(d && e) && f && g;
-  return bar(res);
-}
-
-// CHECK: warning: unsupported MC/DC boolean expression; contains an operation with a nested boolean expression.
diff --git a/clang/test/CoverageMapping/mcdc-nested-expr.cpp b/clang/test/CoverageMapping/mcdc-nested-expr.cpp
new file mode 100644
index 0000000000000..bb82873e3b600
--- /dev/null
+++ b/clang/test/CoverageMapping/mcdc-nested-expr.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++11 -fcoverage-mcdc -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only %s 2> %t.stderr.txt | FileCheck %s
+// RUN: FileCheck %s --check-prefix=WARN < %t.stderr.txt
+
+// "Split-nest" -- boolean expressions within boolean expressions.
+extern bool bar(bool);
+// CHECK: func_split_nest{{.*}}:
+bool func_split_nest(bool a, bool b, bool c, bool d, bool e, bool f, bool g) {
+  // WARN: :[[@LINE+1]]:14: warning: unsupported MC/DC boolean expression; contains an operation with a nested boolean expression.
+  bool res = a && b && c && bar(d && e) && f && g;
+  return bar(res);
+}
+
+// The inner expr begins with the same Loc as the outer expr
+// CHECK: func_condop{{.*}}:
+bool func_condop(bool a, bool b, bool c) {
+  // WARN: :[[@LINE+1]]:10: warning: unsupported MC/DC boolean expression; contains an operation with a nested boolean expression.
+  return (a && b ? true : false) && c;
+}
+
+// __builtin_expect
+// Treated as parentheses.
+// CHECK: func_expect{{.*}}:
+bool func_expect(bool a, bool b, bool c) {
+  // WARN: :[[@LINE+1]]:10: warning: unsupported MC/DC boolean expression; contains an operation with a nested boolean expression.
+  return a || __builtin_expect(b && c, true);
+}
+
+// LNot among BinOp(s)
+// Doesn't split exprs.
+// CHECK: func_lnot{{.*}}:
+bool func_lnot(bool a, bool b, bool c, bool d) {
+  // WARN: :[[@LINE+1]]:10: warning: unsupported MC/DC boolean expression; contains an operation with a nested boolean expression.
+  return !(a || b) && !(c && d);
+}
diff --git a/clang/test/CoverageMapping/mcdc-single-cond.cpp b/clang/test/CoverageMapping/mcdc-single-cond.cpp
new file mode 100644
index 0000000000000..b1eeea879e521
--- /dev/null
+++ b/clang/test/CoverageMapping/mcdc-single-cond.cpp
@@ -0,0 +1,97 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++11 -fcoverage-mcdc -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -disable-llvm-passes -emit-llvm -o %t2.ll %s | FileCheck %s --check-prefixes=MM,MM2
+// RUN: FileCheck %s --check-prefixes=LL,LL2 < %t2.ll
+
+// LL: define{{.+}}func_cond{{.+}}(
+// MM: func_cond{{.*}}:
+int func_cond(bool a, bool b) {
+  // %mcdc.addr* are emitted by static order.
+  // LL:   %[[MA:mcdc.addr.*]] = alloca i32, align 4
+  // LL:  call void @llvm.instrprof.mcdc.parameters(ptr @[[PROFN:.+]], i64 [[#H:]], i32 [[#BS:]])
+  int count = 0;
+  if (a)
+    // NB=2 Single cond
+    // MM2-NOT: Decision
+    ++count;
+  if (a ? true : false)
+    // NB=2,2 Wider decision comes first.
+    // MA2 has C:2
+    // MA3 has C:1
+    ++count;
+  if (a && b ? true : false)
+    // NB=2,3 Wider decision comes first.
+    // MM2:  Decision,File 0, [[@LINE-2]]:7 -> [[#L:@LINE-2]]:13 = M:[[#I:3]], C:2
+    // MM:   Branch,File 0, [[#L]]:7 -> [[#L]]:8 = #6, (#0 - #6) [1,2,0]
+    // MM:   Branch,File 0, [[#L]]:12 -> [[#L]]:13 = #7, (#6 - #7) [2,0,0]
+    // LL:   store i32 0, ptr %[[MA]], align 4
+    // LL:   = load i32, ptr %[[MA]], align 4
+    // LL:   store i32 %{{.+}}, ptr %[[MA]], align 4
+    // LL:   = load i32, ptr %[[MA]], align 4
+    // LL:   store i32 %{{.+}}, ptr %[[MA]], align 4
+    // LL2:  call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:0]], ptr %[[MA]])
+    ++count;
+  while (a || true) {
+    // NB=3 BinOp only
+    // MM:   Decision,File 0, [[@LINE-2]]:10 -> [[#L:@LINE-2]]:19 = M:[[#I:I+3]], C:2
+    // MM:   Branch,File 0, [[#L]]:10 -> [[#L]]:11 = (#0 - #9), #9 [1,0,2]
+    // MM:   Branch,File 0, [[#L]]:15 -> [[#L]]:19 = (#9 - #10), 0 [2,0,0]
+    // LL:   store i32 0, ptr %[[MA]], align 4
+    // LL:   = load i32, ptr %[[MA]], align 4
+    // LL:   store i32 %{{.+}}, ptr %[[MA]], align 4
+    // LL:   = load i32, ptr %[[MA]], align 4
+    // LL:   store i32 %{{.+}}, ptr %[[MA]], align 4
+    // LL2:  call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA]])
+    ++count;
+    break;
+  }
+  while (a || true ? false : true) {
+    // Wider decision comes first.
+    // MM2:  Decision,File 0, [[@LINE-2]]:10 -> [[#L:@LINE-2]]:19 = M:[[#I:I+3]], C:2
+    // MM:   Branch,File 0, [[#L]]:10 -> [[#L]]:11 = ((#0 + #11) - #13), #13 [1,0,2]
+    // MM:   Branch,File 0, [[#L]]:15 -> [[#L]]:19 = (#13 - #14), 0 [2,0,0]
+    // LL:   store i32 0, ptr %[[MA]], align 4
+    // LL:   = load i32, ptr %[[MA]], align 4
+    // LL:   store i32 %{{.+}}, ptr %[[MA]], align 4
+    // LL:   = load i32, ptr %[[MA]], align 4
+    // LL:   store i32 %{{.+}}, ptr %[[MA]], align 4
+    // LL:   call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA]])
+    ++count;
+  }
+  do {
+    ++count;
+  } while (a && false);
+  // BinOp only
+  // MM:   Decision,File 0, [[@LINE-2]]:12 -> [[#L:@LINE-2]]:22 = M:[[#I:I+3]], C:2
+  // MM:   Branch,File 0, [[#L]]:12 -> [[#L]]:13 = #16, ((#0 + #15) - #16) [1,2,0]
+  // MM:   Branch,File 0, [[#L]]:17 -> [[#L]]:22 = 0, (#16 - #17) [2,0,0]
+  // LL:   store i32 0, ptr %[[MA]], align 4
+  // LL:   = load i32, ptr %[[MA]], align 4
+  // LL:   store i32 %{{.+}}, ptr %[[MA]], align 4
+  // LL:   = load i32, ptr %[[MA]], align 4
+  // LL:   store i32 %{{.+}}, ptr %[[MA]], align 4
+  // LL2:  call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA]])
+  do {
+    ++count;
+  } while (a && false ? true : false);
+  // Wider decision comes first.
+  // MM2:  Decision,File 0, [[@LINE-2]]:12 -> [[#L:@LINE-2]]:22 = M:15, C:2
+  // MM:   Branch,File 0, [[#L]]:12 -> [[#L]]:13 = #20, ((#0 + #18) - #20) [1,2,0]
+  // MM:   Branch,File 0, [[#L]]:17 -> [[#L]]:22 = 0, (#20 - #21) [2,0,0]
+  // LL:   store i32 0, ptr %[[MA]], align 4
+  // LL:   = load i32, ptr %[[MA]], align 4
+  // LL:   store i32 %{{.+}}, ptr %[[MA]], align 4
+  // LL:   = load i32, ptr %[[MA]], align 4
+  // LL:   store i32 %{{.+}}, ptr %[[MA]], align 4
+  // LL:   call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA]])
+  // FIXME: Confirm (B+3==BS)
+  for (int i = 0; i < (a ? 2 : 1); ++i) {
+    // Simple nested decision (different column)
+    // MM2-NOT: Decision
+    // LL2-NOT: call void @llvm.instrprof.mcdc.tvbitmap.update
+    ++count;
+  }
+  for (int i = 0; i >= 4 ? false : true; ++i) {
+    // Wider decision comes first.
+    ++count;
+  }
+  return count;
+}

>From d414f29ed8732c77fdcd05cc3b066e9ee0d9de07 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Sun, 2 Feb 2025 21:59:33 +0900
Subject: [PATCH 63/72] [MC/DC] Refactor MCDC::State::Decision. NFC.

Introduce `ID` and `InvalidID`. Then `DecisionByStmt` can have three
states.

* Not assigned if the Stmt(Expr) doesn't exist.
* When `DecisionByStmt[Expr]` exists:
  * Invalid and should be ignored if `ID == Invalid`.
  * Valid if `ID != Invalid`. Other member will be filled in the
    Mapper.
---
 clang/lib/CodeGen/CodeGenPGO.cpp         |  2 +-
 clang/lib/CodeGen/CoverageMappingGen.cpp |  6 ++----
 clang/lib/CodeGen/MCDCState.h            | 16 +++++++++++++++-
 3 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/clang/lib/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp
index 792373839107f..0331ff83e633f 100644
--- a/clang/lib/CodeGen/CodeGenPGO.cpp
+++ b/clang/lib/CodeGen/CodeGenPGO.cpp
@@ -310,7 +310,7 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
           }
 
           // Otherwise, allocate the Decision.
-          MCDCState.DecisionByStmt[BinOp].BitmapIdx = 0;
+          MCDCState.DecisionByStmt[BinOp].ID = MCDCState.DecisionByStmt.size();
         }
         return true;
       }
diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index f09157771d2b5..4dbc0c70e34d6 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -2197,10 +2197,8 @@ struct CounterCoverageMappingBuilder
 
     // Update the state for CodeGenPGO
     assert(MCDCState.DecisionByStmt.contains(E));
-    MCDCState.DecisionByStmt[E] = {
-        MCDCState.BitmapBits, // Top
-        std::move(Builder.Indices),
-    };
+    MCDCState.DecisionByStmt[E].update(MCDCState.BitmapBits, // Top
+                                       std::move(Builder.Indices));
 
     auto DecisionParams = mcdc::DecisionParameters{
         MCDCState.BitmapBits += NumTVs, // Tail
diff --git a/clang/lib/CodeGen/MCDCState.h b/clang/lib/CodeGen/MCDCState.h
index e0dd28ff90ed1..0b6f5f28235f4 100644
--- a/clang/lib/CodeGen/MCDCState.h
+++ b/clang/lib/CodeGen/MCDCState.h
@@ -16,6 +16,8 @@
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ProfileData/Coverage/MCDCTypes.h"
+#include <cassert>
+#include <limits>
 
 namespace clang {
 class Stmt;
@@ -30,8 +32,20 @@ struct State {
   unsigned BitmapBits = 0;
 
   struct Decision {
+    using IndicesTy = llvm::SmallVector<std::array<int, 2>>;
+    static constexpr auto InvalidID = std::numeric_limits<unsigned>::max();
+
     unsigned BitmapIdx;
-    llvm::SmallVector<std::array<int, 2>> Indices;
+    IndicesTy Indices;
+    unsigned ID = InvalidID;
+
+    bool isValid() const { return ID != InvalidID; }
+
+    void update(unsigned I, IndicesTy &&X) {
+      assert(ID != InvalidID);
+      BitmapIdx = I;
+      Indices = std::move(X);
+    }
   };
 
   llvm::DenseMap<const Stmt *, Decision> DecisionByStmt;

>From c74e5af3fb458230931d7cbba5d32e5999c38bf4 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Sun, 2 Feb 2025 22:01:40 +0900
Subject: [PATCH 64/72] [MC/DC] Create dedicated MCDCCondBitmapAddr for each
 Decision

MCDCCondBitmapAddr is moved from `CodeGenFunction` into `MCDCState`
and created for each Decision.

In `maybeCreateMCDCCondBitmap`, Allocate bitmaps for all valid
Decisions and emit them order by ID, to prevent nondeterminism.
---
 clang/lib/CodeGen/CodeGenFunction.h           |  17 +--
 clang/lib/CodeGen/CodeGenPGO.cpp              |  41 +++++--
 clang/lib/CodeGen/CodeGenPGO.h                |   8 +-
 clang/lib/CodeGen/MCDCState.h                 |   2 +
 .../test/CoverageMapping/mcdc-single-cond.cpp | 101 ++++++++++++++++++
 clang/test/Profile/c-mcdc-logicalop-ternary.c |  18 ++--
 6 files changed, 160 insertions(+), 27 deletions(-)
 create mode 100644 clang/test/CoverageMapping/mcdc-single-cond.cpp

diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index e978cad433623..20d81ba3a3bde 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -1628,9 +1628,6 @@ class CodeGenFunction : public CodeGenTypeCache {
 
   CodeGenPGO PGO;
 
-  /// Bitmap used by MC/DC to track condition outcomes of a boolean expression.
-  Address MCDCCondBitmapAddr = Address::invalid();
-
   /// Calculate branch weights appropriate for PGO data
   llvm::MDNode *createProfileWeights(uint64_t TrueCount,
                                      uint64_t FalseCount) const;
@@ -1669,8 +1666,12 @@ class CodeGenFunction : public CodeGenTypeCache {
   void maybeCreateMCDCCondBitmap() {
     if (isMCDCCoverageEnabled()) {
       PGO.emitMCDCParameters(Builder);
-      MCDCCondBitmapAddr =
-          CreateIRTemp(getContext().UnsignedIntTy, "mcdc.addr");
+
+      // Set up MCDCCondBitmapAddr for each Decision.
+      // Note: This doesn't initialize Addrs in invalidated Decisions.
+      for (auto *MCDCCondBitmapAddr : PGO.getMCDCCondBitmapAddrArray(Builder))
+        *MCDCCondBitmapAddr =
+            CreateIRTemp(getContext().UnsignedIntTy, "mcdc.addr");
     }
   }
 
@@ -1682,7 +1683,7 @@ class CodeGenFunction : public CodeGenTypeCache {
   /// Zero-init the MCDC temp value.
   void maybeResetMCDCCondBitmap(const Expr *E) {
     if (isMCDCCoverageEnabled() && isBinaryLogicalOp(E)) {
-      PGO.emitMCDCCondBitmapReset(Builder, E, MCDCCondBitmapAddr);
+      PGO.emitMCDCCondBitmapReset(Builder, E);
       PGO.setCurrentStmt(E);
     }
   }
@@ -1691,7 +1692,7 @@ class CodeGenFunction : public CodeGenTypeCache {
   /// If \p StepV is null, the default increment is 1.
   void maybeUpdateMCDCTestVectorBitmap(const Expr *E) {
     if (isMCDCCoverageEnabled() && isBinaryLogicalOp(E)) {
-      PGO.emitMCDCTestVectorBitmapUpdate(Builder, E, MCDCCondBitmapAddr, *this);
+      PGO.emitMCDCTestVectorBitmapUpdate(Builder, E, *this);
       PGO.setCurrentStmt(E);
     }
   }
@@ -1699,7 +1700,7 @@ class CodeGenFunction : public CodeGenTypeCache {
   /// Update the MCDC temp value with the condition's evaluated result.
   void maybeUpdateMCDCCondBitmap(const Expr *E, llvm::Value *Val) {
     if (isMCDCCoverageEnabled()) {
-      PGO.emitMCDCCondBitmapUpdate(Builder, E, MCDCCondBitmapAddr, Val, *this);
+      PGO.emitMCDCCondBitmapUpdate(Builder, E, Val, *this);
       PGO.setCurrentStmt(E);
     }
   }
diff --git a/clang/lib/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp
index 0331ff83e633f..7d16f673ada41 100644
--- a/clang/lib/CodeGen/CodeGenPGO.cpp
+++ b/clang/lib/CodeGen/CodeGenPGO.cpp
@@ -1245,9 +1245,29 @@ void CodeGenPGO::emitMCDCParameters(CGBuilderTy &Builder) {
       CGM.getIntrinsic(llvm::Intrinsic::instrprof_mcdc_parameters), Args);
 }
 
+/// Fill mcdc.addr order by ID.
+std::vector<Address *>
+CodeGenPGO::getMCDCCondBitmapAddrArray(CGBuilderTy &Builder) {
+  std::vector<Address *> Result;
+
+  if (!canEmitMCDCCoverage(Builder) || !RegionMCDCState)
+    return Result;
+
+  SmallVector<std::pair<unsigned, Address *>> SortedPair;
+  for (auto &[_, V] : RegionMCDCState->DecisionByStmt)
+    if (V.isValid())
+      SortedPair.emplace_back(V.ID, &V.MCDCCondBitmapAddr);
+
+  llvm::sort(SortedPair);
+
+  for (auto &[_, MCDCCondBitmapAddr] : SortedPair)
+    Result.push_back(MCDCCondBitmapAddr);
+
+  return Result;
+}
+
 void CodeGenPGO::emitMCDCTestVectorBitmapUpdate(CGBuilderTy &Builder,
                                                 const Expr *S,
-                                                Address MCDCCondBitmapAddr,
                                                 CodeGenFunction &CGF) {
   if (!canEmitMCDCCoverage(Builder) || !RegionMCDCState)
     return;
@@ -1258,6 +1278,10 @@ void CodeGenPGO::emitMCDCTestVectorBitmapUpdate(CGBuilderTy &Builder,
   if (DecisionStateIter == RegionMCDCState->DecisionByStmt.end())
     return;
 
+  auto &MCDCCondBitmapAddr = DecisionStateIter->second.MCDCCondBitmapAddr;
+  if (!MCDCCondBitmapAddr.isValid())
+    return;
+
   // Don't create tvbitmap_update if the record is allocated but excluded.
   // Or `bitmap |= (1 << 0)` would be wrongly executed to the next bitmap.
   if (DecisionStateIter->second.Indices.size() == 0)
@@ -1280,14 +1304,16 @@ void CodeGenPGO::emitMCDCTestVectorBitmapUpdate(CGBuilderTy &Builder,
       CGM.getIntrinsic(llvm::Intrinsic::instrprof_mcdc_tvbitmap_update), Args);
 }
 
-void CodeGenPGO::emitMCDCCondBitmapReset(CGBuilderTy &Builder, const Expr *S,
-                                         Address MCDCCondBitmapAddr) {
+void CodeGenPGO::emitMCDCCondBitmapReset(CGBuilderTy &Builder, const Expr *S) {
   if (!canEmitMCDCCoverage(Builder) || !RegionMCDCState)
     return;
 
-  S = S->IgnoreParens();
+  auto I = RegionMCDCState->DecisionByStmt.find(S->IgnoreParens());
+  if (I == RegionMCDCState->DecisionByStmt.end())
+    return;
 
-  if (!RegionMCDCState->DecisionByStmt.contains(S))
+  auto &MCDCCondBitmapAddr = I->second.MCDCCondBitmapAddr;
+  if (!MCDCCondBitmapAddr.isValid())
     return;
 
   // Emit intrinsic that resets a dedicated temporary value on the stack to 0.
@@ -1295,7 +1321,6 @@ void CodeGenPGO::emitMCDCCondBitmapReset(CGBuilderTy &Builder, const Expr *S,
 }
 
 void CodeGenPGO::emitMCDCCondBitmapUpdate(CGBuilderTy &Builder, const Expr *S,
-                                          Address MCDCCondBitmapAddr,
                                           llvm::Value *Val,
                                           CodeGenFunction &CGF) {
   if (!canEmitMCDCCoverage(Builder) || !RegionMCDCState)
@@ -1325,6 +1350,10 @@ void CodeGenPGO::emitMCDCCondBitmapUpdate(CGBuilderTy &Builder, const Expr *S,
   if (DecisionIter == RegionMCDCState->DecisionByStmt.end())
     return;
 
+  auto &MCDCCondBitmapAddr = DecisionIter->second.MCDCCondBitmapAddr;
+  if (!MCDCCondBitmapAddr.isValid())
+    return;
+
   const auto &TVIdxs = DecisionIter->second.Indices[Branch.ID];
 
   auto *CurTV = Builder.CreateLoad(MCDCCondBitmapAddr,
diff --git a/clang/lib/CodeGen/CodeGenPGO.h b/clang/lib/CodeGen/CodeGenPGO.h
index 1944b640951d5..0d7dd13f611a9 100644
--- a/clang/lib/CodeGen/CodeGenPGO.h
+++ b/clang/lib/CodeGen/CodeGenPGO.h
@@ -114,14 +114,12 @@ class CodeGenPGO {
   void emitCounterSetOrIncrement(CGBuilderTy &Builder, const Stmt *S,
                                  llvm::Value *StepV);
   void emitMCDCTestVectorBitmapUpdate(CGBuilderTy &Builder, const Expr *S,
-                                      Address MCDCCondBitmapAddr,
                                       CodeGenFunction &CGF);
   void emitMCDCParameters(CGBuilderTy &Builder);
-  void emitMCDCCondBitmapReset(CGBuilderTy &Builder, const Expr *S,
-                               Address MCDCCondBitmapAddr);
+  std::vector<Address *> getMCDCCondBitmapAddrArray(CGBuilderTy &Builder);
+  void emitMCDCCondBitmapReset(CGBuilderTy &Builder, const Expr *S);
   void emitMCDCCondBitmapUpdate(CGBuilderTy &Builder, const Expr *S,
-                                Address MCDCCondBitmapAddr, llvm::Value *Val,
-                                CodeGenFunction &CGF);
+                                llvm::Value *Val, CodeGenFunction &CGF);
 
   void markStmtAsUsed(bool Skipped, const Stmt *S) {
     // Do nothing.
diff --git a/clang/lib/CodeGen/MCDCState.h b/clang/lib/CodeGen/MCDCState.h
index 0b6f5f28235f4..2bb4eaf9fdfc8 100644
--- a/clang/lib/CodeGen/MCDCState.h
+++ b/clang/lib/CodeGen/MCDCState.h
@@ -13,6 +13,7 @@
 #ifndef LLVM_CLANG_LIB_CODEGEN_MCDCSTATE_H
 #define LLVM_CLANG_LIB_CODEGEN_MCDCSTATE_H
 
+#include "Address.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ProfileData/Coverage/MCDCTypes.h"
@@ -38,6 +39,7 @@ struct State {
     unsigned BitmapIdx;
     IndicesTy Indices;
     unsigned ID = InvalidID;
+    Address MCDCCondBitmapAddr = Address::invalid();
 
     bool isValid() const { return ID != InvalidID; }
 
diff --git a/clang/test/CoverageMapping/mcdc-single-cond.cpp b/clang/test/CoverageMapping/mcdc-single-cond.cpp
new file mode 100644
index 0000000000000..d6c694a63dd28
--- /dev/null
+++ b/clang/test/CoverageMapping/mcdc-single-cond.cpp
@@ -0,0 +1,101 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++11 -fcoverage-mcdc -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -disable-llvm-passes -emit-llvm -o %t2.ll %s | FileCheck %s --check-prefixes=MM,MM2
+// RUN: FileCheck %s --check-prefixes=LL,LL2 < %t2.ll
+
+// LL: define{{.+}}func_cond{{.+}}(
+// MM: func_cond{{.*}}:
+int func_cond(bool a, bool b) {
+  // %mcdc.addr* are emitted by static order.
+  // LL:   %[[MA4:mcdc.addr.*]] = alloca i32, align 4
+  // LL:   %[[MA6:mcdc.addr.*]] = alloca i32, align 4
+  // LL:   %[[MA7:mcdc.addr.*]] = alloca i32, align 4
+  // LL:   %[[MA9:mcdc.addr.*]] = alloca i32, align 4
+  // LL:   %[[MA10:mcdc.addr.*]] = alloca i32, align 4
+  // LL:  call void @llvm.instrprof.mcdc.parameters(ptr @[[PROFN:.+]], i64 [[#H:]], i32 [[#BS:]])
+  int count = 0;
+  if (a)
+    // NB=2 Single cond
+    // MM2-NOT: Decision
+    ++count;
+  if (a ? true : false)
+    // NB=2,2 Wider decision comes first.
+    // MA2 has C:2
+    // MA3 has C:1
+    ++count;
+  if (a && b ? true : false)
+    // NB=2,3 Wider decision comes first.
+    // MM2:  Decision,File 0, [[@LINE-2]]:7 -> [[#L:@LINE-2]]:13 = M:[[#I:3]], C:2
+    // MM:   Branch,File 0, [[#L]]:7 -> [[#L]]:8 = #6, (#0 - #6) [1,2,0]
+    // MM:   Branch,File 0, [[#L]]:12 -> [[#L]]:13 = #7, (#6 - #7) [2,0,0]
+    // LL:   store i32 0, ptr %[[MA4]], align 4
+    // LL:   = load i32, ptr %[[MA4]], align 4
+    // LL:   store i32 %{{.+}}, ptr %[[MA4]], align 4
+    // LL:   = load i32, ptr %[[MA4]], align 4
+    // LL:   store i32 %{{.+}}, ptr %[[MA4]], align 4
+    // LL2:  call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:0]], ptr %[[MA4]])
+    ++count;
+  while (a || true) {
+    // NB=3 BinOp only
+    // MM:   Decision,File 0, [[@LINE-2]]:10 -> [[#L:@LINE-2]]:19 = M:[[#I:I+3]], C:2
+    // MM:   Branch,File 0, [[#L]]:10 -> [[#L]]:11 = (#0 - #9), #9 [1,0,2]
+    // MM:   Branch,File 0, [[#L]]:15 -> [[#L]]:19 = (#9 - #10), 0 [2,0,0]
+    // LL:   store i32 0, ptr %[[MA6]], align 4
+    // LL:   = load i32, ptr %[[MA6]], align 4
+    // LL:   store i32 %{{.+}}, ptr %[[MA6]], align 4
+    // LL:   = load i32, ptr %[[MA6]], align 4
+    // LL:   store i32 %{{.+}}, ptr %[[MA6]], align 4
+    // LL2:  call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA6]])
+    ++count;
+    break;
+  }
+  while (a || true ? false : true) {
+    // Wider decision comes first.
+    // MM2:  Decision,File 0, [[@LINE-2]]:10 -> [[#L:@LINE-2]]:19 = M:[[#I:I+3]], C:2
+    // MM:   Branch,File 0, [[#L]]:10 -> [[#L]]:11 = ((#0 + #11) - #13), #13 [1,0,2]
+    // MM:   Branch,File 0, [[#L]]:15 -> [[#L]]:19 = (#13 - #14), 0 [2,0,0]
+    // LL:   store i32 0, ptr %[[MA7]], align 4
+    // LL:   = load i32, ptr %[[MA7]], align 4
+    // LL:   store i32 %{{.+}}, ptr %[[MA7]], align 4
+    // LL:   = load i32, ptr %[[MA7]], align 4
+    // LL:   store i32 %{{.+}}, ptr %[[MA7]], align 4
+    // LL:   call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA7]])
+    ++count;
+  }
+  do {
+    ++count;
+  } while (a && false);
+  // BinOp only
+  // MM:   Decision,File 0, [[@LINE-2]]:12 -> [[#L:@LINE-2]]:22 = M:[[#I:I+3]], C:2
+  // MM:   Branch,File 0, [[#L]]:12 -> [[#L]]:13 = #16, ((#0 + #15) - #16) [1,2,0]
+  // MM:   Branch,File 0, [[#L]]:17 -> [[#L]]:22 = 0, (#16 - #17) [2,0,0]
+  // LL:   store i32 0, ptr %[[MA9]], align 4
+  // LL:   = load i32, ptr %[[MA9]], align 4
+  // LL:   store i32 %{{.+}}, ptr %[[MA9]], align 4
+  // LL:   = load i32, ptr %[[MA9]], align 4
+  // LL:   store i32 %{{.+}}, ptr %[[MA9]], align 4
+  // LL2:  call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA9]])
+  do {
+    ++count;
+  } while (a && false ? true : false);
+  // Wider decision comes first.
+  // MM2:  Decision,File 0, [[@LINE-2]]:12 -> [[#L:@LINE-2]]:22 = M:15, C:2
+  // MM:   Branch,File 0, [[#L]]:12 -> [[#L]]:13 = #20, ((#0 + #18) - #20) [1,2,0]
+  // MM:   Branch,File 0, [[#L]]:17 -> [[#L]]:22 = 0, (#20 - #21) [2,0,0]
+  // LL:   store i32 0, ptr %[[MA10]], align 4
+  // LL:   = load i32, ptr %[[MA10]], align 4
+  // LL:   store i32 %{{.+}}, ptr %[[MA10]], align 4
+  // LL:   = load i32, ptr %[[MA10]], align 4
+  // LL:   store i32 %{{.+}}, ptr %[[MA10]], align 4
+  // LL:   call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA10]])
+  // FIXME: Confirm (B+3==BS)
+  for (int i = 0; i < (a ? 2 : 1); ++i) {
+    // Simple nested decision (different column)
+    // MM2-NOT: Decision
+    // LL2-NOT: call void @llvm.instrprof.mcdc.tvbitmap.update
+    ++count;
+  }
+  for (int i = 0; i >= 4 ? false : true; ++i) {
+    // Wider decision comes first.
+    ++count;
+  }
+  return count;
+}
diff --git a/clang/test/Profile/c-mcdc-logicalop-ternary.c b/clang/test/Profile/c-mcdc-logicalop-ternary.c
index 18ce0b4e5dc14..18682ffdbfec3 100644
--- a/clang/test/Profile/c-mcdc-logicalop-ternary.c
+++ b/clang/test/Profile/c-mcdc-logicalop-ternary.c
@@ -13,12 +13,14 @@ int test(int a, int b, int c, int d, int e, int f) {
 
 // ALLOCATE MCDC TEMP AND ZERO IT.
 // MCDC-LABEL: @test(
-// MCDC: %mcdc.addr = alloca i32, align 4
-// MCDC: store i32 0, ptr %mcdc.addr, align 4
+// MCDC: %[[ADDR0:mcdc.+]] = alloca i32, align 4
+// MCDC: %[[ADDR1:mcdc.+]] = alloca i32, align 4
+// MCDC: %[[ADDR2:mcdc.+]] = alloca i32, align 4
+// MCDC: store i32 0, ptr %[[ADDR0]], align 4
 
 // TERNARY TRUE SHOULD UPDATE THE BITMAP WITH RESULT AT ELEMENT 0.
 // MCDC-LABEL: cond.true:
-// MCDC-DAG:  %[[TEMP0:mcdc.temp[0-9]*]] = load i32, ptr %mcdc.addr, align 4
+// MCDC-DAG:  %[[TEMP0:mcdc.temp[0-9]*]] = load i32, ptr %[[ADDR0]], align 4
 // MCDC:  %[[TEMP:[0-9]+]] = add i32 %[[TEMP0]], 0
 // MCDC:  %[[LAB1:[0-9]+]] = lshr i32 %[[TEMP]], 3
 // MCDC:  %[[LAB4:[0-9]+]] = getelementptr inbounds i8, ptr @__profbm_test, i32 %[[LAB1]]
@@ -30,12 +32,12 @@ int test(int a, int b, int c, int d, int e, int f) {
 // MCDC:  store i8 %[[LAB9]], ptr %[[LAB4]], align 1
 
 // CHECK FOR ZERO OF MCDC TEMP
-// MCDC: store i32 0, ptr %mcdc.addr, align 4
+// MCDC: store i32 0, ptr %[[ADDR1]], align 4
 
 // TERNARY TRUE YIELDS TERNARY LHS LOGICAL-AND.
 // TERNARY LHS LOGICAL-AND SHOULD UPDATE THE BITMAP WITH RESULT AT ELEMENT 1.
 // MCDC-LABEL: land.end:
-// MCDC-DAG:  %[[TEMP0:mcdc.temp[0-9]*]] = load i32, ptr %mcdc.addr, align 4
+// MCDC-DAG:  %[[TEMP0:mcdc.temp[0-9]*]] = load i32, ptr %[[ADDR1]], align 4
 // MCDC:  %[[TEMP:[0-9]+]] = add i32 %[[TEMP0]], 3
 // MCDC:  %[[LAB1:[0-9]+]] = lshr i32 %[[TEMP]], 3
 // MCDC:  %[[LAB4:[0-9]+]] = getelementptr inbounds i8, ptr @__profbm_test, i32 %[[LAB1]]
@@ -48,7 +50,7 @@ int test(int a, int b, int c, int d, int e, int f) {
 
 // TERNARY FALSE SHOULD UPDATE THE BITMAP WITH RESULT AT ELEMENT 0.
 // MCDC-LABEL: cond.false:
-// MCDC-DAG:  %[[TEMP0:mcdc.temp[0-9]*]] = load i32, ptr %mcdc.addr, align 4
+// MCDC-DAG: %[[TEMP0:mcdc.+]] = load i32, ptr %[[ADDR0]], align 4
 // MCDC:  %[[TEMP:[0-9]+]] = add i32 %[[TEMP0]], 0
 // MCDC:  %[[LAB1:[0-9]+]] = lshr i32 %[[TEMP]], 3
 // MCDC:  %[[LAB4:[0-9]+]] = getelementptr inbounds i8, ptr @__profbm_test, i32 %[[LAB1]]
@@ -60,12 +62,12 @@ int test(int a, int b, int c, int d, int e, int f) {
 // MCDC:  store i8 %[[LAB9]], ptr %[[LAB4]], align 1
 
 // CHECK FOR ZERO OF MCDC TEMP
-// MCDC: store i32 0, ptr %mcdc.addr, align 4
+// MCDC: store i32 0, ptr %[[ADDR2]], align 4
 
 // TERNARY FALSE YIELDS TERNARY RHS LOGICAL-OR.
 // TERNARY RHS LOGICAL-OR SHOULD UPDATE THE BITMAP WITH RESULT AT ELEMENT 2.
 // MCDC-LABEL: lor.end:
-// MCDC-DAG:  %[[TEMP0:mcdc.temp[0-9]*]] = load i32, ptr %mcdc.addr, align 4
+// MCDC-DAG:  %[[TEMP0:mcdc.temp[0-9]*]] = load i32, ptr %[[ADDR2]], align 4
 // MCDC:  %[[TEMP:[0-9]+]] = add i32 %[[TEMP0]], 6
 // MCDC:  %[[LAB1:[0-9]+]] = lshr i32 %[[TEMP]], 3
 // MCDC:  %[[LAB4:[0-9]+]] = getelementptr inbounds i8, ptr @__profbm_test, i32 %[[LAB1]]

>From f2cf50e10b59d7d461967baef4d589c9282d0f6d Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Sun, 2 Feb 2025 22:11:51 +0900
Subject: [PATCH 65/72] [MC/DC] Enable usage of `!` among `&&` and `||`

In the current implementation, `!(a || b) && c` was not treated as one
Decision with three terms.

Fixes #124563
---
 clang/include/clang/AST/IgnoreExpr.h          |  8 ++
 clang/lib/CodeGen/CodeGenFunction.cpp         | 12 ++-
 clang/lib/CodeGen/CodeGenPGO.cpp              |  8 +-
 clang/lib/CodeGen/CoverageMappingGen.cpp      | 12 +++
 .../test/CoverageMapping/mcdc-nested-expr.cpp |  6 +-
 clang/test/Profile/c-mcdc-not.c               | 95 +++++++++++++++++++
 6 files changed, 132 insertions(+), 9 deletions(-)

diff --git a/clang/include/clang/AST/IgnoreExpr.h b/clang/include/clang/AST/IgnoreExpr.h
index 917bada61fa6f..c48c0c0daf815 100644
--- a/clang/include/clang/AST/IgnoreExpr.h
+++ b/clang/include/clang/AST/IgnoreExpr.h
@@ -134,6 +134,14 @@ inline Expr *IgnoreElidableImplicitConstructorSingleStep(Expr *E) {
   return E;
 }
 
+inline Expr *IgnoreUOpLNotSingleStep(Expr *E) {
+  if (auto *UO = dyn_cast<UnaryOperator>(E)) {
+    if (UO->getOpcode() == UO_LNot)
+      return UO->getSubExpr();
+  }
+  return E;
+}
+
 inline Expr *IgnoreImplicitAsWrittenSingleStep(Expr *E) {
   if (auto *ICE = dyn_cast<ImplicitCastExpr>(E))
     return ICE->getSubExprAsWritten();
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index bbef277a52448..2c380ac926b1e 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -27,6 +27,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/Expr.h"
+#include "clang/AST/IgnoreExpr.h"
 #include "clang/AST/StmtCXX.h"
 #include "clang/AST/StmtObjC.h"
 #include "clang/Basic/Builtins.h"
@@ -1748,12 +1749,13 @@ bool CodeGenFunction::ConstantFoldsToSimpleInteger(const Expr *Cond,
 
 /// Strip parentheses and simplistic logical-NOT operators.
 const Expr *CodeGenFunction::stripCond(const Expr *C) {
-  while (const UnaryOperator *Op = dyn_cast<UnaryOperator>(C->IgnoreParens())) {
-    if (Op->getOpcode() != UO_LNot)
-      break;
-    C = Op->getSubExpr();
+  while (true) {
+    const Expr *SC =
+        IgnoreExprNodes(C, IgnoreParensSingleStep, IgnoreUOpLNotSingleStep);
+    if (C == SC)
+      return SC;
+    C = SC;
   }
-  return C->IgnoreParens();
 }
 
 /// Determine whether the given condition is an instrumentable condition
diff --git a/clang/lib/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp
index 792373839107f..0fd49b880bba3 100644
--- a/clang/lib/CodeGen/CodeGenPGO.cpp
+++ b/clang/lib/CodeGen/CodeGenPGO.cpp
@@ -247,8 +247,9 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
     }
 
     if (const Expr *E = dyn_cast<Expr>(S)) {
-      const BinaryOperator *BinOp = dyn_cast<BinaryOperator>(E->IgnoreParens());
-      if (BinOp && BinOp->isLogicalOp()) {
+      if (const auto *BinOp =
+              dyn_cast<BinaryOperator>(CodeGenFunction::stripCond(E));
+          BinOp && BinOp->isLogicalOp()) {
         /// Check for "split-nested" logical operators. This happens when a new
         /// boolean expression logical-op nest is encountered within an existing
         /// boolean expression, separated by a non-logical operator.  For
@@ -280,7 +281,8 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
       return true;
 
     if (const Expr *E = dyn_cast<Expr>(S)) {
-      const BinaryOperator *BinOp = dyn_cast<BinaryOperator>(E->IgnoreParens());
+      const BinaryOperator *BinOp =
+          dyn_cast<BinaryOperator>(CodeGenFunction::stripCond(E));
       if (BinOp && BinOp->isLogicalOp()) {
         assert(LogOpStack.back() == BinOp);
         LogOpStack.pop_back();
diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index f09157771d2b5..9bf73cf27a5fa 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -799,6 +799,12 @@ struct MCDCCoverageBuilder {
   /// Return the LHS Decision ([0,0] if not set).
   const mcdc::ConditionIDs &back() const { return DecisionStack.back(); }
 
+  void swapConds() {
+    if (DecisionStack.empty())
+      return;
+
+    std::swap(DecisionStack.back()[false], DecisionStack.back()[true]);
+  }
   /// Push the binary operator statement to track the nest level and assign IDs
   /// to the operator's LHS and RHS.  The RHS may be a larger subtree that is
   /// broken up on successive levels.
@@ -2241,6 +2247,12 @@ struct CounterCoverageMappingBuilder
             SM.isInSystemHeader(SM.getSpellingLoc(E->getEndLoc())));
   }
 
+  void VisitUnaryLNot(const UnaryOperator *E) {
+    MCDCBuilder.swapConds();
+    Visit(E->getSubExpr());
+    MCDCBuilder.swapConds();
+  }
+
   void VisitBinLAnd(const BinaryOperator *E) {
     if (isExprInSystemHeader(E)) {
       LeafExprSet.insert(E);
diff --git a/clang/test/CoverageMapping/mcdc-nested-expr.cpp b/clang/test/CoverageMapping/mcdc-nested-expr.cpp
index bb82873e3b600..a49dad0b33612 100644
--- a/clang/test/CoverageMapping/mcdc-nested-expr.cpp
+++ b/clang/test/CoverageMapping/mcdc-nested-expr.cpp
@@ -29,6 +29,10 @@ bool func_expect(bool a, bool b, bool c) {
 // Doesn't split exprs.
 // CHECK: func_lnot{{.*}}:
 bool func_lnot(bool a, bool b, bool c, bool d) {
-  // WARN: :[[@LINE+1]]:10: warning: unsupported MC/DC boolean expression; contains an operation with a nested boolean expression.
   return !(a || b) && !(c && d);
+  // CHECK:  Decision,File 0, [[@LINE-1]]:10 -> [[#L:@LINE-1]]:32 = M:5, C:4
+  // CHECK:  Branch,File 0, [[#L]]:12 -> [[#L]]:13 = (#0 - #2), #2 [1,0,3]
+  // CHECK:  Branch,File 0, [[#L]]:17 -> [[#L]]:18 = (#2 - #3), #3 [3,0,2]
+  // CHECK:  Branch,File 0, [[#L]]:25 -> [[#L]]:26 = #4, (#1 - #4) [2,4,0]
+  // CHECK:  Branch,File 0, [[#L]]:30 -> [[#L]]:31 = #5, (#4 - #5) [4,0,0]
 }
diff --git a/clang/test/Profile/c-mcdc-not.c b/clang/test/Profile/c-mcdc-not.c
index 7083aa226fb95..d6d79bf15cb08 100644
--- a/clang/test/Profile/c-mcdc-not.c
+++ b/clang/test/Profile/c-mcdc-not.c
@@ -85,3 +85,98 @@ int test(int a, int b, int c, int d, int e, int f) {
 // MCDC:  %[[BITS:.+]] = load i8, ptr %[[LAB4]], align 1
 // MCDC:  %[[LAB8:[0-9]+]] = or i8 %[[BITS]], %[[LAB7]]
 // MCDC:  store i8 %[[LAB8]], ptr %[[LAB4]], align 1
+
+int internot(int a, int b, int c, int d, int e, int f) {
+  return !(!(!a && b) || !(!!(!c && d) || !(e && !f)));
+}
+
+// MCDC-LABEL: @internot(
+// MCDC-DAG:  store i32 0, ptr %mcdc.addr, align 4
+
+// Branch #2, (#0 - #2) [1,3,0]
+// !a [+0 => b][+6 => END]
+// MCDC-DAG:  %[[A:.+]] = load i32, ptr %a.addr, align 4
+// MCDC-DAG:  %[[AB:.+]] = icmp ne i32 %[[A]], 0
+// MCDC-DAG:  %[[AN:.+]] = xor i1 %[[AB]], true
+// MCDC-DAG:  %[[M1:.+]] = load i32, ptr %mcdc.addr, align 4
+// MCDC-DAG:  %[[M1T:.+]] = add i32 %[[M1]], 0
+// MCDC-DAG:  %[[M1F:.+]] = add i32 %[[M1]], 6
+// MCDC-DAG:  %[[M1S:.+]] = select i1 %[[AN]], i32 %[[M1T]], i32 %[[M1F]]
+// MCDC-DAG:  store i32 %[[M1S]], ptr %mcdc.addr, align 4
+
+// Branch #3, (#2 - #3) [3,2,0]
+// b [+0 => c][+7 => END]
+// MCDC-DAG:  %[[B:.+]] = load i32, ptr %b.addr, align 4
+// MCDC-DAG:  %[[BB:.+]] = icmp ne i32 %[[B]], 0
+// MCDC-DAG:  %[[M3:.+]] = load i32, ptr %mcdc.addr, align 4
+// MCDC-DAG:  %[[M3T:.+]] = add i32 %[[M3]], 0
+// MCDC-DAG:  %[[M3F:.+]] = add i32 %[[M3]], 7
+// MCDC-DAG:  %[[M3S:.+]] = select i1 %[[BB]], i32 %[[M3T]], i32 %[[M3F]]
+// MCDC-DAG:  store i32 %[[M3S]], ptr %mcdc.addr, align 4
+
+// Branch #5, (#1 - #5) [2,5,4]
+// !c [+0 => d][+0 => e]
+// MCDC-DAG:  %[[C:.+]] = load i32, ptr %c.addr, align 4
+// MCDC-DAG:  %[[CB:.+]] = icmp ne i32 %[[C]], 0
+// MCDC-DAG:  %[[CN:.+]] = xor i1 %[[CB]], true
+// MCDC-DAG:  %[[M2:.+]] = load i32, ptr %mcdc.addr, align 4
+// MCDC-DAG:  %[[M2T:.+]] = add i32 %[[M2]], 0
+// MCDC-DAG:  %[[M2F:.+]] = add i32 %[[M2]], 0
+// MCDC-DAG:  %[[M2S:.+]] = select i1 %[[CN]], i32 %[[M2T]], i32 %[[M2F]]
+// MCDC-DAG:  store i32 %[[M2S]], ptr %mcdc.addr, align 4
+
+// Branch #6, (#5 - #6) [5,0,4]
+// d [+8 => END][+1 => e]]
+// MCDC-DAG:  %[[D:.+]] = load i32, ptr %d.addr, align 4
+// MCDC-DAG:  %[[DB:.+]] = icmp ne i32 %[[D]], 0
+// MCDC-DAG:  %[[M5:.+]] = load i32, ptr %mcdc.addr, align 4
+// MCDC-DAG:  %[[M5T:.+]] = add i32 %[[M5]], 8
+// MCDC-DAG:  %[[M5F:.+]] = add i32 %[[M5]], 1
+// MCDC-DAG:  %[[M5S:.+]] = select i1 %[[DB]], i32 %[[M5T]], i32 %[[M5F]]
+// MCDC-DAG:  store i32 %[[M5S]], ptr %mcdc.addr, align 4
+
+// Branch #7, (#4 - #7) [4,6,0]
+// e [+0 => f][+0 => END]
+// from:
+//   [c => +0]
+//   [d => +1]
+// MCDC-DAG:  %[[E:.+]] = load i32, ptr %e.addr, align 4
+// MCDC-DAG:  %[[EB:.+]] = icmp ne i32 %[[E]], 0
+// MCDC-DAG:  %[[M4:.+]] = load i32, ptr %mcdc.addr, align 4
+// MCDC-DAG:  %[[M4T:.+]] = add i32 %[[M4]], 0
+// MCDC-DAG:  %[[M4F:.+]] = add i32 %[[M4]], 0
+// MCDC-DAG:  %[[M4S:.+]] = select i1 %[[EB]], i32 %[[M4T]], i32 %[[M4F]]
+// MCDC-DAG:  store i32 %[[M4S]], ptr %mcdc.addr, align 4
+
+// Branch #8, (#7 - #8) [6,0,0]
+// !f [+4 => END][+2 => END]
+// MCDC-DAG:  %[[F:.+]] = load i32, ptr %f.addr, align 4
+// MCDC-DAG:  %[[FB:.+]] = icmp ne i32 %[[F]], 0
+// MCDC-DAG:  %[[FN:.+]] = xor i1 %[[FB]], true
+// MCDC-DAG:  %[[M6:.+]] = load i32, ptr %mcdc.addr, align 4
+// MCDC-DAG:  %[[M6T:.+]] = add i32 %[[M6]], 4
+// MCDC-DAG:  %[[M6F:.+]] = add i32 %[[M6]], 2
+// MCDC-DAG:  %[[M6S:.+]] = select i1 %[[FN]], i32 %[[M6T]], i32 %[[M6F]]
+// MCDC-DAG:  store i32 %[[M6S]], ptr %mcdc.addr, align 4
+
+// from:
+//   [e => +0]
+//   [f => +2]
+//     [c => +0]
+//     [d => +1]
+//   [f => +4]
+//     [c => +0]
+//     [d => +1]
+//   [a => +6]
+//   [b => +7]
+//   [d => +8]
+// MCDC-DAG:  %[[T0:.+]] = load i32, ptr %mcdc.addr, align 4
+// MCDC-DAG:  %[[T:.+]] = add i32 %[[T0]], 0
+// MCDC-DAG:  %[[TA:.+]] = lshr i32 %[[T]], 3
+// MCDC-DAG:  %[[BA:.+]] = getelementptr inbounds i8, ptr @__profbm_internot, i32 %[[TA]]
+// MCDC-DAG:  %[[BI:.+]] = and i32 %[[T]], 7
+// MCDC-DAG:  %[[BI1:.+]] = trunc i32 %[[BI]] to i8
+// MCDC-DAG:  %[[BM:.+]] = shl i8 1, %[[BI1]]
+// MCDC-DAG:  %mcdc.bits = load i8, ptr %[[BA]], align 1
+// MCDC-DAG:  %[[BN:.+]] = or i8 %mcdc.bits, %[[BM]]
+// MCDC-DAG:  store i8 %[[BN]], ptr %[[BA]], align 1

>From 7c71ae3369b1df23c8a3e65a2950885b6162e06b Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Mon, 3 Feb 2025 20:30:27 +0900
Subject: [PATCH 66/72] Update ReleaseNotes

---
 clang/docs/ReleaseNotes.rst | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index b8b47103d9517..22f52b388fd40 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -116,6 +116,9 @@ Improvements to Clang's time-trace
 Improvements to Coverage Mapping
 --------------------------------
 
+- [MC/DC] Unary logical not `!` among binary operators is recognized
+  as a part of the expression. (#GH124563)
+
 Bug Fixes in This Version
 -------------------------
 

>From 079bf69ee66b3cda8206f790185a8bb325ec7064 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Sat, 1 Mar 2025 15:37:35 +0900
Subject: [PATCH 67/72] isValid()

---
 clang/lib/CodeGen/MCDCState.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/MCDCState.h b/clang/lib/CodeGen/MCDCState.h
index 0b6f5f28235f4..4b89ddd12d672 100644
--- a/clang/lib/CodeGen/MCDCState.h
+++ b/clang/lib/CodeGen/MCDCState.h
@@ -42,7 +42,7 @@ struct State {
     bool isValid() const { return ID != InvalidID; }
 
     void update(unsigned I, IndicesTy &&X) {
-      assert(ID != InvalidID);
+      assert(isValid());
       BitmapIdx = I;
       Indices = std::move(X);
     }

>From 8b35e76018417c301dc757ea5446292dd3a3996c Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Sat, 1 Mar 2025 15:52:53 +0900
Subject: [PATCH 68/72] Remove mcdc-single-cond.cpp

---
 .../test/CoverageMapping/mcdc-single-cond.cpp | 97 -------------------
 1 file changed, 97 deletions(-)
 delete mode 100644 clang/test/CoverageMapping/mcdc-single-cond.cpp

diff --git a/clang/test/CoverageMapping/mcdc-single-cond.cpp b/clang/test/CoverageMapping/mcdc-single-cond.cpp
deleted file mode 100644
index b1eeea879e521..0000000000000
--- a/clang/test/CoverageMapping/mcdc-single-cond.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++11 -fcoverage-mcdc -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -disable-llvm-passes -emit-llvm -o %t2.ll %s | FileCheck %s --check-prefixes=MM,MM2
-// RUN: FileCheck %s --check-prefixes=LL,LL2 < %t2.ll
-
-// LL: define{{.+}}func_cond{{.+}}(
-// MM: func_cond{{.*}}:
-int func_cond(bool a, bool b) {
-  // %mcdc.addr* are emitted by static order.
-  // LL:   %[[MA:mcdc.addr.*]] = alloca i32, align 4
-  // LL:  call void @llvm.instrprof.mcdc.parameters(ptr @[[PROFN:.+]], i64 [[#H:]], i32 [[#BS:]])
-  int count = 0;
-  if (a)
-    // NB=2 Single cond
-    // MM2-NOT: Decision
-    ++count;
-  if (a ? true : false)
-    // NB=2,2 Wider decision comes first.
-    // MA2 has C:2
-    // MA3 has C:1
-    ++count;
-  if (a && b ? true : false)
-    // NB=2,3 Wider decision comes first.
-    // MM2:  Decision,File 0, [[@LINE-2]]:7 -> [[#L:@LINE-2]]:13 = M:[[#I:3]], C:2
-    // MM:   Branch,File 0, [[#L]]:7 -> [[#L]]:8 = #6, (#0 - #6) [1,2,0]
-    // MM:   Branch,File 0, [[#L]]:12 -> [[#L]]:13 = #7, (#6 - #7) [2,0,0]
-    // LL:   store i32 0, ptr %[[MA]], align 4
-    // LL:   = load i32, ptr %[[MA]], align 4
-    // LL:   store i32 %{{.+}}, ptr %[[MA]], align 4
-    // LL:   = load i32, ptr %[[MA]], align 4
-    // LL:   store i32 %{{.+}}, ptr %[[MA]], align 4
-    // LL2:  call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:0]], ptr %[[MA]])
-    ++count;
-  while (a || true) {
-    // NB=3 BinOp only
-    // MM:   Decision,File 0, [[@LINE-2]]:10 -> [[#L:@LINE-2]]:19 = M:[[#I:I+3]], C:2
-    // MM:   Branch,File 0, [[#L]]:10 -> [[#L]]:11 = (#0 - #9), #9 [1,0,2]
-    // MM:   Branch,File 0, [[#L]]:15 -> [[#L]]:19 = (#9 - #10), 0 [2,0,0]
-    // LL:   store i32 0, ptr %[[MA]], align 4
-    // LL:   = load i32, ptr %[[MA]], align 4
-    // LL:   store i32 %{{.+}}, ptr %[[MA]], align 4
-    // LL:   = load i32, ptr %[[MA]], align 4
-    // LL:   store i32 %{{.+}}, ptr %[[MA]], align 4
-    // LL2:  call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA]])
-    ++count;
-    break;
-  }
-  while (a || true ? false : true) {
-    // Wider decision comes first.
-    // MM2:  Decision,File 0, [[@LINE-2]]:10 -> [[#L:@LINE-2]]:19 = M:[[#I:I+3]], C:2
-    // MM:   Branch,File 0, [[#L]]:10 -> [[#L]]:11 = ((#0 + #11) - #13), #13 [1,0,2]
-    // MM:   Branch,File 0, [[#L]]:15 -> [[#L]]:19 = (#13 - #14), 0 [2,0,0]
-    // LL:   store i32 0, ptr %[[MA]], align 4
-    // LL:   = load i32, ptr %[[MA]], align 4
-    // LL:   store i32 %{{.+}}, ptr %[[MA]], align 4
-    // LL:   = load i32, ptr %[[MA]], align 4
-    // LL:   store i32 %{{.+}}, ptr %[[MA]], align 4
-    // LL:   call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA]])
-    ++count;
-  }
-  do {
-    ++count;
-  } while (a && false);
-  // BinOp only
-  // MM:   Decision,File 0, [[@LINE-2]]:12 -> [[#L:@LINE-2]]:22 = M:[[#I:I+3]], C:2
-  // MM:   Branch,File 0, [[#L]]:12 -> [[#L]]:13 = #16, ((#0 + #15) - #16) [1,2,0]
-  // MM:   Branch,File 0, [[#L]]:17 -> [[#L]]:22 = 0, (#16 - #17) [2,0,0]
-  // LL:   store i32 0, ptr %[[MA]], align 4
-  // LL:   = load i32, ptr %[[MA]], align 4
-  // LL:   store i32 %{{.+}}, ptr %[[MA]], align 4
-  // LL:   = load i32, ptr %[[MA]], align 4
-  // LL:   store i32 %{{.+}}, ptr %[[MA]], align 4
-  // LL2:  call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA]])
-  do {
-    ++count;
-  } while (a && false ? true : false);
-  // Wider decision comes first.
-  // MM2:  Decision,File 0, [[@LINE-2]]:12 -> [[#L:@LINE-2]]:22 = M:15, C:2
-  // MM:   Branch,File 0, [[#L]]:12 -> [[#L]]:13 = #20, ((#0 + #18) - #20) [1,2,0]
-  // MM:   Branch,File 0, [[#L]]:17 -> [[#L]]:22 = 0, (#20 - #21) [2,0,0]
-  // LL:   store i32 0, ptr %[[MA]], align 4
-  // LL:   = load i32, ptr %[[MA]], align 4
-  // LL:   store i32 %{{.+}}, ptr %[[MA]], align 4
-  // LL:   = load i32, ptr %[[MA]], align 4
-  // LL:   store i32 %{{.+}}, ptr %[[MA]], align 4
-  // LL:   call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA]])
-  // FIXME: Confirm (B+3==BS)
-  for (int i = 0; i < (a ? 2 : 1); ++i) {
-    // Simple nested decision (different column)
-    // MM2-NOT: Decision
-    // LL2-NOT: call void @llvm.instrprof.mcdc.tvbitmap.update
-    ++count;
-  }
-  for (int i = 0; i >= 4 ? false : true; ++i) {
-    // Wider decision comes first.
-    ++count;
-  }
-  return count;
-}

>From 4d531f3c2916624fbedb5248b2e0ed06f54621f0 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Sat, 1 Mar 2025 16:10:52 +0900
Subject: [PATCH 69/72] Prune mcdc-single-cond.cpp

---
 .../test/CoverageMapping/mcdc-single-cond.cpp | 101 ------------------
 1 file changed, 101 deletions(-)
 delete mode 100644 clang/test/CoverageMapping/mcdc-single-cond.cpp

diff --git a/clang/test/CoverageMapping/mcdc-single-cond.cpp b/clang/test/CoverageMapping/mcdc-single-cond.cpp
deleted file mode 100644
index d6c694a63dd28..0000000000000
--- a/clang/test/CoverageMapping/mcdc-single-cond.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++11 -fcoverage-mcdc -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -disable-llvm-passes -emit-llvm -o %t2.ll %s | FileCheck %s --check-prefixes=MM,MM2
-// RUN: FileCheck %s --check-prefixes=LL,LL2 < %t2.ll
-
-// LL: define{{.+}}func_cond{{.+}}(
-// MM: func_cond{{.*}}:
-int func_cond(bool a, bool b) {
-  // %mcdc.addr* are emitted by static order.
-  // LL:   %[[MA4:mcdc.addr.*]] = alloca i32, align 4
-  // LL:   %[[MA6:mcdc.addr.*]] = alloca i32, align 4
-  // LL:   %[[MA7:mcdc.addr.*]] = alloca i32, align 4
-  // LL:   %[[MA9:mcdc.addr.*]] = alloca i32, align 4
-  // LL:   %[[MA10:mcdc.addr.*]] = alloca i32, align 4
-  // LL:  call void @llvm.instrprof.mcdc.parameters(ptr @[[PROFN:.+]], i64 [[#H:]], i32 [[#BS:]])
-  int count = 0;
-  if (a)
-    // NB=2 Single cond
-    // MM2-NOT: Decision
-    ++count;
-  if (a ? true : false)
-    // NB=2,2 Wider decision comes first.
-    // MA2 has C:2
-    // MA3 has C:1
-    ++count;
-  if (a && b ? true : false)
-    // NB=2,3 Wider decision comes first.
-    // MM2:  Decision,File 0, [[@LINE-2]]:7 -> [[#L:@LINE-2]]:13 = M:[[#I:3]], C:2
-    // MM:   Branch,File 0, [[#L]]:7 -> [[#L]]:8 = #6, (#0 - #6) [1,2,0]
-    // MM:   Branch,File 0, [[#L]]:12 -> [[#L]]:13 = #7, (#6 - #7) [2,0,0]
-    // LL:   store i32 0, ptr %[[MA4]], align 4
-    // LL:   = load i32, ptr %[[MA4]], align 4
-    // LL:   store i32 %{{.+}}, ptr %[[MA4]], align 4
-    // LL:   = load i32, ptr %[[MA4]], align 4
-    // LL:   store i32 %{{.+}}, ptr %[[MA4]], align 4
-    // LL2:  call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:0]], ptr %[[MA4]])
-    ++count;
-  while (a || true) {
-    // NB=3 BinOp only
-    // MM:   Decision,File 0, [[@LINE-2]]:10 -> [[#L:@LINE-2]]:19 = M:[[#I:I+3]], C:2
-    // MM:   Branch,File 0, [[#L]]:10 -> [[#L]]:11 = (#0 - #9), #9 [1,0,2]
-    // MM:   Branch,File 0, [[#L]]:15 -> [[#L]]:19 = (#9 - #10), 0 [2,0,0]
-    // LL:   store i32 0, ptr %[[MA6]], align 4
-    // LL:   = load i32, ptr %[[MA6]], align 4
-    // LL:   store i32 %{{.+}}, ptr %[[MA6]], align 4
-    // LL:   = load i32, ptr %[[MA6]], align 4
-    // LL:   store i32 %{{.+}}, ptr %[[MA6]], align 4
-    // LL2:  call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA6]])
-    ++count;
-    break;
-  }
-  while (a || true ? false : true) {
-    // Wider decision comes first.
-    // MM2:  Decision,File 0, [[@LINE-2]]:10 -> [[#L:@LINE-2]]:19 = M:[[#I:I+3]], C:2
-    // MM:   Branch,File 0, [[#L]]:10 -> [[#L]]:11 = ((#0 + #11) - #13), #13 [1,0,2]
-    // MM:   Branch,File 0, [[#L]]:15 -> [[#L]]:19 = (#13 - #14), 0 [2,0,0]
-    // LL:   store i32 0, ptr %[[MA7]], align 4
-    // LL:   = load i32, ptr %[[MA7]], align 4
-    // LL:   store i32 %{{.+}}, ptr %[[MA7]], align 4
-    // LL:   = load i32, ptr %[[MA7]], align 4
-    // LL:   store i32 %{{.+}}, ptr %[[MA7]], align 4
-    // LL:   call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA7]])
-    ++count;
-  }
-  do {
-    ++count;
-  } while (a && false);
-  // BinOp only
-  // MM:   Decision,File 0, [[@LINE-2]]:12 -> [[#L:@LINE-2]]:22 = M:[[#I:I+3]], C:2
-  // MM:   Branch,File 0, [[#L]]:12 -> [[#L]]:13 = #16, ((#0 + #15) - #16) [1,2,0]
-  // MM:   Branch,File 0, [[#L]]:17 -> [[#L]]:22 = 0, (#16 - #17) [2,0,0]
-  // LL:   store i32 0, ptr %[[MA9]], align 4
-  // LL:   = load i32, ptr %[[MA9]], align 4
-  // LL:   store i32 %{{.+}}, ptr %[[MA9]], align 4
-  // LL:   = load i32, ptr %[[MA9]], align 4
-  // LL:   store i32 %{{.+}}, ptr %[[MA9]], align 4
-  // LL2:  call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA9]])
-  do {
-    ++count;
-  } while (a && false ? true : false);
-  // Wider decision comes first.
-  // MM2:  Decision,File 0, [[@LINE-2]]:12 -> [[#L:@LINE-2]]:22 = M:15, C:2
-  // MM:   Branch,File 0, [[#L]]:12 -> [[#L]]:13 = #20, ((#0 + #18) - #20) [1,2,0]
-  // MM:   Branch,File 0, [[#L]]:17 -> [[#L]]:22 = 0, (#20 - #21) [2,0,0]
-  // LL:   store i32 0, ptr %[[MA10]], align 4
-  // LL:   = load i32, ptr %[[MA10]], align 4
-  // LL:   store i32 %{{.+}}, ptr %[[MA10]], align 4
-  // LL:   = load i32, ptr %[[MA10]], align 4
-  // LL:   store i32 %{{.+}}, ptr %[[MA10]], align 4
-  // LL:   call void @llvm.instrprof.mcdc.tvbitmap.update(ptr @[[PROFN]], i64 [[#H]], i32 [[#B:B+3]], ptr %[[MA10]])
-  // FIXME: Confirm (B+3==BS)
-  for (int i = 0; i < (a ? 2 : 1); ++i) {
-    // Simple nested decision (different column)
-    // MM2-NOT: Decision
-    // LL2-NOT: call void @llvm.instrprof.mcdc.tvbitmap.update
-    ++count;
-  }
-  for (int i = 0; i >= 4 ? false : true; ++i) {
-    // Wider decision comes first.
-    ++count;
-  }
-  return count;
-}

>From 317cf772f471bed3694cb6665d79bc8aaac9778c Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Mon, 5 Jan 2026 16:25:26 +0900
Subject: [PATCH 70/72] Update mcdc-export-json.test (in #159119)

---
 llvm/test/tools/llvm-cov/mcdc-export-json.test | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/test/tools/llvm-cov/mcdc-export-json.test b/llvm/test/tools/llvm-cov/mcdc-export-json.test
index 4b6f3b011451a..3ff563955c996 100644
--- a/llvm/test/tools/llvm-cov/mcdc-export-json.test
+++ b/llvm/test/tools/llvm-cov/mcdc-export-json.test
@@ -1,7 +1,7 @@
 // RUN: llvm-profdata merge %S/Inputs/mcdc-general.proftext -o %t.profdata
 // RUN: llvm-cov export --format=text %S/Inputs/mcdc-general.o -instr-profile %t.profdata | FileCheck %s
 
-// CHECK: 12,7,12,27,2,4,0,0,5,[true,true,true,true],[{"conditions":[false,null,false,null],"executed":true,"result":false},{"conditions":[false,null,true,false],"executed":true,"result":false},{"conditions":[true,false,false,null],"executed":true,"result":false},{"conditions":[true,false,true,false],"executed":true,"result":false},{"conditions":[true,false,true,true],"executed":true,"result":true},{"conditions":[true,true,null,null],"executed":true,"result":true}]
+// CHECK: 12,7,12,27,2,4,0,0,5,[true,true,true,true],[{"conditions":[false,null,false,null],"executed":true,"result":false},{"conditions":[true,false,false,null],"executed":true,"result":false},{"conditions":[false,null,true,false],"executed":true,"result":false},{"conditions":[true,false,true,false],"executed":true,"result":false},{"conditions":[true,false,true,true],"executed":true,"result":true},{"conditions":[true,true,null,null],"executed":true,"result":true}]
 // CHECK: 15,7,15,13,1,2,0,0,5,[true,true],[{"conditions":[false,null],"executed":true,"result":false},{"conditions":[true,false],"executed":true,"result":false},{"conditions":[true,true],"executed":true,"result":true}]
 // CHECK: 15,19,15,25,1,1,0,0,5,[true,false],[{"conditions":[false,null],"executed":true,"result":false},{"conditions":[true,true],"executed":true,"result":true}]
 // CHECK: 18,7,19,15,1,3,0,0,5,[true,true,false,true],[{"conditions":[false,null,null,null],"executed":true,"result":false},{"conditions":[true,false,null,null],"executed":true,"result":false},{"conditions":[true,true,true,false],"executed":true,"result":false},{"conditions":[true,true,true,true],"executed":true,"result":true}]

>From 5d31a507879e4518f83e0db6046811d9562b1b64 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Mon, 5 Jan 2026 19:30:44 +0900
Subject: [PATCH 71/72] Add comments

---
 clang/lib/CodeGen/CodeGenFunction.h      | 10 ++++++++--
 clang/lib/CodeGen/CoverageMappingGen.cpp |  5 +++++
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index b6c1017c1bec9..13c8f2002aad9 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -1662,9 +1662,15 @@ class CodeGenFunction : public CodeGenTypeCache {
   void markStmtAsUsed(bool Skipped, const Stmt *S);
   void markStmtMaybeUsed(const Stmt *S);
 
+  /// Used to specify which counter in a pair shall be incremented.
+  /// For non-binary counters, a skip counter is derived as (Parent - Exec).
+  /// In contrast for binary counters, a skip counter cannot be computed from
+  /// the Parent counter. In such cases, dedicated SkipPath counters must be
+  /// allocated and marked (incremented as binary counters). (Parent can be
+  /// synthesized with (Exec + Skip) in simple cases)
   enum CounterForIncrement {
-    UseExecPath = 0,
-    UseSkipPath,
+    UseExecPath = 0, ///< Exec (true)
+    UseSkipPath,     ///< Skip (false)
   };
 
   /// Increment the profiler's counter for the given statement by \p StepV.
diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index a6fb7f5b3fddd..9a6d3c9abecbd 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -886,7 +886,12 @@ struct CounterCoverageMappingBuilder
   /// The map of statements to count values.
   llvm::DenseMap<const Stmt *, CounterPair> &CounterMap;
 
+  /// Used to expand an allocatd SkipCnt to Expression with known counters.
+  /// Key: SkipCnt
+  /// Val: Subtract Expression
   CounterExpressionBuilder::SubstMap MapToExpand;
+
+  /// Index and number for additional counters for SkipCnt.
   unsigned NextCounterNum;
 
   MCDC::State &MCDCState;

>From babbcf8bf87055739e25f0da5f18f807b1f62bb9 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Tue, 6 Jan 2026 11:01:03 +0900
Subject: [PATCH 72/72] emitCounterSetOrIncrement: Simplify.

- s/`TheMap`/`TheCounterPair`/
- Change the type of `Counter` to `ValueOpt`.
---
 clang/lib/CodeGen/CodeGenPGO.cpp | 18 +++++++-----------
 1 file changed, 7 insertions(+), 11 deletions(-)

diff --git a/clang/lib/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp
index 97fc328ee424e..d23f1a9aa5142 100644
--- a/clang/lib/CodeGen/CodeGenPGO.cpp
+++ b/clang/lib/CodeGen/CodeGenPGO.cpp
@@ -1210,21 +1210,17 @@ void CodeGenPGO::emitCounterSetOrIncrement(CGBuilderTy &Builder, const Stmt *S,
   if (!RegionCounterMap)
     return;
 
-  unsigned Counter;
-  auto &TheMap = (*RegionCounterMap)[S];
-  if (!UseSkipPath) {
-    if (!TheMap.Executed.hasValue())
-      return;
-    Counter = TheMap.Executed;
-  } else {
-    if (!TheMap.Skipped.hasValue())
-      return;
-    Counter = TheMap.Skipped;
-  }
+  // Allocate S in the Map regardless of emission.
+  const auto &TheCounterPair = (*RegionCounterMap)[S];
 
   if (!Builder.GetInsertBlock())
     return;
 
+  const CounterPair::ValueOpt &Counter =
+      (UseSkipPath ? TheCounterPair.Skipped : TheCounterPair.Executed);
+  if (!Counter.hasValue())
+    return;
+
   // Make sure that pointer to global is passed in with zero addrspace
   // This is relevant during GPU profiling
   auto *NormalizedFuncNameVarPtr =



More information about the cfe-commits mailing list