[clang] [llvm] [MC/DC][Coverage] Loosen the limit of NumConds from 6 (PR #82448)

NAKAMURA Takumi via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 20 16:52:29 PST 2024


https://github.com/chapuni created https://github.com/llvm/llvm-project/pull/82448

This is the draft of: https://discourse.llvm.org/t/rfc-coverage-new-algorithm-and-file-format-for-mc-dc/76798

All tests have not been satisfied yet.

Depends on #80676

>From d168e0cb85eb150caa7ab241f136c5a23f79ba38 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Mon, 5 Feb 2024 00:33:40 +0900
Subject: [PATCH 01/11] Implement MCDCTVIdxBuilder and MCDCTestVectorBuilder
 (LLVM side)

This accept current version of profdata. The output might be different.

See also
https://discourse.llvm.org/t/rfc-coverage-new-algorithm-and-file-format-for-mc-dc/76798
---
 .../ProfileData/Coverage/CoverageMapping.h    |  24 ++
 .../ProfileData/Coverage/CoverageMapping.cpp  | 226 +++++++++++++-----
 llvm/test/tools/llvm-cov/mcdc-const.test      |  28 +--
 llvm/test/tools/llvm-cov/mcdc-general.test    |  16 +-
 4 files changed, 214 insertions(+), 80 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index 88ec60c7aa33c6..62867275a8524d 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -32,6 +32,7 @@
 #include "llvm/Support/raw_ostream.h"
 #include <cassert>
 #include <cstdint>
+#include <functional>
 #include <iterator>
 #include <memory>
 #include <sstream>
@@ -557,6 +558,29 @@ struct MCDCRecord {
   }
 };
 
+class MCDCTVIdxBuilder {
+public:
+  struct MCDCNode {
+    int InCount = 0;
+    unsigned Width;
+    struct {
+      int ID;
+      int Idx;
+    } Conds[2];
+  };
+
+  SmallVector<MCDCNode> Nodes;
+  unsigned NumTestVectors;
+
+public:
+  using NodeIDs = std::tuple<unsigned, // ID1 (ends with 0)
+                             unsigned, // ID1 for False
+                             unsigned  // ID1 for True
+                             >;
+
+  MCDCTVIdxBuilder(std::function<NodeIDs(bool TellSize)> Fetcher);
+};
+
 /// A Counter mapping context is used to connect the counters, expressions
 /// and the obtained counter values.
 class CounterMappingContext {
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index 39e43f86eab5e9..d3a60c664b9e9a 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -223,6 +223,171 @@ Expected<int64_t> CounterMappingContext::evaluate(const Counter &C) const {
   return LastPoppedValue;
 }
 
+MCDCTVIdxBuilder::MCDCTVIdxBuilder(
+    std::function<NodeIDs(bool TellSize)> Fetcher) {
+  // Build Nodes and set up each InCount
+  int MaxID = -1;
+  Nodes.resize(std::get<0>(Fetcher(true)));
+  while (true) {
+    auto [ID1, FalseID1, TrueID1] = Fetcher(false);
+    if (ID1 == 0)
+      break;
+    if (Nodes.size() < ID1)
+      Nodes.resize(ID1);
+    int ID = ID1 - 1;
+    MaxID = std::max(MaxID, ID);
+    auto &Node = Nodes[ID];
+    Node.Conds[0].ID = FalseID1 - 1;
+    Node.Conds[1].ID = TrueID1 - 1;
+    for (unsigned I = 0; I < 2; ++I) {
+      int NextID = Node.Conds[I].ID;
+      if (NextID >= 0)
+        ++Nodes[NextID].InCount;
+    }
+  }
+
+  if (MaxID < 0)
+    return;
+
+  // Sort key ordered by <-Width, Ord>
+  SmallVector<std::tuple<int,      /// -Width
+                         unsigned, /// Ord
+                         int,      /// ID
+                         unsigned  /// Cond (0 or 1)
+                         >>
+      Decisions;
+
+  // Traverse Nodes to assign Idx
+  SmallVector<int> Q;
+  assert(Nodes[0].InCount == 0);
+  Nodes[0].Width = 1;
+  Q.push_back(0);
+
+  unsigned Ord = 0;
+  while (!Q.empty()) {
+    int ID = *Q.begin();
+    Q.erase(Q.begin());
+    auto &Node = Nodes[ID];
+    assert(Node.Width > 0);
+
+    for (unsigned I = 0; I < 2; ++I) {
+      int NextID = Node.Conds[I].ID;
+      assert(NextID != 0);
+      if (NextID < 0) {
+        Decisions.emplace_back(-Node.Width, Ord++, ID, I);
+        assert(Ord == Decisions.size());
+        continue;
+      }
+
+      auto &NextNode = Nodes[NextID];
+      assert(NextNode.InCount > 0);
+      Node.Conds[I].Idx = NextNode.Width; // ???
+      NextNode.Width += Node.Width;
+      if (--NextNode.InCount == 0)
+        Q.push_back(NextID);
+    }
+  }
+
+  std::sort(Decisions.begin(), Decisions.end());
+
+  // Assign TestVector Index
+  unsigned CurIdx = 0;
+  for (auto [NegWidth, Ord, ID, C] : Decisions) {
+    unsigned Width = -NegWidth;
+    auto &Node = Nodes[ID];
+    assert(Node.Width == Width);
+    assert(Node.Conds[C].Idx == 0);
+    assert(Node.Conds[C].ID < 0);
+    Node.Conds[C].Idx = CurIdx;
+    CurIdx += Width;
+  }
+  NumTestVectors = CurIdx;
+}
+
+namespace {
+
+class MCDCTestVectorBuilder : public MCDCTVIdxBuilder {
+  MCDCRecord::TestVectors TestVectors;
+  const BitVector &Bitmap;
+  unsigned BitmapIdx;
+#ifndef NDEBUG
+  DenseSet<unsigned> TVIDs;
+#endif
+
+  class BranchProvider {
+    ArrayRef<const CounterMappingRegion *> Branches;
+    unsigned BranchIdx = 0;
+
+  public:
+    BranchProvider(ArrayRef<const CounterMappingRegion *> Branches)
+        : Branches(Branches) {}
+
+    std::function<NodeIDs(bool)> getFetcher() {
+      return [this](bool TellSize) {
+        if (TellSize)
+          return NodeIDs(Branches.size(), 0, 0);
+        if (BranchIdx >= Branches.size())
+          return NodeIDs(0, 0, 0);
+        const auto *B = Branches[BranchIdx++];
+        return NodeIDs(B->MCDCParams.ID, B->MCDCParams.FalseID,
+                       B->MCDCParams.TrueID);
+      };
+    }
+  };
+
+public:
+  MCDCTestVectorBuilder(ArrayRef<const CounterMappingRegion *> Branches,
+                        const BitVector &Bitmap, unsigned BitmapIdx)
+      : MCDCTVIdxBuilder(BranchProvider(Branches).getFetcher()), Bitmap(Bitmap),
+        BitmapIdx(BitmapIdx) {}
+
+protected:
+  MCDCRecord::TestVector TempTV;
+
+  void buildTestVector(int ID = 0, unsigned TVIdx = 0, unsigned Index = 0) {
+    const auto &Node = Nodes[ID];
+
+    for (unsigned I = 0; I < 2; ++I) {
+      auto MCDCCond = (I ? MCDCRecord::MCDC_True : MCDCRecord::MCDC_False);
+      const auto &Cond = Node.Conds[I];
+      auto NextID = Cond.ID;
+      Index |= I << ID;
+      TempTV[ID] = MCDCCond;
+      if (NextID >= 0) {
+        buildTestVector(NextID, TVIdx + Cond.Idx, Index);
+        continue;
+      }
+
+      auto FinalTVIdx = Cond.Idx + TVIdx;
+      assert(TVIdx < Node.Width);
+#ifndef NDEBUG
+      assert(!TVIDs.contains(FinalTVIdx));
+      TVIDs.insert(FinalTVIdx);
+#endif
+
+      assert(BitmapIdx + Index < Bitmap.size() && "Bitmap overrun");
+      if (!Bitmap[BitmapIdx + Index])
+        continue;
+
+      TestVectors.push_back(TempTV);
+      TestVectors.back().push_back(MCDCCond);
+    }
+
+    // Reset back to DontCare.
+    TempTV[ID] = MCDCRecord::MCDC_DontCare;
+  }
+
+public:
+  MCDCRecord::TestVectors findExecutedTestVectors() {
+    TempTV.resize(Nodes.size(), MCDCRecord::MCDC_DontCare);
+    buildTestVector();
+    assert(TVIDs.size() == NumTestVectors);
+    return std::move(TestVectors);
+  }
+};
+
+} // namespace
+
 class MCDCRecordProcessor {
   /// A bitmap representing the executed test vectors for a boolean expression.
   /// Each index of the bitmap corresponds to a possible test vector. An index
@@ -251,9 +416,6 @@ class MCDCRecordProcessor {
   /// Mapping of calculated MC/DC Independence Pairs for each condition.
   MCDCRecord::TVPairMap IndependencePairs;
 
-  /// Total number of possible Test Vectors for the boolean expression.
-  MCDCRecord::TestVectors TestVectors;
-
   /// Actual executed Test Vectors for the boolean expression, based on
   /// ExecutedTestVectorBitmap.
   MCDCRecord::TestVectors ExecVectors;
@@ -265,56 +427,9 @@ class MCDCRecordProcessor {
       : Bitmap(Bitmap), Region(Region), Branches(Branches),
         NumConditions(Region.MCDCParams.NumConditions),
         BitmapIdx(Region.MCDCParams.BitmapIdx * CHAR_BIT),
-        Folded(NumConditions, false), IndependencePairs(NumConditions),
-        TestVectors((size_t)1 << NumConditions) {}
+        Folded(NumConditions, false), IndependencePairs(NumConditions) {}
 
 private:
-  void recordTestVector(MCDCRecord::TestVector &TV, unsigned Index,
-                        MCDCRecord::CondState Result) {
-    // Copy the completed test vector to the vector of testvectors.
-    TestVectors[Index] = TV;
-
-    // The final value (T,F) is equal to the last non-dontcare state on the
-    // path (in a short-circuiting system).
-    TestVectors[Index].push_back(Result);
-  }
-
-  // Walk the binary decision diagram and try assigning both false and true to
-  // each node. When a terminal node (ID == 0) is reached, fill in the value in
-  // the truth table.
-  void buildTestVector(MCDCRecord::TestVector &TV, unsigned ID,
-                       unsigned Index) {
-    const CounterMappingRegion *Branch = Map[ID];
-
-    TV[ID - 1] = MCDCRecord::MCDC_False;
-    if (Branch->MCDCParams.FalseID > 0)
-      buildTestVector(TV, Branch->MCDCParams.FalseID, Index);
-    else
-      recordTestVector(TV, Index, MCDCRecord::MCDC_False);
-
-    Index |= 1 << (ID - 1);
-    TV[ID - 1] = MCDCRecord::MCDC_True;
-    if (Branch->MCDCParams.TrueID > 0)
-      buildTestVector(TV, Branch->MCDCParams.TrueID, Index);
-    else
-      recordTestVector(TV, Index, MCDCRecord::MCDC_True);
-
-    // Reset back to DontCare.
-    TV[ID - 1] = MCDCRecord::MCDC_DontCare;
-  }
-
-  /// Walk the bits in the bitmap.  A bit set to '1' indicates that the test
-  /// vector at the corresponding index was executed during a test run.
-  void findExecutedTestVectors() {
-    for (unsigned Idx = 0; Idx < (1u << NumConditions); ++Idx) {
-      assert(BitmapIdx + Idx < Bitmap.size() && "Bitmap overrun");
-      if (Bitmap[BitmapIdx + Idx] == 0)
-        continue;
-      assert(!TestVectors[Idx].empty() && "Test Vector doesn't exist.");
-      ExecVectors.push_back(TestVectors[Idx]);
-    }
-  }
-
   // 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.
@@ -378,14 +493,9 @@ class MCDCRecordProcessor {
       Folded[I++] = (B->Count.isZero() && B->FalseCount.isZero());
     }
 
-    // Walk the binary decision diagram to enumerate all possible test vectors.
-    // We start at the root node (ID == 1) with all values being DontCare.
-    // `Index` encodes the bitmask of true values and is initially 0.
-    MCDCRecord::TestVector TV(NumConditions, MCDCRecord::MCDC_DontCare);
-    buildTestVector(TV, 1, 0);
-
     // Using Profile Bitmap from runtime, mark the executed test vectors.
-    findExecutedTestVectors();
+    ExecVectors = MCDCTestVectorBuilder(Branches, Bitmap, BitmapIdx)
+                      .findExecutedTestVectors();
 
     // Compare executed test vectors against each other to find an independence
     // pairs for each condition.  This processing takes the most time.
diff --git a/llvm/test/tools/llvm-cov/mcdc-const.test b/llvm/test/tools/llvm-cov/mcdc-const.test
index 0b2c9c98d53555..5424625cf6a6b5 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 { T,  C  = T      }
-// CHECKFULLCASE-NEXT: |  2 { F,  C  = T      }
+//      CHECKFULLCASE: |  1 { F,  C  = T      }
+// CHECKFULLCASE-NEXT: |  2 { T,  C  = T      }
 //      CHECKFULLCASE: |  C1-Pair: not covered
 // CHECKFULLCASE-NEXT: |  C2-Pair: constant folded
 //      CHECKFULLCASE: |  MC/DC Coverage for Decision: 0.00%
@@ -106,8 +106,8 @@
 // CHECKFULLCASE-NEXT: |  C2-Pair: not covered
 // CHECKFULLCASE-NEXT: |  C3-Pair: not covered
 //      CHECKFULLCASE: |  MC/DC Coverage for Decision: 0.00%
-//      CHECKFULLCASE: |  1 { T,  C,  -  = T      }
-// CHECKFULLCASE-NEXT: |  2 { F,  C,  -  = T      }
+//      CHECKFULLCASE: |  1 { F,  C,  -  = T      }
+// CHECKFULLCASE-NEXT: |  2 { T,  C,  -  = T      }
 //      CHECKFULLCASE: |  C1-Pair: not covered
 // CHECKFULLCASE-NEXT: |  C2-Pair: constant folded
 // CHECKFULLCASE-NEXT: |  C3-Pair: not covered
@@ -118,8 +118,8 @@
 // CHECKFULLCASE-NEXT: |  C2-Pair: not covered
 // CHECKFULLCASE-NEXT: |  C3-Pair: not covered
 //      CHECKFULLCASE: |  MC/DC Coverage for Decision: 0.00%
-//      CHECKFULLCASE: |  1 { T,  C,  -  = T      }
-// CHECKFULLCASE-NEXT: |  2 { F,  C,  T  = T      }
+//      CHECKFULLCASE: |  1 { F,  C,  T  = T      }
+// CHECKFULLCASE-NEXT: |  2 { T,  C,  -  = 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 { T,  -,  C  = T      }
-// CHECKFULLCASE-NEXT: |  2 { F,  T,  C  = T      }
+//      CHECKFULLCASE: |  1 { F,  T,  C  = T      }
+// CHECKFULLCASE-NEXT: |  2 { 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 { T,  C,  -  = T      }
-// CHECKFULLCASE-NEXT: |  2 { F,  C,  -  = T      }
+//      CHECKFULLCASE: |  1 { F,  C,  -  = T      }
+// CHECKFULLCASE-NEXT: |  2 { T,  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 { T,  -,  C  = T      }
-// CHECKFULLCASE-NEXT: |  2 { F,  T,  C  = T      }
+//      CHECKFULLCASE: |  1 { F,  T,  C  = T      }
+// CHECKFULLCASE-NEXT: |  2 { 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 { T,  C,  -  = T      }
-// CHECKFULLCASE-NEXT: |  2 { F,  C,  T  = T      }
+//      CHECKFULLCASE: |  1 { F,  C,  T  = T      }
+// CHECKFULLCASE-NEXT: |  2 { T,  C,  -  = 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 753036bedaf170..4b59ce59d638e9 100644
--- a/llvm/test/tools/llvm-cov/mcdc-general.test
+++ b/llvm/test/tools/llvm-cov/mcdc-general.test
@@ -19,16 +19,16 @@
 // CHECK-NEXT:  |
 // CHECK-NEXT:  |     C1, C2, C3, C4    Result
 // CHECK-NEXT:  |  1 { F,  -,  F,  -  = F      }
-// CHECK-NEXT:  |  2 { T,  F,  F,  -  = F      }
-// CHECK-NEXT:  |  3 { F,  -,  T,  F  = F      }
+// CHECK-NEXT:  |  2 { F,  -,  T,  F  = F      }
+// CHECK-NEXT:  |  3 { T,  F,  F,  -  = F      }
 // CHECK-NEXT:  |  4 { T,  F,  T,  F  = F      }
-// CHECK-NEXT:  |  5 { T,  T,  -,  -  = T      }
-// CHECK-NEXT:  |  6 { T,  F,  T,  T  = T      }
+// CHECK-NEXT:  |  5 { T,  F,  T,  T  = T      }
+// CHECK-NEXT:  |  6 { T,  T,  -,  -  = T      }
 // CHECK-NEXT:  |
-// CHECK-NEXT:  |  C1-Pair: covered: (1,5)
-// CHECK-NEXT:  |  C2-Pair: covered: (2,5)
-// CHECK-NEXT:  |  C3-Pair: covered: (2,6)
-// CHECK-NEXT:  |  C4-Pair: covered: (4,6)
+// CHECK-NEXT:  |  C1-Pair: covered: (1,6)
+// CHECK-NEXT:  |  C2-Pair: covered: (3,6)
+// CHECK-NEXT:  |  C3-Pair: covered: (3,5)
+// CHECK-NEXT:  |  C4-Pair: covered: (4,5)
 // CHECK-NEXT:  |  MC/DC Coverage for Decision: 100.00%
 // CHECK-NEXT:  |
 // CHECK-NEXT:  ------------------

>From 35b19ea47f34bb14b30fca25572fcd55a3b6b3b5 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Tue, 6 Feb 2024 17:21:04 +0900
Subject: [PATCH 02/11] Revert "Implement MCDCTVIdxBuilder and
 MCDCTestVectorBuilder (LLVM side)"

This reverts commit d168e0cb85eb150caa7ab241f136c5a23f79ba38.
---
 .../ProfileData/Coverage/CoverageMapping.h    |  24 --
 .../ProfileData/Coverage/CoverageMapping.cpp  | 226 +++++-------------
 llvm/test/tools/llvm-cov/mcdc-const.test      |  28 +--
 llvm/test/tools/llvm-cov/mcdc-general.test    |  16 +-
 4 files changed, 80 insertions(+), 214 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index 62867275a8524d..88ec60c7aa33c6 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -32,7 +32,6 @@
 #include "llvm/Support/raw_ostream.h"
 #include <cassert>
 #include <cstdint>
-#include <functional>
 #include <iterator>
 #include <memory>
 #include <sstream>
@@ -558,29 +557,6 @@ struct MCDCRecord {
   }
 };
 
-class MCDCTVIdxBuilder {
-public:
-  struct MCDCNode {
-    int InCount = 0;
-    unsigned Width;
-    struct {
-      int ID;
-      int Idx;
-    } Conds[2];
-  };
-
-  SmallVector<MCDCNode> Nodes;
-  unsigned NumTestVectors;
-
-public:
-  using NodeIDs = std::tuple<unsigned, // ID1 (ends with 0)
-                             unsigned, // ID1 for False
-                             unsigned  // ID1 for True
-                             >;
-
-  MCDCTVIdxBuilder(std::function<NodeIDs(bool TellSize)> Fetcher);
-};
-
 /// A Counter mapping context is used to connect the counters, expressions
 /// and the obtained counter values.
 class CounterMappingContext {
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index d3a60c664b9e9a..39e43f86eab5e9 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -223,171 +223,6 @@ Expected<int64_t> CounterMappingContext::evaluate(const Counter &C) const {
   return LastPoppedValue;
 }
 
-MCDCTVIdxBuilder::MCDCTVIdxBuilder(
-    std::function<NodeIDs(bool TellSize)> Fetcher) {
-  // Build Nodes and set up each InCount
-  int MaxID = -1;
-  Nodes.resize(std::get<0>(Fetcher(true)));
-  while (true) {
-    auto [ID1, FalseID1, TrueID1] = Fetcher(false);
-    if (ID1 == 0)
-      break;
-    if (Nodes.size() < ID1)
-      Nodes.resize(ID1);
-    int ID = ID1 - 1;
-    MaxID = std::max(MaxID, ID);
-    auto &Node = Nodes[ID];
-    Node.Conds[0].ID = FalseID1 - 1;
-    Node.Conds[1].ID = TrueID1 - 1;
-    for (unsigned I = 0; I < 2; ++I) {
-      int NextID = Node.Conds[I].ID;
-      if (NextID >= 0)
-        ++Nodes[NextID].InCount;
-    }
-  }
-
-  if (MaxID < 0)
-    return;
-
-  // Sort key ordered by <-Width, Ord>
-  SmallVector<std::tuple<int,      /// -Width
-                         unsigned, /// Ord
-                         int,      /// ID
-                         unsigned  /// Cond (0 or 1)
-                         >>
-      Decisions;
-
-  // Traverse Nodes to assign Idx
-  SmallVector<int> Q;
-  assert(Nodes[0].InCount == 0);
-  Nodes[0].Width = 1;
-  Q.push_back(0);
-
-  unsigned Ord = 0;
-  while (!Q.empty()) {
-    int ID = *Q.begin();
-    Q.erase(Q.begin());
-    auto &Node = Nodes[ID];
-    assert(Node.Width > 0);
-
-    for (unsigned I = 0; I < 2; ++I) {
-      int NextID = Node.Conds[I].ID;
-      assert(NextID != 0);
-      if (NextID < 0) {
-        Decisions.emplace_back(-Node.Width, Ord++, ID, I);
-        assert(Ord == Decisions.size());
-        continue;
-      }
-
-      auto &NextNode = Nodes[NextID];
-      assert(NextNode.InCount > 0);
-      Node.Conds[I].Idx = NextNode.Width; // ???
-      NextNode.Width += Node.Width;
-      if (--NextNode.InCount == 0)
-        Q.push_back(NextID);
-    }
-  }
-
-  std::sort(Decisions.begin(), Decisions.end());
-
-  // Assign TestVector Index
-  unsigned CurIdx = 0;
-  for (auto [NegWidth, Ord, ID, C] : Decisions) {
-    unsigned Width = -NegWidth;
-    auto &Node = Nodes[ID];
-    assert(Node.Width == Width);
-    assert(Node.Conds[C].Idx == 0);
-    assert(Node.Conds[C].ID < 0);
-    Node.Conds[C].Idx = CurIdx;
-    CurIdx += Width;
-  }
-  NumTestVectors = CurIdx;
-}
-
-namespace {
-
-class MCDCTestVectorBuilder : public MCDCTVIdxBuilder {
-  MCDCRecord::TestVectors TestVectors;
-  const BitVector &Bitmap;
-  unsigned BitmapIdx;
-#ifndef NDEBUG
-  DenseSet<unsigned> TVIDs;
-#endif
-
-  class BranchProvider {
-    ArrayRef<const CounterMappingRegion *> Branches;
-    unsigned BranchIdx = 0;
-
-  public:
-    BranchProvider(ArrayRef<const CounterMappingRegion *> Branches)
-        : Branches(Branches) {}
-
-    std::function<NodeIDs(bool)> getFetcher() {
-      return [this](bool TellSize) {
-        if (TellSize)
-          return NodeIDs(Branches.size(), 0, 0);
-        if (BranchIdx >= Branches.size())
-          return NodeIDs(0, 0, 0);
-        const auto *B = Branches[BranchIdx++];
-        return NodeIDs(B->MCDCParams.ID, B->MCDCParams.FalseID,
-                       B->MCDCParams.TrueID);
-      };
-    }
-  };
-
-public:
-  MCDCTestVectorBuilder(ArrayRef<const CounterMappingRegion *> Branches,
-                        const BitVector &Bitmap, unsigned BitmapIdx)
-      : MCDCTVIdxBuilder(BranchProvider(Branches).getFetcher()), Bitmap(Bitmap),
-        BitmapIdx(BitmapIdx) {}
-
-protected:
-  MCDCRecord::TestVector TempTV;
-
-  void buildTestVector(int ID = 0, unsigned TVIdx = 0, unsigned Index = 0) {
-    const auto &Node = Nodes[ID];
-
-    for (unsigned I = 0; I < 2; ++I) {
-      auto MCDCCond = (I ? MCDCRecord::MCDC_True : MCDCRecord::MCDC_False);
-      const auto &Cond = Node.Conds[I];
-      auto NextID = Cond.ID;
-      Index |= I << ID;
-      TempTV[ID] = MCDCCond;
-      if (NextID >= 0) {
-        buildTestVector(NextID, TVIdx + Cond.Idx, Index);
-        continue;
-      }
-
-      auto FinalTVIdx = Cond.Idx + TVIdx;
-      assert(TVIdx < Node.Width);
-#ifndef NDEBUG
-      assert(!TVIDs.contains(FinalTVIdx));
-      TVIDs.insert(FinalTVIdx);
-#endif
-
-      assert(BitmapIdx + Index < Bitmap.size() && "Bitmap overrun");
-      if (!Bitmap[BitmapIdx + Index])
-        continue;
-
-      TestVectors.push_back(TempTV);
-      TestVectors.back().push_back(MCDCCond);
-    }
-
-    // Reset back to DontCare.
-    TempTV[ID] = MCDCRecord::MCDC_DontCare;
-  }
-
-public:
-  MCDCRecord::TestVectors findExecutedTestVectors() {
-    TempTV.resize(Nodes.size(), MCDCRecord::MCDC_DontCare);
-    buildTestVector();
-    assert(TVIDs.size() == NumTestVectors);
-    return std::move(TestVectors);
-  }
-};
-
-} // namespace
-
 class MCDCRecordProcessor {
   /// A bitmap representing the executed test vectors for a boolean expression.
   /// Each index of the bitmap corresponds to a possible test vector. An index
@@ -416,6 +251,9 @@ class MCDCRecordProcessor {
   /// Mapping of calculated MC/DC Independence Pairs for each condition.
   MCDCRecord::TVPairMap IndependencePairs;
 
+  /// Total number of possible Test Vectors for the boolean expression.
+  MCDCRecord::TestVectors TestVectors;
+
   /// Actual executed Test Vectors for the boolean expression, based on
   /// ExecutedTestVectorBitmap.
   MCDCRecord::TestVectors ExecVectors;
@@ -427,9 +265,56 @@ class MCDCRecordProcessor {
       : Bitmap(Bitmap), Region(Region), Branches(Branches),
         NumConditions(Region.MCDCParams.NumConditions),
         BitmapIdx(Region.MCDCParams.BitmapIdx * CHAR_BIT),
-        Folded(NumConditions, false), IndependencePairs(NumConditions) {}
+        Folded(NumConditions, false), IndependencePairs(NumConditions),
+        TestVectors((size_t)1 << NumConditions) {}
 
 private:
+  void recordTestVector(MCDCRecord::TestVector &TV, unsigned Index,
+                        MCDCRecord::CondState Result) {
+    // Copy the completed test vector to the vector of testvectors.
+    TestVectors[Index] = TV;
+
+    // The final value (T,F) is equal to the last non-dontcare state on the
+    // path (in a short-circuiting system).
+    TestVectors[Index].push_back(Result);
+  }
+
+  // Walk the binary decision diagram and try assigning both false and true to
+  // each node. When a terminal node (ID == 0) is reached, fill in the value in
+  // the truth table.
+  void buildTestVector(MCDCRecord::TestVector &TV, unsigned ID,
+                       unsigned Index) {
+    const CounterMappingRegion *Branch = Map[ID];
+
+    TV[ID - 1] = MCDCRecord::MCDC_False;
+    if (Branch->MCDCParams.FalseID > 0)
+      buildTestVector(TV, Branch->MCDCParams.FalseID, Index);
+    else
+      recordTestVector(TV, Index, MCDCRecord::MCDC_False);
+
+    Index |= 1 << (ID - 1);
+    TV[ID - 1] = MCDCRecord::MCDC_True;
+    if (Branch->MCDCParams.TrueID > 0)
+      buildTestVector(TV, Branch->MCDCParams.TrueID, Index);
+    else
+      recordTestVector(TV, Index, MCDCRecord::MCDC_True);
+
+    // Reset back to DontCare.
+    TV[ID - 1] = MCDCRecord::MCDC_DontCare;
+  }
+
+  /// Walk the bits in the bitmap.  A bit set to '1' indicates that the test
+  /// vector at the corresponding index was executed during a test run.
+  void findExecutedTestVectors() {
+    for (unsigned Idx = 0; Idx < (1u << NumConditions); ++Idx) {
+      assert(BitmapIdx + Idx < Bitmap.size() && "Bitmap overrun");
+      if (Bitmap[BitmapIdx + Idx] == 0)
+        continue;
+      assert(!TestVectors[Idx].empty() && "Test Vector doesn't exist.");
+      ExecVectors.push_back(TestVectors[Idx]);
+    }
+  }
+
   // 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.
@@ -493,9 +378,14 @@ class MCDCRecordProcessor {
       Folded[I++] = (B->Count.isZero() && B->FalseCount.isZero());
     }
 
+    // Walk the binary decision diagram to enumerate all possible test vectors.
+    // We start at the root node (ID == 1) with all values being DontCare.
+    // `Index` encodes the bitmask of true values and is initially 0.
+    MCDCRecord::TestVector TV(NumConditions, MCDCRecord::MCDC_DontCare);
+    buildTestVector(TV, 1, 0);
+
     // Using Profile Bitmap from runtime, mark the executed test vectors.
-    ExecVectors = MCDCTestVectorBuilder(Branches, Bitmap, BitmapIdx)
-                      .findExecutedTestVectors();
+    findExecutedTestVectors();
 
     // Compare executed test vectors against each other to find an independence
     // pairs for each condition.  This processing takes the most time.
diff --git a/llvm/test/tools/llvm-cov/mcdc-const.test b/llvm/test/tools/llvm-cov/mcdc-const.test
index 5424625cf6a6b5..0b2c9c98d53555 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,8 +106,8 @@
 // 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
@@ -118,8 +118,8 @@
 // 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 4b59ce59d638e9..753036bedaf170 100644
--- a/llvm/test/tools/llvm-cov/mcdc-general.test
+++ b/llvm/test/tools/llvm-cov/mcdc-general.test
@@ -19,16 +19,16 @@
 // 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:  |  5 { T,  T,  -,  -  = T      }
+// CHECK-NEXT:  |  6 { T,  F,  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:  |  C4-Pair: covered: (4,5)
+// CHECK-NEXT:  |  C1-Pair: covered: (1,5)
+// CHECK-NEXT:  |  C2-Pair: covered: (2,5)
+// CHECK-NEXT:  |  C3-Pair: covered: (2,6)
+// CHECK-NEXT:  |  C4-Pair: covered: (4,6)
 // CHECK-NEXT:  |  MC/DC Coverage for Decision: 100.00%
 // CHECK-NEXT:  |
 // CHECK-NEXT:  ------------------

>From 8c777ebbea6f5d005de2112b88eceec9b5eeeadd Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Tue, 6 Feb 2024 17:06:11 +0900
Subject: [PATCH 03/11] [Coverage] MCDCRecordProcessor: Find `ExecVectors`
 directly

Deprecate `TestVectors`, since no one uses it.

This affects the output order of ExecVectors.
The current impl emits sorted by binary value of ExecVector.
This impl emits along the traversal of `buildTestVector()`.
---
 .../ProfileData/Coverage/CoverageMapping.cpp  | 31 +++++++------------
 llvm/test/tools/llvm-cov/mcdc-const.test      | 28 ++++++++---------
 llvm/test/tools/llvm-cov/mcdc-general.test    | 16 +++++-----
 3 files changed, 33 insertions(+), 42 deletions(-)

diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index 6b189c31463283..eb0996e33b70dc 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -253,9 +253,6 @@ class MCDCRecordProcessor {
   /// Mapping of calculated MC/DC Independence Pairs for each condition.
   MCDCRecord::TVPairMap IndependencePairs;
 
-  /// Total number of possible Test Vectors for the boolean expression.
-  MCDCRecord::TestVectors TestVectors;
-
   /// Actual executed Test Vectors for the boolean expression, based on
   /// ExecutedTestVectorBitmap.
   MCDCRecord::TestVectors ExecVectors;
@@ -267,18 +264,20 @@ class MCDCRecordProcessor {
       : Bitmap(Bitmap), Region(Region), Branches(Branches),
         NumConditions(Region.MCDCParams.NumConditions),
         BitmapIdx(Region.MCDCParams.BitmapIdx * CHAR_BIT),
-        Folded(NumConditions, false), IndependencePairs(NumConditions),
-        TestVectors((size_t)1 << NumConditions) {}
+        Folded(NumConditions, false), IndependencePairs(NumConditions) {}
 
 private:
   void recordTestVector(MCDCRecord::TestVector &TV, unsigned Index,
                         MCDCRecord::CondState Result) {
+    if (!Bitmap[BitmapIdx + Index])
+      return;
+
     // Copy the completed test vector to the vector of testvectors.
-    TestVectors[Index] = TV;
+    ExecVectors.push_back(TV);
 
     // The final value (T,F) is equal to the last non-dontcare state on the
     // path (in a short-circuiting system).
-    TestVectors[Index].push_back(Result);
+    ExecVectors.back().push_back(Result);
   }
 
   // Walk the binary decision diagram and try assigning both false and true to
@@ -308,13 +307,11 @@ class MCDCRecordProcessor {
   /// Walk the bits in the bitmap.  A bit set to '1' indicates that the test
   /// vector at the corresponding index was executed during a test run.
   void findExecutedTestVectors() {
-    for (unsigned Idx = 0; Idx < (1u << NumConditions); ++Idx) {
-      assert(BitmapIdx + Idx < Bitmap.size() && "Bitmap overrun");
-      if (Bitmap[BitmapIdx + Idx] == 0)
-        continue;
-      assert(!TestVectors[Idx].empty() && "Test Vector doesn't exist.");
-      ExecVectors.push_back(TestVectors[Idx]);
-    }
+    // Walk the binary decision diagram to enumerate all possible test vectors.
+    // We start at the root node (ID == 1) with all values being DontCare.
+    // `Index` encodes the bitmask of true values and is initially 0.
+    MCDCRecord::TestVector TV(NumConditions, MCDCRecord::MCDC_DontCare);
+    buildTestVector(TV, 1, 0);
   }
 
   // Find an independence pair for each condition:
@@ -380,12 +377,6 @@ class MCDCRecordProcessor {
       Folded[I++] = (B->Count.isZero() && B->FalseCount.isZero());
     }
 
-    // Walk the binary decision diagram to enumerate all possible test vectors.
-    // We start at the root node (ID == 1) with all values being DontCare.
-    // `Index` encodes the bitmask of true values and is initially 0.
-    MCDCRecord::TestVector TV(NumConditions, MCDCRecord::MCDC_DontCare);
-    buildTestVector(TV, 1, 0);
-
     // Using Profile Bitmap from runtime, mark the executed test vectors.
     findExecutedTestVectors();
 
diff --git a/llvm/test/tools/llvm-cov/mcdc-const.test b/llvm/test/tools/llvm-cov/mcdc-const.test
index 0b2c9c98d53555..5424625cf6a6b5 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 { T,  C  = T      }
-// CHECKFULLCASE-NEXT: |  2 { F,  C  = T      }
+//      CHECKFULLCASE: |  1 { F,  C  = T      }
+// CHECKFULLCASE-NEXT: |  2 { T,  C  = T      }
 //      CHECKFULLCASE: |  C1-Pair: not covered
 // CHECKFULLCASE-NEXT: |  C2-Pair: constant folded
 //      CHECKFULLCASE: |  MC/DC Coverage for Decision: 0.00%
@@ -106,8 +106,8 @@
 // CHECKFULLCASE-NEXT: |  C2-Pair: not covered
 // CHECKFULLCASE-NEXT: |  C3-Pair: not covered
 //      CHECKFULLCASE: |  MC/DC Coverage for Decision: 0.00%
-//      CHECKFULLCASE: |  1 { T,  C,  -  = T      }
-// CHECKFULLCASE-NEXT: |  2 { F,  C,  -  = T      }
+//      CHECKFULLCASE: |  1 { F,  C,  -  = T      }
+// CHECKFULLCASE-NEXT: |  2 { T,  C,  -  = T      }
 //      CHECKFULLCASE: |  C1-Pair: not covered
 // CHECKFULLCASE-NEXT: |  C2-Pair: constant folded
 // CHECKFULLCASE-NEXT: |  C3-Pair: not covered
@@ -118,8 +118,8 @@
 // CHECKFULLCASE-NEXT: |  C2-Pair: not covered
 // CHECKFULLCASE-NEXT: |  C3-Pair: not covered
 //      CHECKFULLCASE: |  MC/DC Coverage for Decision: 0.00%
-//      CHECKFULLCASE: |  1 { T,  C,  -  = T      }
-// CHECKFULLCASE-NEXT: |  2 { F,  C,  T  = T      }
+//      CHECKFULLCASE: |  1 { F,  C,  T  = T      }
+// CHECKFULLCASE-NEXT: |  2 { T,  C,  -  = 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 { T,  -,  C  = T      }
-// CHECKFULLCASE-NEXT: |  2 { F,  T,  C  = T      }
+//      CHECKFULLCASE: |  1 { F,  T,  C  = T      }
+// CHECKFULLCASE-NEXT: |  2 { 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 { T,  C,  -  = T      }
-// CHECKFULLCASE-NEXT: |  2 { F,  C,  -  = T      }
+//      CHECKFULLCASE: |  1 { F,  C,  -  = T      }
+// CHECKFULLCASE-NEXT: |  2 { T,  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 { T,  -,  C  = T      }
-// CHECKFULLCASE-NEXT: |  2 { F,  T,  C  = T      }
+//      CHECKFULLCASE: |  1 { F,  T,  C  = T      }
+// CHECKFULLCASE-NEXT: |  2 { 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 { T,  C,  -  = T      }
-// CHECKFULLCASE-NEXT: |  2 { F,  C,  T  = T      }
+//      CHECKFULLCASE: |  1 { F,  C,  T  = T      }
+// CHECKFULLCASE-NEXT: |  2 { T,  C,  -  = 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 753036bedaf170..4b59ce59d638e9 100644
--- a/llvm/test/tools/llvm-cov/mcdc-general.test
+++ b/llvm/test/tools/llvm-cov/mcdc-general.test
@@ -19,16 +19,16 @@
 // CHECK-NEXT:  |
 // CHECK-NEXT:  |     C1, C2, C3, C4    Result
 // CHECK-NEXT:  |  1 { F,  -,  F,  -  = F      }
-// CHECK-NEXT:  |  2 { T,  F,  F,  -  = F      }
-// CHECK-NEXT:  |  3 { F,  -,  T,  F  = F      }
+// CHECK-NEXT:  |  2 { F,  -,  T,  F  = F      }
+// CHECK-NEXT:  |  3 { T,  F,  F,  -  = F      }
 // CHECK-NEXT:  |  4 { T,  F,  T,  F  = F      }
-// CHECK-NEXT:  |  5 { T,  T,  -,  -  = T      }
-// CHECK-NEXT:  |  6 { T,  F,  T,  T  = T      }
+// CHECK-NEXT:  |  5 { T,  F,  T,  T  = T      }
+// CHECK-NEXT:  |  6 { T,  T,  -,  -  = T      }
 // CHECK-NEXT:  |
-// CHECK-NEXT:  |  C1-Pair: covered: (1,5)
-// CHECK-NEXT:  |  C2-Pair: covered: (2,5)
-// CHECK-NEXT:  |  C3-Pair: covered: (2,6)
-// CHECK-NEXT:  |  C4-Pair: covered: (4,6)
+// CHECK-NEXT:  |  C1-Pair: covered: (1,6)
+// CHECK-NEXT:  |  C2-Pair: covered: (3,6)
+// CHECK-NEXT:  |  C3-Pair: covered: (3,5)
+// CHECK-NEXT:  |  C4-Pair: covered: (4,5)
 // CHECK-NEXT:  |  MC/DC Coverage for Decision: 100.00%
 // CHECK-NEXT:  |
 // CHECK-NEXT:  ------------------

>From 5432aecffd203f232842607ff581a20cbbf1ba3b Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Mon, 5 Feb 2024 00:33:40 +0900
Subject: [PATCH 04/11] Implement MCDCTVIdxBuilder (LLVM side)

This accepts current version of profdata. The output might be different.

See also
https://discourse.llvm.org/t/rfc-coverage-new-algorithm-and-file-format-for-mc-dc/76798
---
 .../ProfileData/Coverage/CoverageMapping.h    |  24 +++
 .../ProfileData/Coverage/CoverageMapping.cpp  | 162 +++++++++++++++---
 2 files changed, 166 insertions(+), 20 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index 88ec60c7aa33c6..45c28e6cfd7927 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -32,6 +32,7 @@
 #include "llvm/Support/raw_ostream.h"
 #include <cassert>
 #include <cstdint>
+#include <functional>
 #include <iterator>
 #include <memory>
 #include <sstream>
@@ -557,6 +558,29 @@ struct MCDCRecord {
   }
 };
 
+class MCDCTVIdxBuilder {
+public:
+  struct MCDCNode {
+    int InCount = 0;
+    int Width;
+    struct {
+      int ID;
+      int Idx;
+    } Conds[2];
+  };
+
+  SmallVector<MCDCNode> Nodes;
+  unsigned NumTestVectors;
+
+public:
+  using NodeIDs = std::tuple<unsigned, // ID1 (ends with 0)
+                             unsigned, // ID1 for False
+                             unsigned  // ID1 for True
+                             >;
+
+  MCDCTVIdxBuilder(std::function<NodeIDs(bool TellSize)> Fetcher);
+};
+
 /// A Counter mapping context is used to connect the counters, expressions
 /// and the obtained counter values.
 class CounterMappingContext {
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index eb0996e33b70dc..5eb78f7a785719 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -223,9 +223,119 @@ Expected<int64_t> CounterMappingContext::evaluate(const Counter &C) const {
   return LastPoppedValue;
 }
 
+MCDCTVIdxBuilder::MCDCTVIdxBuilder(
+    std::function<NodeIDs(bool TellSize)> Fetcher) {
+  // Build Nodes and set up each InCount
+  int MaxID = -1;
+  Nodes.resize(std::get<0>(Fetcher(true)));
+  while (true) {
+    auto [ID1, FalseID1, TrueID1] = Fetcher(false);
+    if (ID1 == 0)
+      break;
+    int ID = ID1 - 1;
+    MaxID = std::max(MaxID, ID);
+    auto &Node = Nodes[ID];
+    Node.Conds[0].ID = FalseID1 - 1;
+    Node.Conds[1].ID = TrueID1 - 1;
+    for (unsigned I = 0; I < 2; ++I) {
+#ifndef NDEBUG
+      Node.Conds[I].Idx = INT_MIN;
+#endif
+      int NextID = Node.Conds[I].ID;
+      if (NextID >= 0)
+        ++Nodes[NextID].InCount;
+    }
+  }
+
+  if (MaxID < 0)
+    return;
+
+  // Sort key ordered by <-Width, Ord>
+  SmallVector<std::tuple<int,      /// -Width
+                         unsigned, /// Ord
+                         int,      /// ID
+                         unsigned  /// Cond (0 or 1)
+                         >>
+      Decisions;
+
+  // Traverse Nodes to assign Idx
+  SmallVector<int> Q;
+  assert(Nodes[0].InCount == 0);
+  Nodes[0].Width = 1;
+  Q.push_back(0);
+
+  unsigned Ord = 0;
+  while (!Q.empty()) {
+    int ID = *Q.begin();
+    Q.erase(Q.begin());
+    auto &Node = Nodes[ID];
+    assert(Node.Width > 0);
+
+    for (unsigned I = 0; I < 2; ++I) {
+      int NextID = Node.Conds[I].ID;
+      assert(NextID != 0);
+      if (NextID < 0) {
+        Decisions.emplace_back(-Node.Width, Ord++, ID, I);
+        assert(Ord == Decisions.size());
+        continue;
+      }
+
+      auto &NextNode = Nodes[NextID];
+      assert(NextNode.InCount > 0);
+      assert(Node.Conds[I].Idx == INT_MIN);
+      Node.Conds[I].Idx = NextNode.Width;
+      NextNode.Width += Node.Width;
+      if (--NextNode.InCount == 0)
+        Q.push_back(NextID);
+    }
+  }
+
+  std::sort(Decisions.begin(), Decisions.end());
+
+  // Assign TestVector Index
+  unsigned CurIdx = 0;
+  for (auto [NegWidth, Ord, ID, C] : Decisions) {
+    int Width = -NegWidth;
+    assert(Nodes[ID].Width == Width);
+    assert(Nodes[ID].Conds[C].Idx == INT_MIN);
+    assert(Nodes[ID].Conds[C].ID < 0);
+    Nodes[ID].Conds[C].Idx = CurIdx;
+    CurIdx += Width;
+  }
+  NumTestVectors = CurIdx;
+
+#ifndef NDEBUG
+  for (const auto &Node : Nodes)
+    for (const auto &Cond : Node.Conds)
+      assert(Cond.Idx != INT_MIN);
+#endif
+}
+
 namespace {
 
-class MCDCRecordProcessor {
+class BranchProvider {
+  using NodeIDs = MCDCTVIdxBuilder::NodeIDs;
+  ArrayRef<const CounterMappingRegion *> Branches;
+  unsigned BranchIdx = 0;
+
+public:
+  BranchProvider(ArrayRef<const CounterMappingRegion *> Branches)
+      : Branches(Branches) {}
+
+  std::function<NodeIDs(bool)> getFetcher() {
+    return [this](bool TellSize) {
+      if (TellSize)
+        return NodeIDs(Branches.size(), 0, 0);
+      if (BranchIdx >= Branches.size())
+        return NodeIDs(0, 0, 0);
+      const auto *B = Branches[BranchIdx++];
+      return NodeIDs(B->MCDCParams.ID, B->MCDCParams.FalseID,
+                     B->MCDCParams.TrueID);
+    };
+  }
+};
+
+class MCDCRecordProcessor : MCDCTVIdxBuilder {
   /// A bitmap representing the executed test vectors for a boolean expression.
   /// Each index of the bitmap corresponds to a possible test vector. An index
   /// with a bit value of '1' indicates that the corresponding Test Vector
@@ -257,18 +367,28 @@ class MCDCRecordProcessor {
   /// ExecutedTestVectorBitmap.
   MCDCRecord::TestVectors ExecVectors;
 
+#ifndef NDEBUG
+  DenseSet<unsigned> TVIDs;
+#endif
+
 public:
   MCDCRecordProcessor(const BitVector &Bitmap,
                       const CounterMappingRegion &Region,
                       ArrayRef<const CounterMappingRegion *> Branches)
-      : Bitmap(Bitmap), Region(Region), Branches(Branches),
+      : MCDCTVIdxBuilder(BranchProvider(Branches).getFetcher()), Bitmap(Bitmap),
+        Region(Region), Branches(Branches),
         NumConditions(Region.MCDCParams.NumConditions),
         BitmapIdx(Region.MCDCParams.BitmapIdx * CHAR_BIT),
         Folded(NumConditions, false), IndependencePairs(NumConditions) {}
 
 private:
-  void recordTestVector(MCDCRecord::TestVector &TV, unsigned Index,
+  void recordTestVector(MCDCRecord::TestVector &TV, int TVIdx, unsigned Index,
                         MCDCRecord::CondState Result) {
+#ifndef NDEBUG
+    assert(!TVIDs.contains(TVIdx));
+    TVIDs.insert(TVIdx);
+#endif
+
     if (!Bitmap[BitmapIdx + Index])
       return;
 
@@ -283,25 +403,26 @@ class MCDCRecordProcessor {
   // Walk the binary decision diagram and try assigning both false and true to
   // each node. When a terminal node (ID == 0) is reached, fill in the value in
   // the truth table.
-  void buildTestVector(MCDCRecord::TestVector &TV, unsigned ID,
+  void buildTestVector(MCDCRecord::TestVector &TV, int ID, int TVIdx,
                        unsigned Index) {
-    const CounterMappingRegion *Branch = Map[ID];
-
-    TV[ID - 1] = MCDCRecord::MCDC_False;
-    if (Branch->MCDCParams.FalseID > 0)
-      buildTestVector(TV, Branch->MCDCParams.FalseID, Index);
-    else
-      recordTestVector(TV, Index, MCDCRecord::MCDC_False);
-
-    Index |= 1 << (ID - 1);
-    TV[ID - 1] = MCDCRecord::MCDC_True;
-    if (Branch->MCDCParams.TrueID > 0)
-      buildTestVector(TV, Branch->MCDCParams.TrueID, Index);
-    else
-      recordTestVector(TV, Index, MCDCRecord::MCDC_True);
+    const auto &Node = Nodes[ID];
+
+    for (unsigned I = 0; I < 2; ++I) {
+      auto MCDCCond = (I ? MCDCRecord::MCDC_True : MCDCRecord::MCDC_False);
+      const auto &Cond = Node.Conds[I];
+      auto NextID = Cond.ID;
+      Index |= I << ID;
+      TV[ID] = MCDCCond;
+      if (NextID >= 0) {
+        buildTestVector(TV, NextID, TVIdx + Cond.Idx, Index);
+      } else {
+        assert(TVIdx < Node.Width);
+        recordTestVector(TV, Cond.Idx + TVIdx, Index, MCDCCond);
+      }
+    }
 
     // Reset back to DontCare.
-    TV[ID - 1] = MCDCRecord::MCDC_DontCare;
+    TV[ID] = MCDCRecord::MCDC_DontCare;
   }
 
   /// Walk the bits in the bitmap.  A bit set to '1' indicates that the test
@@ -311,7 +432,8 @@ class MCDCRecordProcessor {
     // We start at the root node (ID == 1) with all values being DontCare.
     // `Index` encodes the bitmask of true values and is initially 0.
     MCDCRecord::TestVector TV(NumConditions, MCDCRecord::MCDC_DontCare);
-    buildTestVector(TV, 1, 0);
+    buildTestVector(TV, 0, 0, 0);
+    assert(TVIDs.size() == NumTestVectors);
   }
 
   // Find an independence pair for each condition:

>From 3ee8a6131de896869edd03f18e07e193c3229fe4 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Tue, 6 Feb 2024 21:41:43 +0900
Subject: [PATCH 05/11] Update comments and assertions

---
 .../ProfileData/Coverage/CoverageMapping.h    | 14 +++++++---
 .../ProfileData/Coverage/CoverageMapping.cpp  | 28 +++++++++++--------
 2 files changed, 27 insertions(+), 15 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index 45c28e6cfd7927..7341b41aed63d7 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -558,14 +558,15 @@ struct MCDCRecord {
   }
 };
 
+/// Compute Conds[].Idx from Branch-like structure
 class MCDCTVIdxBuilder {
 public:
   struct MCDCNode {
-    int InCount = 0;
-    int Width;
+    int InCount = 0; /// Reference count; temporary use
+    int Width;       /// Number of paths (>= 1)
     struct {
-      int ID;
-      int Idx;
+      int Idx; /// Index in TestVectors bitmap
+      int ID;  /// Final Decision if ID<0, or NextID
     } Conds[2];
   };
 
@@ -578,6 +579,11 @@ class MCDCTVIdxBuilder {
                              unsigned  // ID1 for True
                              >;
 
+  /// Assign Idx
+  /// \param Fetcher Function to fetch NodeIDs.
+  ///        returns {size,0,0} with TellSize=ture
+  ///        returns {ID1,TrueID1,FalseID1} as the value
+  ///        returns {0,0,0} as the terminator
   MCDCTVIdxBuilder(std::function<NodeIDs(bool TellSize)> Fetcher);
 };
 
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index 5eb78f7a785719..cafb36c19c27f9 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -266,25 +266,32 @@ MCDCTVIdxBuilder::MCDCTVIdxBuilder(
 
   unsigned Ord = 0;
   while (!Q.empty()) {
-    int ID = *Q.begin();
-    Q.erase(Q.begin());
+    auto IID = Q.begin();
+    int ID = *IID;
+    Q.erase(IID);
     auto &Node = Nodes[ID];
     assert(Node.Width > 0);
 
     for (unsigned I = 0; I < 2; ++I) {
       int NextID = Node.Conds[I].ID;
-      assert(NextID != 0);
+      assert(NextID != 0 && "NextID should not point to the top");
       if (NextID < 0) {
+        // Decision
         Decisions.emplace_back(-Node.Width, Ord++, ID, I);
         assert(Ord == Decisions.size());
         continue;
       }
 
+      // Inter Node
       auto &NextNode = Nodes[NextID];
       assert(NextNode.InCount > 0);
       assert(Node.Conds[I].Idx == INT_MIN);
+
+      // Assign Idx
       Node.Conds[I].Idx = NextNode.Width;
       NextNode.Width += Node.Width;
+
+      // Ready if all incomings are processed.
       if (--NextNode.InCount == 0)
         Q.push_back(NextID);
     }
@@ -292,7 +299,7 @@ MCDCTVIdxBuilder::MCDCTVIdxBuilder(
 
   std::sort(Decisions.begin(), Decisions.end());
 
-  // Assign TestVector Index
+  // Assign TestVector Indices in Decision Nodes
   unsigned CurIdx = 0;
   for (auto [NegWidth, Ord, ID, C] : Decisions) {
     int Width = -NegWidth;
@@ -313,6 +320,7 @@ MCDCTVIdxBuilder::MCDCTVIdxBuilder(
 
 namespace {
 
+/// Returns the fetcher to return {ID1,TrueID1,FalseID1} from Branches
 class BranchProvider {
   using NodeIDs = MCDCTVIdxBuilder::NodeIDs;
   ArrayRef<const CounterMappingRegion *> Branches;
@@ -368,7 +376,7 @@ class MCDCRecordProcessor : MCDCTVIdxBuilder {
   MCDCRecord::TestVectors ExecVectors;
 
 #ifndef NDEBUG
-  DenseSet<unsigned> TVIDs;
+  DenseSet<unsigned> TVIdxs;
 #endif
 
 public:
@@ -384,10 +392,7 @@ class MCDCRecordProcessor : MCDCTVIdxBuilder {
 private:
   void recordTestVector(MCDCRecord::TestVector &TV, int TVIdx, unsigned Index,
                         MCDCRecord::CondState Result) {
-#ifndef NDEBUG
-    assert(!TVIDs.contains(TVIdx));
-    TVIDs.insert(TVIdx);
-#endif
+    assert(TVIdxs.insert(TVIdx).second && "Duplicate TVIdx");
 
     if (!Bitmap[BitmapIdx + Index])
       return;
@@ -429,11 +434,12 @@ class MCDCRecordProcessor : MCDCTVIdxBuilder {
   /// vector at the corresponding index was executed during a test run.
   void findExecutedTestVectors() {
     // Walk the binary decision diagram to enumerate all possible test vectors.
-    // We start at the root node (ID == 1) with all values being DontCare.
+    // We start at the root node (ID == 0) with all values being DontCare.
+    // `TVIdx` starts with 0 and is in the traversal.
     // `Index` encodes the bitmask of true values and is initially 0.
     MCDCRecord::TestVector TV(NumConditions, MCDCRecord::MCDC_DontCare);
     buildTestVector(TV, 0, 0, 0);
-    assert(TVIDs.size() == NumTestVectors);
+    assert(TVIdxs.size() == NumTestVectors && "TVIdxs wasn't fulfilled");
   }
 
   // Find an independence pair for each condition:

>From 1f0f3fc963fdd8b4e637a45f362c49c8e907ae4b Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Mon, 12 Feb 2024 18:10:18 +0900
Subject: [PATCH 06/11] Reorganize TVIdxBuilder

* Split out `Indices[ID][Cond]`
* Let `Nodes` debug-only.
* Introduce `Offset`
* Introduce `HardMaxTVs`
---
 .../ProfileData/Coverage/CoverageMapping.h    | 45 ++++++++----
 .../ProfileData/Coverage/CoverageMapping.cpp  | 71 ++++++++++++-------
 2 files changed, 74 insertions(+), 42 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index 7341b41aed63d7..bafb1ce2ce5e0c 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -558,33 +558,48 @@ struct MCDCRecord {
   }
 };
 
-/// Compute Conds[].Idx from Branch-like structure
+/// Compute Indices from Branch-like structure
 class MCDCTVIdxBuilder {
 public:
   struct MCDCNode {
     int InCount = 0; /// Reference count; temporary use
-    int Width;       /// Number of paths (>= 1)
-    struct {
-      int Idx; /// Index in TestVectors bitmap
-      int ID;  /// Final Decision if ID<0, or NextID
-    } Conds[2];
+    int Width;       /// Number of accumulated paths (>= 1)
+    std::array<int, 2> NextIDs;
   };
 
-  SmallVector<MCDCNode> Nodes;
-  unsigned NumTestVectors;
+#ifndef NDEBUG
+  /// This is no longer needed after the assignment.
+  /// It may be used in assert() for reconfirmation.
+  SmallVector<MCDCNode> SavedNodes;
+#endif
 
-public:
-  using NodeIDs = std::tuple<unsigned, // ID1 (ends with 0)
-                             unsigned, // ID1 for False
-                             unsigned  // ID1 for True
-                             >;
+  /// Output: Index for TestVectors bitmap
+  SmallVector<std::array<int, 2>> Indices;
+
+  /// Output: The number of test vectors.
+  /// Error with HardMaxTVs if the number has exploded.
+  int NumTestVectors;
 
-  /// Assign Idx
+  /// Hard limit of test vectors
+  static constexpr auto HardMaxTVs =
+      std::numeric_limits<decltype(NumTestVectors)>::max();
+
+public:
+  /// Inputs: to gather MCDCBranch-like ID to construct the BDD.
+  using NodeIDs =
+      std::tuple<CounterMappingRegion::MCDCConditionID, // ID1 (ends with 0)
+                 CounterMappingRegion::MCDCConditionID, // ID1 for False
+                 CounterMappingRegion::MCDCConditionID  // ID1 for True
+                 >;
+
+  /// Calculate and assign Indices
   /// \param Fetcher Function to fetch NodeIDs.
   ///        returns {size,0,0} with TellSize=ture
   ///        returns {ID1,TrueID1,FalseID1} as the value
   ///        returns {0,0,0} as the terminator
-  MCDCTVIdxBuilder(std::function<NodeIDs(bool TellSize)> Fetcher);
+  /// \param Offset Offset of index to final decisions.
+  MCDCTVIdxBuilder(std::function<NodeIDs(bool TellSize)> Fetcher,
+                   int Offset = 0);
 };
 
 /// A Counter mapping context is used to connect the counters, expressions
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index cafb36c19c27f9..83932b9b6317cf 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -224,10 +224,12 @@ Expected<int64_t> CounterMappingContext::evaluate(const Counter &C) const {
 }
 
 MCDCTVIdxBuilder::MCDCTVIdxBuilder(
-    std::function<NodeIDs(bool TellSize)> Fetcher) {
-  // Build Nodes and set up each InCount
+    std::function<NodeIDs(bool TellSize)> Fetcher, int Offset) {
+  // Construct Nodes and set up each InCount
   int MaxID = -1;
-  Nodes.resize(std::get<0>(Fetcher(true)));
+  auto N = std::get<0>(Fetcher(true));
+  SmallVector<MCDCNode> Nodes(N);
+  Indices.resize(N);
   while (true) {
     auto [ID1, FalseID1, TrueID1] = Fetcher(false);
     if (ID1 == 0)
@@ -235,13 +237,13 @@ MCDCTVIdxBuilder::MCDCTVIdxBuilder(
     int ID = ID1 - 1;
     MaxID = std::max(MaxID, ID);
     auto &Node = Nodes[ID];
-    Node.Conds[0].ID = FalseID1 - 1;
-    Node.Conds[1].ID = TrueID1 - 1;
+    Node.NextIDs[0] = FalseID1 - 1;
+    Node.NextIDs[1] = TrueID1 - 1;
     for (unsigned I = 0; I < 2; ++I) {
 #ifndef NDEBUG
-      Node.Conds[I].Idx = INT_MIN;
+      Indices[ID][I] = INT_MIN;
 #endif
-      int NextID = Node.Conds[I].ID;
+      auto NextID = Node.NextIDs[I];
       if (NextID >= 0)
         ++Nodes[NextID].InCount;
     }
@@ -273,7 +275,7 @@ MCDCTVIdxBuilder::MCDCTVIdxBuilder(
     assert(Node.Width > 0);
 
     for (unsigned I = 0; I < 2; ++I) {
-      int NextID = Node.Conds[I].ID;
+      auto NextID = Node.NextIDs[I];
       assert(NextID != 0 && "NextID should not point to the top");
       if (NextID < 0) {
         // Decision
@@ -285,13 +287,19 @@ MCDCTVIdxBuilder::MCDCTVIdxBuilder(
       // Inter Node
       auto &NextNode = Nodes[NextID];
       assert(NextNode.InCount > 0);
-      assert(Node.Conds[I].Idx == INT_MIN);
 
       // Assign Idx
-      Node.Conds[I].Idx = NextNode.Width;
-      NextNode.Width += Node.Width;
+      assert(Indices[ID][I] == INT_MIN);
+      Indices[ID][I] = NextNode.Width;
+      auto NextWidth = int64_t(NextNode.Width) + Node.Width;
+      if (NextWidth > HardMaxTVs) {
+        NumTestVectors = HardMaxTVs; // Overflow
+        return;
+      }
+      NextNode.Width = NextWidth;
 
       // Ready if all incomings are processed.
+      // Or NextNode.Width hasn't been confirmed yet.
       if (--NextNode.InCount == 0)
         Q.push_back(NextID);
     }
@@ -300,21 +308,28 @@ MCDCTVIdxBuilder::MCDCTVIdxBuilder(
   std::sort(Decisions.begin(), Decisions.end());
 
   // Assign TestVector Indices in Decision Nodes
-  unsigned CurIdx = 0;
+  int64_t CurIdx = 0;
   for (auto [NegWidth, Ord, ID, C] : Decisions) {
     int Width = -NegWidth;
     assert(Nodes[ID].Width == Width);
-    assert(Nodes[ID].Conds[C].Idx == INT_MIN);
-    assert(Nodes[ID].Conds[C].ID < 0);
-    Nodes[ID].Conds[C].Idx = CurIdx;
+    assert(Nodes[ID].NextIDs[C] < 0);
+    assert(Indices[ID][C] == INT_MIN);
+    Indices[ID][C] = Offset + CurIdx;
     CurIdx += Width;
+    if (CurIdx > HardMaxTVs) {
+      NumTestVectors = HardMaxTVs; // Overflow
+      return;
+    }
   }
+
+  assert(CurIdx < HardMaxTVs);
   NumTestVectors = CurIdx;
 
 #ifndef NDEBUG
-  for (const auto &Node : Nodes)
-    for (const auto &Cond : Node.Conds)
-      assert(Cond.Idx != INT_MIN);
+  for (const auto &Idxs : Indices)
+    for (auto Idx : Idxs)
+      assert(Idx != INT_MIN);
+  SavedNodes = std::move(Nodes);
 #endif
 }
 
@@ -363,7 +378,7 @@ class MCDCRecordProcessor : MCDCTVIdxBuilder {
   unsigned BitmapIdx;
 
   /// Mapping of a condition ID to its corresponding branch region.
-  llvm::DenseMap<unsigned, const CounterMappingRegion *> Map;
+  llvm::DenseMap<int, std::array<int, 2>> NextIDsMap;
 
   /// Vector used to track whether a condition is constant folded.
   MCDCRecord::BoolVector Folded;
@@ -410,19 +425,19 @@ class MCDCRecordProcessor : MCDCTVIdxBuilder {
   // the truth table.
   void buildTestVector(MCDCRecord::TestVector &TV, int ID, int TVIdx,
                        unsigned Index) {
-    const auto &Node = Nodes[ID];
+    const auto &NextIDs = NextIDsMap[ID];
 
     for (unsigned I = 0; I < 2; ++I) {
       auto MCDCCond = (I ? MCDCRecord::MCDC_True : MCDCRecord::MCDC_False);
-      const auto &Cond = Node.Conds[I];
-      auto NextID = Cond.ID;
+      auto NextID = NextIDs[I];
+      assert(NextID == SavedNodes[ID].NextIDs[I]);
       Index |= I << ID;
       TV[ID] = MCDCCond;
       if (NextID >= 0) {
-        buildTestVector(TV, NextID, TVIdx + Cond.Idx, Index);
+        buildTestVector(TV, NextID, TVIdx + Indices[ID][I], Index);
       } else {
-        assert(TVIdx < Node.Width);
-        recordTestVector(TV, Cond.Idx + TVIdx, Index, MCDCCond);
+        assert(TVIdx < SavedNodes[ID].Width);
+        recordTestVector(TV, Indices[ID][I] + TVIdx, Index, MCDCCond);
       }
     }
 
@@ -439,7 +454,8 @@ class MCDCRecordProcessor : MCDCTVIdxBuilder {
     // `Index` encodes the bitmask of true values and is initially 0.
     MCDCRecord::TestVector TV(NumConditions, MCDCRecord::MCDC_DontCare);
     buildTestVector(TV, 0, 0, 0);
-    assert(TVIdxs.size() == NumTestVectors && "TVIdxs wasn't fulfilled");
+    assert(TVIdxs.size() == unsigned(NumTestVectors) &&
+           "TVIdxs wasn't fulfilled");
   }
 
   // Find an independence pair for each condition:
@@ -499,7 +515,8 @@ class MCDCRecordProcessor : MCDCTVIdxBuilder {
     // - Record whether the condition is constant folded so that we exclude it
     //   from being measured.
     for (const auto *B : Branches) {
-      Map[B->MCDCParams.ID] = B;
+      NextIDsMap[B->MCDCParams.ID - 1] = {int(B->MCDCParams.FalseID) - 1,
+                                          int(B->MCDCParams.TrueID) - 1};
       PosToID[I] = B->MCDCParams.ID - 1;
       CondLoc[I] = B->startLoc();
       Folded[I++] = (B->Count.isZero() && B->FalseCount.isZero());

>From e3de6478e296c7dca9244d70fd8f5063232c32ef Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Thu, 15 Feb 2024 20:19:53 +0900
Subject: [PATCH 07/11] [CoverageMapping] Refactor `mcdc::TVIdxBuilder`

* Sink `TVIdxBuilder` into `mcdc::`.
* The ctor accepts `SmallVector<ConditionIDs>` indexed by `ID`.
* `class NextIDsBuilder` provides `NextIDs` as`SmallVector<ConditionIDs>`,
  for `TVIdxBuilder` to use it before `MCDCRecordProcessor()`.
  It was `BranchParamsMap` or `Map` as `DenseMap<Branch>`.
* `NodeIDs` and `Fetcher` function are deprecated.
---
 .../ProfileData/Coverage/CoverageMapping.h    | 22 ++----
 .../ProfileData/Coverage/CoverageMapping.cpp  | 72 ++++++++-----------
 2 files changed, 36 insertions(+), 58 deletions(-)

diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index cb3b260973e9f1..4ac1d88f9206d4 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -551,13 +551,14 @@ struct MCDCRecord {
   }
 };
 
+namespace mcdc {
 /// Compute Indices from Branch-like structure
-class MCDCTVIdxBuilder {
+class TVIdxBuilder {
 public:
   struct MCDCNode {
     int InCount = 0; /// Reference count; temporary use
     int Width;       /// Number of accumulated paths (>= 1)
-    std::array<int, 2> NextIDs;
+    ConditionIDs NextIDs;
   };
 
 #ifndef NDEBUG
@@ -566,7 +567,7 @@ class MCDCTVIdxBuilder {
   SmallVector<MCDCNode> SavedNodes;
 #endif
 
-  /// Output: Index for TestVectors bitmap
+  /// Output: Index for TestVectors bitmap (These are not CondIDs)
   SmallVector<std::array<int, 2>> Indices;
 
   /// Output: The number of test vectors.
@@ -578,21 +579,12 @@ class MCDCTVIdxBuilder {
       std::numeric_limits<decltype(NumTestVectors)>::max();
 
 public:
-  /// Inputs: to gather MCDCBranch-like ID to construct the BDD.
-  using NodeIDs = std::tuple<mcdc::ConditionID, // ID (ends with -1)
-                             mcdc::ConditionID, // ID for False
-                             mcdc::ConditionID  // ID for True
-                             >;
-
   /// Calculate and assign Indices
-  /// \param Fetcher Function to fetch NodeIDs.
-  ///        returns {size,0,0} with TellSize=ture
-  ///        returns {ID1,TrueID1,FalseID1} as the value
-  ///        returns {0,0,0} as the terminator
+  /// \param NextIDs The list of {FalseID, TrueID} indexed by ID
   /// \param Offset Offset of index to final decisions.
-  MCDCTVIdxBuilder(std::function<NodeIDs(bool TellSize)> Fetcher,
-                   int Offset = 0);
+  TVIdxBuilder(const SmallVectorImpl<ConditionIDs> &NextIDs, int Offset = 0);
 };
+} // namespace mcdc
 
 /// A Counter mapping context is used to connect the counters, expressions
 /// and the obtained counter values.
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index 6896603debf7f2..8e6205c4b61667 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -223,34 +223,24 @@ Expected<int64_t> CounterMappingContext::evaluate(const Counter &C) const {
   return LastPoppedValue;
 }
 
-MCDCTVIdxBuilder::MCDCTVIdxBuilder(
-    std::function<NodeIDs(bool TellSize)> Fetcher, int Offset) {
+mcdc::TVIdxBuilder::TVIdxBuilder(const SmallVectorImpl<ConditionIDs> &NextIDs,
+                                 int Offset)
+    : Indices(NextIDs.size()) {
   // Construct Nodes and set up each InCount
-  mcdc::ConditionID MaxID = -1;
-  auto N = std::get<0>(Fetcher(true));
+  auto N = NextIDs.size();
   SmallVector<MCDCNode> Nodes(N);
-  Indices.resize(N);
-  while (true) {
-    auto [ID, FalseID, TrueID] = Fetcher(false);
-    if (ID < 0)
-      break;
-    MaxID = std::max(MaxID, ID);
-    auto &Node = Nodes[ID];
-    Node.NextIDs[0] = FalseID;
-    Node.NextIDs[1] = TrueID;
-    for (unsigned I = 0; I < 2; ++I) {
+  for (unsigned ID = 0; ID < N; ++ID) {
+    for (unsigned C = 0; C < 2; ++C) {
 #ifndef NDEBUG
-      Indices[ID][I] = INT_MIN;
+      Indices[ID][C] = INT_MIN;
 #endif
-      auto NextID = Node.NextIDs[I];
+      auto NextID = NextIDs[ID][C];
+      Nodes[ID].NextIDs[C] = NextID;
       if (NextID >= 0)
         ++Nodes[NextID].InCount;
     }
   }
 
-  if (MaxID < 0)
-    return;
-
   // Sort key ordered by <-Width, Ord>
   SmallVector<std::tuple<int,      /// -Width
                          unsigned, /// Ord
@@ -334,29 +324,29 @@ MCDCTVIdxBuilder::MCDCTVIdxBuilder(
 
 namespace {
 
-/// Returns the fetcher to return {ID1,TrueID1,FalseID1} from Branches
-class BranchProvider {
-  using NodeIDs = MCDCTVIdxBuilder::NodeIDs;
-  ArrayRef<const CounterMappingRegion *> Branches;
-  unsigned BranchIdx = 0;
+/// Construct this->NextIDs with Branches for TVIdxBuilder to use it
+/// before MCDCRecordProcessor().
+class NextIDsBuilder {
+protected:
+  SmallVector<mcdc::ConditionIDs> NextIDs;
 
 public:
-  BranchProvider(ArrayRef<const CounterMappingRegion *> Branches)
-      : Branches(Branches) {}
-
-  std::function<NodeIDs(bool)> getFetcher() {
-    return [this](bool TellSize) {
-      if (TellSize)
-        return NodeIDs(Branches.size(), 0, 0);
-      if (BranchIdx >= Branches.size())
-        return NodeIDs(-1, 0, 0);
-      const auto &B = Branches[BranchIdx++]->getBranchParams();
-      return NodeIDs(B.ID, B.Conds[false], B.Conds[true]);
-    };
+  NextIDsBuilder(const ArrayRef<const CounterMappingRegion *> Branches)
+      : NextIDs(Branches.size()) {
+#ifndef NDEBUG
+    DenseSet<mcdc::ConditionID> SeenIDs;
+#endif
+    for (const auto *Branch : Branches) {
+      const auto &BranchParams = Branch->getBranchParams();
+      assert(BranchParams.ID >= 0 && "CondID isn't set");
+      assert(SeenIDs.insert(BranchParams.ID).second && "Duplicate CondID");
+      NextIDs[BranchParams.ID] = BranchParams.Conds;
+    }
+    assert(SeenIDs.size() == Branches.size());
   }
 };
 
-class MCDCRecordProcessor : MCDCTVIdxBuilder {
+class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
   /// A bitmap representing the executed test vectors for a boolean expression.
   /// Each index of the bitmap corresponds to a possible test vector. An index
   /// with a bit value of '1' indicates that the corresponding Test Vector
@@ -376,9 +366,6 @@ class MCDCRecordProcessor : MCDCTVIdxBuilder {
 
   unsigned BitmapIdx;
 
-  /// Mapping of a condition ID to its corresponding branch params.
-  llvm::DenseMap<mcdc::ConditionID, mcdc::ConditionIDs> NextIDsMap;
-
   /// Vector used to track whether a condition is constant folded.
   MCDCRecord::BoolVector Folded;
 
@@ -397,7 +384,7 @@ class MCDCRecordProcessor : MCDCTVIdxBuilder {
   MCDCRecordProcessor(const BitVector &Bitmap,
                       const CounterMappingRegion &Region,
                       ArrayRef<const CounterMappingRegion *> Branches)
-      : MCDCTVIdxBuilder(BranchProvider(Branches).getFetcher()), Bitmap(Bitmap),
+      : NextIDsBuilder(Branches), TVIdxBuilder(this->NextIDs), Bitmap(Bitmap),
         Region(Region), DecisionParams(Region.getDecisionParams()),
         Branches(Branches), NumConditions(DecisionParams.NumConditions),
         BitmapIdx(DecisionParams.BitmapIdx * CHAR_BIT),
@@ -416,7 +403,7 @@ class MCDCRecordProcessor : MCDCTVIdxBuilder {
       static_assert(MCDCRecord::MCDC_True == 1);
       Index |= MCDCCond << ID;
       TV[ID] = MCDCCond;
-      auto NextID = NextIDsMap[ID][MCDCCond];
+      auto NextID = NextIDs[ID][MCDCCond];
       auto NextTVIdx = TVIdx + Indices[ID][MCDCCond];
       assert(NextID == SavedNodes[ID].NextIDs[MCDCCond]);
       if (NextID >= 0) {
@@ -513,7 +500,6 @@ class MCDCRecordProcessor : MCDCTVIdxBuilder {
     //   from being measured.
     for (const auto *B : Branches) {
       const auto &BranchParams = B->getBranchParams();
-      NextIDsMap[BranchParams.ID] = BranchParams.Conds;
       PosToID[I] = BranchParams.ID;
       CondLoc[I] = B->startLoc();
       Folded[I++] = (B->Count.isZero() && B->FalseCount.isZero());

>From 753d0ad692c56b81d471d4c8282bb41432fcd815 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Thu, 15 Feb 2024 22:18:19 +0900
Subject: [PATCH 08/11] remove <functional>

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

diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index 4ac1d88f9206d4..c34c6f70de6b3b 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -33,7 +33,6 @@
 #include "llvm/Support/raw_ostream.h"
 #include <cassert>
 #include <cstdint>
-#include <functional>
 #include <iterator>
 #include <memory>
 #include <sstream>

>From 17cbac7f99d2b800dc008d3413886495d03531d0 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Wed, 21 Feb 2024 09:02:02 +0900
Subject: [PATCH 09/11] Update comments.

---
 .../llvm/ProfileData/Coverage/CoverageMapping.h  | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index c34c6f70de6b3b..b39f262c3d976b 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -551,7 +551,20 @@ struct MCDCRecord {
 };
 
 namespace mcdc {
-/// Compute Indices from Branch-like structure
+/// Compute TestVector Indices "TVIdx" from the Conds graph.
+///
+/// Clang CodeGen handles the bitmap index based on TVIdx.
+/// llvm-cov reconstructs conditions from TVIdx.
+///
+/// For each leaf "The final decision",
+/// - TVIdx should be unique.
+/// - TVIdx has the Width.
+///   - The width represents the number of possible paths.
+///   - The minimum width is 1 "deterministic".
+/// - The order of leaves are sorted by Width DESC. It expects
+///   latter TVIdx(s) (with Width=1) could be pruned and altered to
+///   other simple branch conditions.
+///
 class TVIdxBuilder {
 public:
   struct MCDCNode {
@@ -580,6 +593,7 @@ class TVIdxBuilder {
 public:
   /// Calculate and assign Indices
   /// \param NextIDs The list of {FalseID, TrueID} indexed by ID
+  ///        The first element [0] should be the root node.
   /// \param Offset Offset of index to final decisions.
   TVIdxBuilder(const SmallVectorImpl<ConditionIDs> &NextIDs, int Offset = 0);
 };

>From 1a4ffa7f2dc2b6ed1af1ef128865c29bf9cfc752 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Wed, 21 Feb 2024 09:02:02 +0900
Subject: [PATCH 10/11] Add unittest

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

diff --git a/llvm/unittests/ProfileData/CoverageMappingTest.cpp b/llvm/unittests/ProfileData/CoverageMappingTest.cpp
index 425b3d10510af7..c5b7c26bef9a7e 100644
--- a/llvm/unittests/ProfileData/CoverageMappingTest.cpp
+++ b/llvm/unittests/ProfileData/CoverageMappingTest.cpp
@@ -16,6 +16,7 @@
 #include "llvm/Testing/Support/SupportHelpers.h"
 #include "gtest/gtest.h"
 
+#include <map>
 #include <ostream>
 #include <utility>
 
@@ -1074,4 +1075,59 @@ TEST(CoverageMappingTest, filename_compilation_dir) {
   }
 }
 
+TEST(CoverageMappingTest, TVIdxBuilder) {
+  // ((n0 && n3) || (n2 && n4) || (n1 && n5))
+  static const std::array<mcdc::ConditionIDs, 6> Branches = {{
+      {2, 3},
+      {-1, 5},
+      {1, 4},
+      {2, -1},
+      {1, -1},
+      {-1, -1},
+  }};
+  int Offset = 1000;
+  auto TheBuilder = mcdc::TVIdxBuilder(
+      SmallVector<mcdc::ConditionIDs>(ArrayRef(Branches)), Offset);
+  ASSERT_TRUE(TheBuilder.NumTestVectors < TheBuilder.HardMaxTVs);
+  ASSERT_EQ(TheBuilder.Indices.size(), 6u);
+  ASSERT_EQ(TheBuilder.NumTestVectors, 15);
+
+  std::map<int, int> Decisions;
+  for (unsigned I = 0; I < TheBuilder.Indices.size(); ++I) {
+    struct Rec {
+      int Width;
+      std::array<int, 2> Indices;
+    };
+    static const std::array<Rec, 6> IndicesRefs = {{
+        {1, {0, 0}},
+        {4, {1000, 0}},
+        {2, {0, 0}},
+        {1, {1, 1014}},
+        {2, {2, 1012}},
+        {4, {1004, 1008}},
+    }};
+    ASSERT_EQ(TheBuilder.Indices[I], IndicesRefs[I].Indices);
+
+#ifndef NDEBUG
+    const auto &Node = TheBuilder.SavedNodes[I];
+    ASSERT_EQ(Node.Width, IndicesRefs[I].Width);
+    for (int C = 0; C < 2; ++C) {
+      auto Index = TheBuilder.Indices[I][C];
+      if (Node.NextIDs[C] < 0)
+        ASSERT_TRUE(Decisions.insert({Index, Node.Width}).second);
+    }
+#endif
+  }
+
+#ifndef NDEBUG
+  int NextIdx = Offset;
+  for (const auto [Index, Width] : Decisions) {
+    ASSERT_EQ(Index, NextIdx);
+    NextIdx += Width;
+  }
+  // The sum of Width(s) is NumTVs.
+  ASSERT_EQ(NextIdx, Offset + TheBuilder.NumTestVectors);
+#endif
+}
+
 } // end anonymous namespace

>From b5ecfcc22cffdd560dc5b6a050889b6c6deacbdb Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Fri, 16 Feb 2024 00:09:41 +0900
Subject: [PATCH 11/11] [MC/DC][Coverage] Loosen the limit of NumConds from 6

---
 clang/lib/CodeGen/CodeGenPGO.cpp              |  61 +++++-----
 clang/lib/CodeGen/CoverageMappingGen.cpp      | 115 +++++++++++++++++-
 clang/lib/CodeGen/MCDCState.h                 |  18 ++-
 .../CoverageMapping/branch-constfolded.cpp    |  34 +++---
 clang/test/CoverageMapping/logical.cpp        |   8 +-
 clang/test/CoverageMapping/mcdc-class.cpp     |   4 +-
 .../CoverageMapping/mcdc-error-conditions.cpp |  86 ++++++++++++-
 .../mcdc-logical-scalar-ids.cpp               |  30 ++---
 .../mcdc-logical-stmt-ids-all.cpp             |  32 ++---
 .../CoverageMapping/mcdc-logical-stmt-ids.cpp |  30 ++---
 clang/test/Profile/c-mcdc-logicalop-ternary.c |   6 +-
 .../ProfileData/Coverage/CoverageMapping.cpp  |  32 ++---
 .../llvm-cov/Inputs/mcdc-const-folding.o      | Bin 34504 -> 34528 bytes
 .../Inputs/mcdc-const-folding.proftext        |  36 +++---
 llvm/test/tools/llvm-cov/Inputs/mcdc-const.o  | Bin 5112 -> 5112 bytes
 .../tools/llvm-cov/Inputs/mcdc-const.proftext |   6 +-
 .../test/tools/llvm-cov/Inputs/mcdc-general.o | Bin 6200 -> 6232 bytes
 .../llvm-cov/Inputs/mcdc-general.proftext     |  11 +-
 llvm/test/tools/llvm-cov/Inputs/mcdc-macro.o  | Bin 6424 -> 6480 bytes
 .../tools/llvm-cov/Inputs/mcdc-macro.proftext |  15 +--
 llvm/test/tools/llvm-cov/Inputs/mcdc-maxbs.o  | Bin 4632 -> 4112 bytes
 llvm/test/tools/llvm-cov/mcdc-maxbs.test      |   2 +-
 .../ProfileData/CoverageMappingTest.cpp       |   2 +-
 23 files changed, 348 insertions(+), 180 deletions(-)

diff --git a/clang/lib/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp
index 48c5e68a3b7ba4..b004bf45fa75d7 100644
--- a/clang/lib/CodeGen/CodeGenPGO.cpp
+++ b/clang/lib/CodeGen/CodeGenPGO.cpp
@@ -163,8 +163,7 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
   PGOHash Hash;
   /// The map of statements to counters.
   llvm::DenseMap<const Stmt *, unsigned> &CounterMap;
-  /// The next bitmap byte index to assign.
-  unsigned NextMCDCBitmapIdx;
+  /// The state of MC/DC Coverage in this function.
   MCDC::State &MCDCState;
   /// Maximum number of supported MC/DC conditions in a boolean expression.
   unsigned MCDCMaxCond;
@@ -178,7 +177,7 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
                     MCDC::State &MCDCState, unsigned MCDCMaxCond,
                     DiagnosticsEngine &Diag)
       : NextCounter(0), Hash(HashVersion), CounterMap(CounterMap),
-        NextMCDCBitmapIdx(0), MCDCState(MCDCState), MCDCMaxCond(MCDCMaxCond),
+        MCDCState(MCDCState), MCDCMaxCond(MCDCMaxCond),
         ProfileVersion(ProfileVersion), Diag(Diag) {}
 
   // Blocks and lambdas are handled as separate functions, so we need not
@@ -306,11 +305,8 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
             return false;
           }
 
-          // Otherwise, allocate the number of bytes required for the bitmap
-          // based on the number of conditions. Must be at least 1-byte long.
-          MCDCState.BitmapMap[BinOp] = NextMCDCBitmapIdx;
-          unsigned SizeInBits = std::max<unsigned>(1L << NumCond, CHAR_BIT);
-          NextMCDCBitmapIdx += SizeInBits / CHAR_BIT;
+          // Otherwise, allocate the Decision.
+          MCDCState.BitmapMap[BinOp].BitmapIdx = 0;
         }
         return true;
       }
@@ -983,7 +979,7 @@ void CodeGenPGO::mapRegionCounters(const Decl *D) {
   // for most embedded applications. Setting a maximum value prevents the
   // bitmap footprint from growing too large without the user's knowledge. In
   // the future, this value could be adjusted with a command-line option.
-  unsigned MCDCMaxConditions = (CGM.getCodeGenOpts().MCDCCoverage) ? 6 : 0;
+  unsigned MCDCMaxConditions = (CGM.getCodeGenOpts().MCDCCoverage) ? 32767 : 0;
 
   RegionCounterMap.reset(new llvm::DenseMap<const Stmt *, unsigned>);
   RegionMCDCState.reset(new MCDC::State);
@@ -999,7 +995,6 @@ void CodeGenPGO::mapRegionCounters(const Decl *D) {
     Walker.TraverseDecl(const_cast<CapturedDecl *>(CD));
   assert(Walker.NextCounter > 0 && "no entry counter mapped for decl");
   NumRegionCounters = Walker.NextCounter;
-  RegionMCDCState->BitmapBytes = Walker.NextMCDCBitmapIdx;
   FunctionHash = Walker.Hash.finalize();
 }
 
@@ -1124,9 +1119,11 @@ void CodeGenPGO::emitMCDCParameters(CGBuilderTy &Builder) {
   // Emit intrinsic representing MCDC bitmap parameters at function entry.
   // This is used by the instrumentation pass, but it isn't actually lowered to
   // anything.
-  llvm::Value *Args[3] = {llvm::ConstantExpr::getBitCast(FuncNameVar, I8PtrTy),
-                          Builder.getInt64(FunctionHash),
-                          Builder.getInt32(RegionMCDCState->BitmapBytes)};
+  llvm::Value *Args[3] = {
+      llvm::ConstantExpr::getBitCast(FuncNameVar, I8PtrTy),
+      Builder.getInt64(FunctionHash),
+      Builder.getInt32(llvm::alignTo(RegionMCDCState->BitmapBits, CHAR_BIT) /
+                       CHAR_BIT)};
   Builder.CreateCall(
       CGM.getIntrinsic(llvm::Intrinsic::instrprof_mcdc_parameters), Args);
 }
@@ -1139,12 +1136,9 @@ void CodeGenPGO::emitMCDCTestVectorBitmapUpdate(CGBuilderTy &Builder,
 
   S = S->IgnoreParens();
 
-  auto ExprMCDCBitmapMapIterator = RegionMCDCState->BitmapMap.find(S);
-  if (ExprMCDCBitmapMapIterator == RegionMCDCState->BitmapMap.end())
+  if (!RegionMCDCState->BitmapMap.contains(S))
     return;
 
-  // Extract the ID of the global bitmap associated with this expression.
-  unsigned MCDCTestVectorBitmapID = ExprMCDCBitmapMapIterator->second;
   auto *I8PtrTy = llvm::PointerType::getUnqual(CGM.getLLVMContext());
 
   // Emit intrinsic responsible for updating the global bitmap corresponding to
@@ -1154,9 +1148,8 @@ void CodeGenPGO::emitMCDCTestVectorBitmapUpdate(CGBuilderTy &Builder,
   // index represents an executed test vector.
   llvm::Value *Args[5] = {llvm::ConstantExpr::getBitCast(FuncNameVar, I8PtrTy),
                           Builder.getInt64(FunctionHash),
-                          Builder.getInt32(RegionMCDCState->BitmapBytes),
-                          Builder.getInt32(MCDCTestVectorBitmapID),
-                          MCDCCondBitmapAddr.getPointer()};
+                          Builder.getInt32(RegionMCDCState->BitmapBits),
+                          Builder.getInt32(0), MCDCCondBitmapAddr.getPointer()};
   Builder.CreateCall(
       CGM.getIntrinsic(llvm::Intrinsic::instrprof_mcdc_tvbitmap_update), Args);
 }
@@ -1195,21 +1188,23 @@ void CodeGenPGO::emitMCDCCondBitmapUpdate(CGBuilderTy &Builder, const Expr *S,
     return;
 
   // Extract the ID of the condition we are setting in the bitmap.
-  auto CondID = ExprMCDCConditionIDMapIterator->second;
-  assert(CondID >= 0 && "Condition has no ID!");
+  const auto &Branch = ExprMCDCConditionIDMapIterator->second;
+  assert(Branch.ID >= 0 && "Condition has no ID!");
 
-  auto *I8PtrTy = llvm::PointerType::getUnqual(CGM.getLLVMContext());
+  // Cancel the emission if the Decision is erased after the allocation.
+  const auto DecisionIter =
+      RegionMCDCState->BitmapMap.find(Branch.DecisionStmt);
+  if (DecisionIter == RegionMCDCState->BitmapMap.end())
+    return;
 
-  // Emit intrinsic that updates a dedicated temporary value on the stack after
-  // a condition is evaluated. After the set of conditions has been updated,
-  // the resulting value is used to update the boolean expression's bitmap.
-  llvm::Value *Args[5] = {llvm::ConstantExpr::getBitCast(FuncNameVar, I8PtrTy),
-                          Builder.getInt64(FunctionHash),
-                          Builder.getInt32(CondID),
-                          MCDCCondBitmapAddr.getPointer(), Val};
-  Builder.CreateCall(
-      CGM.getIntrinsic(llvm::Intrinsic::instrprof_mcdc_condbitmap_update),
-      Args);
+  const auto &TVIdxs = DecisionIter->second.Indices[Branch.ID];
+
+  auto *CurTV = Builder.CreateLoad(MCDCCondBitmapAddr,
+                                   "mcdc." + Twine(Branch.ID + 1) + ".cur");
+  auto *NewTV = Builder.CreateAdd(CurTV, Builder.getInt32(TVIdxs[true]));
+  NewTV = Builder.CreateSelect(
+      Val, NewTV, Builder.CreateAdd(CurTV, Builder.getInt32(TVIdxs[false])));
+  Builder.CreateStore(NewTV, MCDCCondBitmapAddr);
 }
 
 void CodeGenPGO::setValueProfilingFlag(llvm::Module &M) {
diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index c10d85ea89ee61..ec51023a2d2051 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -182,6 +182,16 @@ class SourceMappingRegion {
 
   bool isBranch() const { return FalseCount.has_value(); }
 
+  bool isMCDCBranch() const {
+    const auto *BranchParams = std::get_if<mcdc::BranchParameters>(&MCDCParams);
+    assert(!BranchParams || BranchParams->ID >= 0);
+    return BranchParams;
+  }
+
+  const auto &getMCDCBranchParams() const {
+    return mcdc::getParams<const mcdc::BranchParameters>(MCDCParams);
+  }
+
   bool isMCDCDecision() const {
     const auto *DecisionParams =
         std::get_if<mcdc::DecisionParameters>(&MCDCParams);
@@ -194,6 +204,8 @@ class SourceMappingRegion {
   }
 
   const mcdc::Parameters &getMCDCParams() const { return MCDCParams; }
+
+  void resetMCDCParams() { MCDCParams = mcdc::Parameters(); }
 };
 
 /// Spelling locations for the start and end of a source region.
@@ -684,7 +696,9 @@ struct MCDCCoverageBuilder {
 
   llvm::SmallVector<mcdc::ConditionIDs> DecisionStack;
   MCDC::State &MCDCState;
-  llvm::DenseMap<const Stmt *, mcdc::ConditionID> &CondIDs;
+  llvm::DenseMap<const Stmt *, MCDC::State::Branch> &CondIDs;
+  const Stmt *DecisionStmt = nullptr;
+  llvm::DenseMap<mcdc::ConditionID, mcdc::ConditionIDs> cache;
   mcdc::ConditionID NextID = 0;
   bool NotMapped = false;
 
@@ -714,7 +728,7 @@ struct MCDCCoverageBuilder {
 
   /// Set the given condition's ID.
   void setCondID(const Expr *Cond, mcdc::ConditionID ID) {
-    CondIDs[CodeGenFunction::stripCond(Cond)] = ID;
+    CondIDs[CodeGenFunction::stripCond(Cond)] = {ID, DecisionStmt};
   }
 
   /// Return the ID of a given condition.
@@ -723,7 +737,15 @@ struct MCDCCoverageBuilder {
     if (I == CondIDs.end())
       return -1;
     else
-      return I->second;
+      return I->second.ID;
+  }
+
+  void ccc(const Expr *CondExpr, mcdc::ConditionIDs IDs) {
+    auto ID = getCondID(CondExpr);
+    if (ID < 0)
+      return;
+    if (!cache.contains(ID))
+      cache[ID] = IDs;
   }
 
   /// Return the LHS Decision ([0,0] if not set).
@@ -745,6 +767,12 @@ struct MCDCCoverageBuilder {
     if (NotMapped)
       return;
 
+    if (NextID == 0) {
+      cache.clear();
+      DecisionStmt = E;
+      assert(MCDCState.BitmapMap.contains(E));
+    }
+
     const mcdc::ConditionIDs &ParentDecision = DecisionStack.back();
 
     // If the operator itself has an assigned ID, this means it represents a
@@ -794,9 +822,33 @@ struct MCDCCoverageBuilder {
     // Set number of conditions and reset.
     unsigned TotalConds = NextID;
 
+    llvm::SmallVector<mcdc::ConditionIDs> R(cache.size());
+    for (auto [ID, Conds] : cache)
+      R[ID] = Conds;
+    mcdc::TVIdxBuilder xxx(R, MCDCState.BitmapBits);
+    auto NumTVs = xxx.NumTestVectors;
+    assert(MCDCState.BitmapMap.contains(E));
+    auto MaxTVs = mcdc::TVIdxBuilder::HardMaxTVs;
+    if (NumTVs == MaxTVs) {
+      auto &Diag = CGM.getDiags();
+      unsigned DiagID =
+          Diag.getCustomDiagID(DiagnosticsEngine::Warning,
+                               "unsupported MC/DC boolean expression; "
+                               "number of test vectors (%0) exceeds max (%1). "
+                               "Expression will not be covered");
+      Diag.Report(E->getBeginLoc(), DiagID) << NumTVs << MaxTVs;
+
+      MCDCState.BitmapMap[E].BitmapIdx = 0; // Mark to be erased
+    } else {
+      // Last pos
+      MCDCState.BitmapMap[E] = {MCDCState.BitmapBits += NumTVs,
+                                std::move(xxx.Indices)};
+    }
+
     // Reset ID back to beginning.
     NextID = 0;
 
+    // Return the number even if the Decision will be erased.
     return TotalConds;
   }
 };
@@ -853,7 +905,9 @@ struct CounterCoverageMappingBuilder
     return Counter::getCounter(CounterMap[S]);
   }
 
-  unsigned getRegionBitmap(const Stmt *S) { return MCDCState.BitmapMap[S]; }
+  auto getRegionBitmap(const Stmt *S) {
+    return MCDCState.BitmapMap[S].BitmapIdx;
+  }
 
   /// Push a region onto the stack.
   ///
@@ -1959,9 +2013,44 @@ struct CounterCoverageMappingBuilder
                        subtractCounters(ParentCount, TrueCount));
   }
 
+  void RewindDecision(unsigned Since) {
+#ifndef NDEBUG
+    llvm::DenseSet<mcdc::ConditionID> SeenIDs;
+#endif
+    unsigned NConds = 0;
+
+    assert(Since <= SourceRegions.size());
+    auto I = SourceRegions.begin() + Since;
+    while (I != SourceRegions.end()) {
+      if (I->isMCDCDecision()) {
+        assert(I->getMCDCDecisionParams().BitmapIdx == 0 &&
+               "It should be valid");
+        assert(NConds == 0 && "Duplicate MCDCDecision");
+        NConds = I->getMCDCDecisionParams().NumConditions;
+        assert(NConds > 0 && "Malformed MCDCDecision");
+        I = SourceRegions.erase(I);
+        continue;
+      }
+
+      if (I->isMCDCBranch()) {
+        assert(SeenIDs.insert(I->getMCDCBranchParams().ID).second &&
+               "Duplicate CondID");
+        I->resetMCDCParams();
+      }
+
+      ++I;
+    }
+
+    assert(NConds > 0 && "MCDCDecision wasn't found");
+    assert(SeenIDs.size() == NConds && "Unexpected number of MCDCBranch(es)");
+    (void)NConds;
+  }
+
   void VisitBinLAnd(const BinaryOperator *E) {
     bool IsRootNode = MCDCBuilder.isIdle();
 
+    unsigned SourceRegionsSince = SourceRegions.size();
+
     // Keep track of Binary Operator and assign MCDC condition IDs.
     MCDCBuilder.pushAndAssignIDs(E);
 
@@ -1979,6 +2068,9 @@ struct CounterCoverageMappingBuilder
     // Track RHS True/False Decision.
     const auto DecisionRHS = MCDCBuilder.back();
 
+    MCDCBuilder.ccc(E->getLHS(), DecisionLHS);
+    MCDCBuilder.ccc(E->getRHS(), DecisionRHS);
+
     // Create MCDC Decision Region if at top-level (root).
     unsigned NumConds = 0;
     if (IsRootNode && (NumConds = MCDCBuilder.getTotalConditionsAndReset(E)))
@@ -2000,6 +2092,11 @@ struct CounterCoverageMappingBuilder
     // Create Branch Region around RHS condition.
     createBranchRegion(E->getRHS(), RHSTrueCnt,
                        subtractCounters(RHSExecCnt, RHSTrueCnt), DecisionRHS);
+
+    if (IsRootNode && NumConds > 0 && getRegionBitmap(E) == 0) {
+      RewindDecision(SourceRegionsSince);
+      MCDCState.BitmapMap.erase(E);
+    }
   }
 
   // Determine whether the right side of OR operation need to be visited.
@@ -2015,6 +2112,8 @@ struct CounterCoverageMappingBuilder
   void VisitBinLOr(const BinaryOperator *E) {
     bool IsRootNode = MCDCBuilder.isIdle();
 
+    unsigned SourceRegionsSince = SourceRegions.size();
+
     // Keep track of Binary Operator and assign MCDC condition IDs.
     MCDCBuilder.pushAndAssignIDs(E);
 
@@ -2032,6 +2131,9 @@ struct CounterCoverageMappingBuilder
     // Track RHS True/False Decision.
     const auto DecisionRHS = MCDCBuilder.back();
 
+    MCDCBuilder.ccc(E->getLHS(), DecisionLHS);
+    MCDCBuilder.ccc(E->getRHS(), DecisionRHS);
+
     // Create MCDC Decision Region if at top-level (root).
     unsigned NumConds = 0;
     if (IsRootNode && (NumConds = MCDCBuilder.getTotalConditionsAndReset(E)))
@@ -2057,6 +2159,11 @@ struct CounterCoverageMappingBuilder
     // Create Branch Region around RHS condition.
     createBranchRegion(E->getRHS(), subtractCounters(RHSExecCnt, RHSFalseCnt),
                        RHSFalseCnt, DecisionRHS);
+
+    if (IsRootNode && NumConds > 0 && getRegionBitmap(E) == 0) {
+      RewindDecision(SourceRegionsSince);
+      MCDCState.BitmapMap.erase(E);
+    }
   }
 
   void VisitLambdaExpr(const LambdaExpr *LE) {
diff --git a/clang/lib/CodeGen/MCDCState.h b/clang/lib/CodeGen/MCDCState.h
index e6e39237a1b41a..d1763ef23b2821 100644
--- a/clang/lib/CodeGen/MCDCState.h
+++ b/clang/lib/CodeGen/MCDCState.h
@@ -26,9 +26,21 @@ using namespace llvm::coverage::mcdc;
 
 /// Per-Function MC/DC state
 struct State {
-  unsigned BitmapBytes = 0;
-  llvm::DenseMap<const Stmt *, unsigned> BitmapMap;
-  llvm::DenseMap<const Stmt *, ConditionID> CondIDMap;
+  unsigned BitmapBits = 0;
+
+  struct Decision {
+    unsigned BitmapIdx;
+    llvm::SmallVector<std::array<int, 2>> Indices;
+  };
+
+  llvm::DenseMap<const Stmt *, Decision> BitmapMap;
+
+  struct Branch {
+    ConditionID ID;
+    const Stmt *DecisionStmt;
+  };
+
+  llvm::DenseMap<const Stmt *, Branch> CondIDMap;
 };
 
 } // namespace clang::CodeGen::MCDC
diff --git a/clang/test/CoverageMapping/branch-constfolded.cpp b/clang/test/CoverageMapping/branch-constfolded.cpp
index c8755d5d752b63..1e7e32808e8382 100644
--- a/clang/test/CoverageMapping/branch-constfolded.cpp
+++ b/clang/test/CoverageMapping/branch-constfolded.cpp
@@ -4,93 +4,93 @@
 // RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++11 -fcoverage-mcdc -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name branch-constfolded.cpp %s | FileCheck %s -check-prefix=MCDC
 
 // CHECK-LABEL: _Z6fand_0b:
-bool fand_0(bool a) {      // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:20 = M:0, C:2
+bool fand_0(bool a) {      // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:20 = M:3, C:2
   return false && a;       // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:15 = 0, 0
 }                          // CHECK: Branch,File 0, [[@LINE-1]]:19 -> [[@LINE-1]]:20 = #2, (#1 - #2)
 
 // CHECK-LABEL: _Z6fand_1b:
-bool fand_1(bool a) {      // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:19 = M:0, C:2
+bool fand_1(bool a) {      // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:19 = M:3, C:2
   return a && true;        // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = #1, (#0 - #1)
 }                          // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:19 = 0, 0
 
 // CHECK-LABEL: _Z6fand_2bb:
-bool fand_2(bool a, bool b) {// MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:25 = M:0, C:3
+bool fand_2(bool a, bool b) {// MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:25 = M:4, C:3
   return false && a && b;  // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:15 = 0, 0
 }                          // CHECK: Branch,File 0, [[@LINE-1]]:19 -> [[@LINE-1]]:20 = #4, (#3 - #4)
                            // CHECK: Branch,File 0, [[@LINE-2]]:24 -> [[@LINE-2]]:25 = #2, (#1 - #2)
 
 // CHECK-LABEL: _Z6fand_3bb:
-bool fand_3(bool a, bool b) {// MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:24 = M:0, C:3
+bool fand_3(bool a, bool b) {// MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:24 = M:4, C:3
   return a && true && b;   // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = #3, (#0 - #3)
 }                          // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:19 = 0, 0
                            // CHECK: Branch,File 0, [[@LINE-2]]:23 -> [[@LINE-2]]:24 = #2, (#1 - #2)
 
 // CHECK-LABEL: _Z6fand_4bb:
-bool fand_4(bool a, bool b) {// MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:25 = M:0, C:3
+bool fand_4(bool a, bool b) {// MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:25 = M:4, C:3
   return a && b && false;  // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = #3, (#0 - #3)
 }                          // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:16 = #4, (#3 - #4)
                            // CHECK: Branch,File 0, [[@LINE-2]]:20 -> [[@LINE-2]]:25 = 0, 0
 
 // CHECK-LABEL: _Z6fand_5b:
-bool fand_5(bool a) {      // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:23 = M:0, C:2
+bool fand_5(bool a) {      // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:23 = M:3, C:2
   return false && true;    // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:15 = 0, 0
 }                          // CHECK: Branch,File 0, [[@LINE-1]]:19 -> [[@LINE-1]]:23 = 0, 0
 
 // CHECK-LABEL: _Z6fand_6b:
-bool fand_6(bool a) {      // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:19 = M:0, C:2
+bool fand_6(bool a) {      // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:19 = M:3, C:2
   return true && a;        // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:14 = 0, 0
 }                          // CHECK: Branch,File 0, [[@LINE-1]]:18 -> [[@LINE-1]]:19 = #2, (#1 - #2)
 
 // CHECK-LABEL: _Z6fand_7b:
-bool fand_7(bool a) {      // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:20 = M:0, C:2
+bool fand_7(bool a) {      // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:20 = M:3, C:2
   return a && false;       // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = #1, (#0 - #1)
 }                          // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:20 = 0, 0
 
 // CHECK-LABEL: _Z5for_0b:
-bool for_0(bool a) {       // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:19 = M:0, C:2
+bool for_0(bool a) {       // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:19 = M:3, C:2
   return true || a;        // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:14 = 0, 0
 }                          // CHECK: Branch,File 0, [[@LINE-1]]:18 -> [[@LINE-1]]:19 = (#1 - #2), #2
 
 // CHECK-LABEL: _Z5for_1b:
-bool for_1(bool a) {       // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:20 = M:0, C:2
+bool for_1(bool a) {       // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:20 = M:3, C:2
   return a || false;       // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = (#0 - #1), #1
 }                          // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:20 = 0, 0
 
 // CHECK-LABEL: _Z5for_2bb:
-bool for_2(bool a, bool b) {// MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:24 = M:0, C:3
+bool for_2(bool a, bool b) {// MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:24 = M:4, C:3
   return true || a || b;   // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:14 = 0, 0
 }                          // CHECK: Branch,File 0, [[@LINE-1]]:18 -> [[@LINE-1]]:19 = (#3 - #4), #4
                            // CHECK: Branch,File 0, [[@LINE-2]]:23 -> [[@LINE-2]]:24 = (#1 - #2), #2
 
 // CHECK-LABEL: _Z5for_3bb:
-bool for_3(bool a, bool b) {// MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:25 = M:0, C:3
+bool for_3(bool a, bool b) {// MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:25 = M:4, C:3
   return a || false || b;  // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = (#0 - #3), #3
 }                          // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:20 = 0, 0
                            // CHECK: Branch,File 0, [[@LINE-2]]:24 -> [[@LINE-2]]:25 = (#1 - #2), #2
 
 // CHECK-LABEL: _Z5for_4bb:
-bool for_4(bool a, bool b) {// MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:24 = M:0, C:3
+bool for_4(bool a, bool b) {// MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:24 = M:4, C:3
   return a || b || true;   // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = (#0 - #3), #3
 }                          // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:16 = (#3 - #4), #4
                            // CHECK: Branch,File 0, [[@LINE-2]]:20 -> [[@LINE-2]]:24 = 0, 0
 
 // CHECK-LABEL: _Z5for_5b:
-bool for_5(bool a) {       // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:23 = M:0, C:2
+bool for_5(bool a) {       // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:23 = M:3, C:2
   return true || false;    // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:14 = 0, 0
 }                          // CHECK: Branch,File 0, [[@LINE-1]]:18 -> [[@LINE-1]]:23 = 0, 0
 
 // CHECK-LABEL: _Z5for_6b:
-bool for_6(bool a) {       // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:20 = M:0, C:2
+bool for_6(bool a) {       // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:20 = M:3, C:2
   return false || a;       // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:15 = 0, 0
 }                          // CHECK: Branch,File 0, [[@LINE-1]]:19 -> [[@LINE-1]]:20 = (#1 - #2), #2
 
 // CHECK-LABEL: _Z5for_7b:
-bool for_7(bool a) {       // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:19 = M:0, C:2
+bool for_7(bool a) {       // MCDC: Decision,File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:19 = M:3, C:2
   return a || true;        // CHECK: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = (#0 - #1), #1
 }                          // CHECK: Branch,File 0, [[@LINE-1]]:15 -> [[@LINE-1]]:19 = 0, 0
 
 // CHECK-LABEL: _Z5for_8b:
-bool for_8(bool a) {       // MCDC: Decision,File 0, [[@LINE+3]]:7 -> [[@LINE+3]]:20 = M:0, C:2
+bool for_8(bool a) {       // MCDC: Decision,File 0, [[@LINE+3]]:7 -> [[@LINE+3]]:20 = M:3, C:2
                            // CHECK: Branch,File 0, [[@LINE+2]]:7 -> [[@LINE+2]]:11 = 0, 0
                            // CHECK: Branch,File 0, [[@LINE+1]]:15 -> [[@LINE+1]]:20 = 0, 0
   if (true && false)
diff --git a/clang/test/CoverageMapping/logical.cpp b/clang/test/CoverageMapping/logical.cpp
index 7de59e1429808a..2a22d6cca45189 100644
--- a/clang/test/CoverageMapping/logical.cpp
+++ b/clang/test/CoverageMapping/logical.cpp
@@ -3,22 +3,22 @@
 
 int main() {                        // CHECK: File 0, [[@LINE]]:12 -> [[@LINE+23]]:2 = #0
   bool bt = true;
-  bool bf = false;                  // MCDC: Decision,File 0, [[@LINE+1]]:12 -> [[@LINE+1]]:20 = M:0, C:2
+  bool bf = false;                  // MCDC: Decision,File 0, [[@LINE+1]]:12 -> [[@LINE+1]]:20 = M:3, C:2
   bool a = bt && bf;                // CHECK-NEXT: File 0, [[@LINE]]:12 -> [[@LINE]]:14 = #0
                                     // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:12 -> [[@LINE-1]]:14 = #1, (#0 - #1)
                                     // CHECK-NEXT: File 0, [[@LINE-2]]:18 -> [[@LINE-2]]:20 = #1
                                     // CHECK-NEXT: Branch,File 0, [[@LINE-3]]:18 -> [[@LINE-3]]:20 = #2, (#1 - #2)
-                                    // MCDC: Decision,File 0, [[@LINE+1]]:7 -> [[@LINE+2]]:9 = M:1, C:2
+                                    // MCDC: Decision,File 0, [[@LINE+1]]:7 -> [[@LINE+2]]:9 = M:6, C:2
   a = bt &&                         // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:9 = #0
       bf;                           // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:7 -> [[@LINE-1]]:9 = #3, (#0 - #3)
                                     // CHECK-NEXT: File 0, [[@LINE-1]]:7 -> [[@LINE-1]]:9 = #3
                                     // CHECK-NEXT: Branch,File 0, [[@LINE-2]]:7 -> [[@LINE-2]]:9 = #4, (#3 - #4)
-                                    // MCDC: Decision,File 0, [[@LINE+1]]:7 -> [[@LINE+1]]:15 = M:2, C:2
+                                    // MCDC: Decision,File 0, [[@LINE+1]]:7 -> [[@LINE+1]]:15 = M:9, C:2
   a = bf || bt;                     // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:9 = #0
                                     // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:7 -> [[@LINE-1]]:9 = (#0 - #5), #5
                                     // CHECK-NEXT: File 0, [[@LINE-2]]:13 -> [[@LINE-2]]:15 = #5
                                     // CHECK-NEXT: Branch,File 0, [[@LINE-3]]:13 -> [[@LINE-3]]:15 = (#5 - #6), #6
-                                    // MCDC: Decision,File 0, [[@LINE+1]]:7 -> [[@LINE+2]]:9 = M:3, C:2
+                                    // MCDC: Decision,File 0, [[@LINE+1]]:7 -> [[@LINE+2]]:9 = M:12, C:2
   a = bf ||                         // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:9 = #0
       bt;                           // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:7 -> [[@LINE-1]]:9 = (#0 - #7), #7
                                     // CHECK-NEXT: File 0, [[@LINE-1]]:7 -> [[@LINE-1]]:9 = #7
diff --git a/clang/test/CoverageMapping/mcdc-class.cpp b/clang/test/CoverageMapping/mcdc-class.cpp
index dcf6123ee0fc74..7b2937830be766 100644
--- a/clang/test/CoverageMapping/mcdc-class.cpp
+++ b/clang/test/CoverageMapping/mcdc-class.cpp
@@ -23,9 +23,9 @@ Value::~Value(void) {
     bar();
 }
 
-// CHECK-LABEL:  Decision,File 0, 18:7 -> 18:31 = M:0, C:2
+// CHECK-LABEL:  Decision,File 0, 18:7 -> 18:31 = M:3, C:2
 // CHECK-NEXT:  Branch,File 0, 18:7 -> 18:17 = (#0 - #2), #2 [1,0,2]
 // CHECK:  Branch,File 0, 18:21 -> 18:31 = (#2 - #3), #3 [2,0,0]
-// CHECK-LABEL:  Decision,File 0, 22:7 -> 22:31 = M:0, C:2
+// CHECK-LABEL:  Decision,File 0, 22:7 -> 22:31 = M:3, C:2
 // CHECK-NEXT:  Branch,File 0, 22:7 -> 22:17 = (#0 - #2), #2 [1,0,2]
 // CHECK:  Branch,File 0, 22:21 -> 22:31 = (#2 - #3), #3 [2,0,0]
diff --git a/clang/test/CoverageMapping/mcdc-error-conditions.cpp b/clang/test/CoverageMapping/mcdc-error-conditions.cpp
index d34ed693434795..d2042e576159b4 100644
--- a/clang/test/CoverageMapping/mcdc-error-conditions.cpp
+++ b/clang/test/CoverageMapping/mcdc-error-conditions.cpp
@@ -1,7 +1,87 @@
 // 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
 
-bool func_conditions(bool a, bool b, bool c, bool d, bool e, bool f, bool g) {
-  return a && b && c && d && e && f && g;
+// From clang-tidy/misc/MisleadingIdentifier.cpp
+bool func_conditions(unsigned CP) {
+  return (CP == 0x0590) || (CP == 0x05BE) || (CP == 0x05C0) || (CP == 0x05C3) ||
+         (CP == 0x05C6) || (0x05C8 <= CP && CP <= 0x05CF) ||
+         (0x05D0 <= CP && CP <= 0x05EA) || (0x05EB <= CP && CP <= 0x05EE) ||
+         (0x05EF <= CP && CP <= 0x05F2) || (0x05F3 <= CP && CP <= 0x05F4) ||
+         (0x05F5 <= CP && CP <= 0x05FF) || (0x07C0 <= CP && CP <= 0x07C9) ||
+         (0x07CA <= CP && CP <= 0x07EA) || (0x07F4 <= CP && CP <= 0x07F5) ||
+         (CP == 0x07FA) || (0x07FB <= CP && CP <= 0x07FC) ||
+         (0x07FE <= CP && CP <= 0x07FF) || (0x0800 <= CP && CP <= 0x0815) ||
+         (CP == 0x081A) || (CP == 0x0824) || (CP == 0x0828) ||
+         (0x082E <= CP && CP <= 0x082F) || (0x0830 <= CP && CP <= 0x083E) ||
+         (CP == 0x083F) || (0x0840 <= CP && CP <= 0x0858) ||
+         (0x085C <= CP && CP <= 0x085D) || (CP == 0x085E) || (CP == 0x085F) ||
+         (CP == 0x200F) || (CP == 0xFB1D) || (0xFB1F <= CP && CP <= 0xFB28) ||
+         (0xFB2A <= CP && CP <= 0xFB36) || (CP == 0xFB37) ||
+         (0xFB38 <= CP && CP <= 0xFB3C) || (CP == 0xFB3D) || (CP == 0xFB3E) ||
+         (CP == 0xFB3F) || (0xFB40 <= CP && CP <= 0xFB41) || (CP == 0xFB42) ||
+         (0xFB43 <= CP && CP <= 0xFB44) || (CP == 0xFB45) ||
+         (0xFB46 <= CP && CP <= 0xFB4F) || (0x10800 <= CP && CP <= 0x10805) ||
+         (0x10806 <= CP && CP <= 0x10807) || (CP == 0x10808) ||
+         (CP == 0x10809) || (0x1080A <= CP && CP <= 0x10835) ||
+         (CP == 0x10836) || (0x10837 <= CP && CP <= 0x10838) ||
+         (0x10839 <= CP && CP <= 0x1083B) || (CP == 0x1083C) ||
+         (0x1083D <= CP && CP <= 0x1083E) || (0x1083F <= CP && CP <= 0x10855) ||
+         (CP == 0x10856) || (CP == 0x10857) ||
+         (0x10858 <= CP && CP <= 0x1085F) || (0x10860 <= CP && CP <= 0x10876) ||
+         (0x10877 <= CP && CP <= 0x10878) || (0x10879 <= CP && CP <= 0x1087F) ||
+         (0x10880 <= CP && CP <= 0x1089E) || (0x1089F <= CP && CP <= 0x108A6) ||
+         (0x108A7 <= CP && CP <= 0x108AF) || (0x108B0 <= CP && CP <= 0x108DF) ||
+         (0x108E0 <= CP && CP <= 0x108F2) || (CP == 0x108F3) ||
+         (0x108F4 <= CP && CP <= 0x108F5) || (0x108F6 <= CP && CP <= 0x108FA) ||
+         (0x108FB <= CP && CP <= 0x108FF) || (0x10900 <= CP && CP <= 0x10915) ||
+         (0x10916 <= CP && CP <= 0x1091B) || (0x1091C <= CP && CP <= 0x1091E) ||
+         (0x10920 <= CP && CP <= 0x10939) || (0x1093A <= CP && CP <= 0x1093E) ||
+         (CP == 0x1093F) || (0x10940 <= CP && CP <= 0x1097F) ||
+         (0x10980 <= CP && CP <= 0x109B7) || (0x109B8 <= CP && CP <= 0x109BB) ||
+         (0x109BC <= CP && CP <= 0x109BD) || (0x109BE <= CP && CP <= 0x109BF) ||
+         (0x109C0 <= CP && CP <= 0x109CF) || (0x109D0 <= CP && CP <= 0x109D1) ||
+         (0x109D2 <= CP && CP <= 0x109FF) || (CP == 0x10A00) ||
+         (CP == 0x10A04) || (0x10A07 <= CP && CP <= 0x10A0B) ||
+         (0x10A10 <= CP && CP <= 0x10A13) || (CP == 0x10A14) ||
+         (0x10A15 <= CP && CP <= 0x10A17) || (CP == 0x10A18) ||
+         (0x10A19 <= CP && CP <= 0x10A35) || (0x10A36 <= CP && CP <= 0x10A37) ||
+         (0x10A3B <= CP && CP <= 0x10A3E) || (0x10A40 <= CP && CP <= 0x10A48) ||
+         (0x10A49 <= CP && CP <= 0x10A4F) || (0x10A50 <= CP && CP <= 0x10A58) ||
+         (0x10A59 <= CP && CP <= 0x10A5F) || (0x10A60 <= CP && CP <= 0x10A7C) ||
+         (0x10A7D <= CP && CP <= 0x10A7E) || (CP == 0x10A7F) ||
+         (0x10A80 <= CP && CP <= 0x10A9C) || (0x10A9D <= CP && CP <= 0x10A9F) ||
+         (0x10AA0 <= CP && CP <= 0x10ABF) || (0x10AC0 <= CP && CP <= 0x10AC7) ||
+         (CP == 0x10AC8) || (0x10AC9 <= CP && CP <= 0x10AE4) ||
+         (0x10AE7 <= CP && CP <= 0x10AEA) || (0x10AEB <= CP && CP <= 0x10AEF) ||
+         (0x10AF0 <= CP && CP <= 0x10AF6) || (0x10AF7 <= CP && CP <= 0x10AFF) ||
+         (0x10B00 <= CP && CP <= 0x10B35) || (0x10B36 <= CP && CP <= 0x10B38) ||
+         (0x10B40 <= CP && CP <= 0x10B55) || (0x10B56 <= CP && CP <= 0x10B57) ||
+         (0x10B58 <= CP && CP <= 0x10B5F) || (0x10B60 <= CP && CP <= 0x10B72) ||
+         (0x10B73 <= CP && CP <= 0x10B77) || (0x10B78 <= CP && CP <= 0x10B7F) ||
+         (0x10B80 <= CP && CP <= 0x10B91) || (0x10B92 <= CP && CP <= 0x10B98) ||
+         (0x10B99 <= CP && CP <= 0x10B9C) || (0x10B9D <= CP && CP <= 0x10BA8) ||
+         (0x10BA9 <= CP && CP <= 0x10BAF) || (0x10BB0 <= CP && CP <= 0x10BFF) ||
+         (0x10C00 <= CP && CP <= 0x10C48) || (0x10C49 <= CP && CP <= 0x10C7F) ||
+         (0x10C80 <= CP && CP <= 0x10CB2) || (0x10CB3 <= CP && CP <= 0x10CBF) ||
+         (0x10CC0 <= CP && CP <= 0x10CF2) || (0x10CF3 <= CP && CP <= 0x10CF9) ||
+         (0x10CFA <= CP && CP <= 0x10CFF) || (0x10D40 <= CP && CP <= 0x10E5F) ||
+         (CP == 0x10E7F) || (0x10E80 <= CP && CP <= 0x10EA9) ||
+         (CP == 0x10EAA) || (CP == 0x10EAD) ||
+         (0x10EAE <= CP && CP <= 0x10EAF) || (0x10EB0 <= CP && CP <= 0x10EB1) ||
+         (0x10EB2 <= CP && CP <= 0x10EFF) || (0x10F00 <= CP && CP <= 0x10F1C) ||
+         (0x10F1D <= CP && CP <= 0x10F26) || (CP == 0x10F27) ||
+         (0x10F28 <= CP && CP <= 0x10F2F) || (0x10F70 <= CP && CP <= 0x10F81) ||
+         (0x10F86 <= CP && CP <= 0x10F89) || (0x10F8A <= CP && CP <= 0x10FAF) ||
+         (0x10FB0 <= CP && CP <= 0x10FC4) || (0x10FC5 <= CP && CP <= 0x10FCB) ||
+         (0x10FCC <= CP && CP <= 0x10FDF) || (0x10FE0 <= CP && CP <= 0x10FF6) ||
+         (0x10FF7 <= CP && CP <= 0x10FFF) || (0x1E800 <= CP && CP <= 0x1E8C4) ||
+         (0x1E8C5 <= CP && CP <= 0x1E8C6) || (0x1E8C7 <= CP && CP <= 0x1E8CF) ||
+         (0x1E8D7 <= CP && CP <= 0x1E8FF) || (0x1E900 <= CP && CP <= 0x1E943) ||
+         (CP == 0x1E94B) || (0x1E94C <= CP && CP <= 0x1E94F) ||
+         (0x1E950 <= CP && CP <= 0x1E959) || (0x1E95A <= CP && CP <= 0x1E95D) ||
+         (0x1E95E <= CP && CP <= 0x1E95F) || (0x1E960 <= CP && CP <= 0x1EC6F) ||
+         (0x1ECC0 <= CP && CP <= 0x1ECFF) || (0x1ED50 <= CP && CP <= 0x1EDFF);
 }
 
-// CHECK: warning: unsupported MC/DC boolean expression; number of conditions{{.*}} exceeds max
+// CHECK: warning: unsupported MC/DC boolean expression; number of test vectors{{.*}} exceeds max
+// CHECK-NOT: Decision,
+// CHECK-NOT: Branch,{{.*}}]
diff --git a/clang/test/CoverageMapping/mcdc-logical-scalar-ids.cpp b/clang/test/CoverageMapping/mcdc-logical-scalar-ids.cpp
index c820b5df5ad3a9..0694f7dbc294aa 100644
--- a/clang/test/CoverageMapping/mcdc-logical-scalar-ids.cpp
+++ b/clang/test/CoverageMapping/mcdc-logical-scalar-ids.cpp
@@ -10,25 +10,25 @@ bool func_scalar_and(bool a, bool b, bool c, bool d, bool e, bool f) {
     return bar(res1, res2, res3, res4, res5);
 }
 
-// CHECK-LABEL: Decision,File 0, 5:17 -> 5:23 = M:0, C:2
+// CHECK-LABEL: Decision,File 0, 5:17 -> 5:23 = M:3, C:2
 // CHECK-NEXT: Branch,File 0, 5:17 -> 5:18 = #1, (#0 - #1) [1,2,0]
 // CHECK: Branch,File 0, 5:22 -> 5:23 = #2, (#1 - #2) [2,0,0]
-// CHECK-LABEL: Decision,File 0, 6:17 -> 6:28 = M:1, C:3
+// CHECK-LABEL: Decision,File 0, 6:17 -> 6:28 = M:7, C:3
 // CHECK-NEXT: Branch,File 0, 6:17 -> 6:18 = #5, (#0 - #5) [1,3,0]
 // CHECK: Branch,File 0, 6:22 -> 6:23 = #6, (#5 - #6) [3,2,0]
 // CHECK: Branch,File 0, 6:27 -> 6:28 = #4, (#3 - #4) [2,0,0]
-// CHECK-LABEL: Decision,File 0, 7:17 -> 7:33 = M:2, C:4
+// CHECK-LABEL: Decision,File 0, 7:17 -> 7:33 = M:12, C:4
 // CHECK-NEXT: Branch,File 0, 7:17 -> 7:18 = #11, (#0 - #11) [1,4,0]
 // CHECK: Branch,File 0, 7:22 -> 7:23 = #12, (#11 - #12) [4,3,0]
 // CHECK: Branch,File 0, 7:27 -> 7:28 = #10, (#9 - #10) [3,2,0]
 // CHECK: Branch,File 0, 7:32 -> 7:33 = #8, (#7 - #8) [2,0,0]
-// CHECK-LABEL: Decision,File 0, 8:17 -> 8:38 = M:4, C:5
+// CHECK-LABEL: Decision,File 0, 8:17 -> 8:38 = M:18, C:5
 // CHECK-NEXT: Branch,File 0, 8:17 -> 8:18 = #19, (#0 - #19) [1,5,0]
 // CHECK: Branch,File 0, 8:22 -> 8:23 = #20, (#19 - #20) [5,4,0]
 // CHECK: Branch,File 0, 8:27 -> 8:28 = #18, (#17 - #18) [4,3,0]
 // CHECK: Branch,File 0, 8:32 -> 8:33 = #16, (#15 - #16) [3,2,0]
 // CHECK: Branch,File 0, 8:37 -> 8:38 = #14, (#13 - #14) [2,0,0]
-// CHECK-LABEL: Decision,File 0, 9:17 -> 9:43 = M:8, C:6
+// CHECK-LABEL: Decision,File 0, 9:17 -> 9:43 = M:25, C:6
 // CHECK-NEXT: Branch,File 0, 9:17 -> 9:18 = #29, (#0 - #29) [1,6,0]
 // CHECK: Branch,File 0, 9:22 -> 9:23 = #30, (#29 - #30) [6,5,0]
 // CHECK: Branch,File 0, 9:27 -> 9:28 = #28, (#27 - #28) [5,4,0]
@@ -45,25 +45,25 @@ bool func_scalar_or(bool a, bool b, bool c, bool d, bool e, bool f) {
     return bar(res1, res2, res3, res4, res5);
 }
 
-// CHECK-LABEL: Decision,File 0, 40:17 -> 40:23 = M:0, C:2
+// CHECK-LABEL: Decision,File 0, 40:17 -> 40:23 = M:3, C:2
 // CHECK-NEXT: Branch,File 0, 40:17 -> 40:18 = (#0 - #1), #1 [1,0,2]
 // CHECK: Branch,File 0, 40:22 -> 40:23 = (#1 - #2), #2 [2,0,0]
-// CHECK-LABEL: Decision,File 0, 41:17 -> 41:28 = M:1, C:3
+// CHECK-LABEL: Decision,File 0, 41:17 -> 41:28 = M:7, C:3
 // CHECK-NEXT: Branch,File 0, 41:17 -> 41:18 = (#0 - #5), #5 [1,0,3]
 // CHECK: Branch,File 0, 41:22 -> 41:23 = (#5 - #6), #6 [3,0,2]
 // CHECK: Branch,File 0, 41:27 -> 41:28 = (#3 - #4), #4 [2,0,0]
-// CHECK-LABEL: Decision,File 0, 42:17 -> 42:33 = M:2, C:4
+// CHECK-LABEL: Decision,File 0, 42:17 -> 42:33 = M:12, C:4
 // CHECK-NEXT: Branch,File 0, 42:17 -> 42:18 = (#0 - #11), #11 [1,0,4]
 // CHECK: Branch,File 0, 42:22 -> 42:23 = (#11 - #12), #12 [4,0,3]
 // CHECK: Branch,File 0, 42:27 -> 42:28 = (#9 - #10), #10 [3,0,2]
 // CHECK: Branch,File 0, 42:32 -> 42:33 = (#7 - #8), #8 [2,0,0]
-// CHECK-LABEL: Decision,File 0, 43:17 -> 43:38 = M:4, C:5
+// CHECK-LABEL: Decision,File 0, 43:17 -> 43:38 = M:18, C:5
 // CHECK-NEXT: Branch,File 0, 43:17 -> 43:18 = (#0 - #19), #19 [1,0,5]
 // CHECK: Branch,File 0, 43:22 -> 43:23 = (#19 - #20), #20 [5,0,4]
 // CHECK: Branch,File 0, 43:27 -> 43:28 = (#17 - #18), #18 [4,0,3]
 // CHECK: Branch,File 0, 43:32 -> 43:33 = (#15 - #16), #16 [3,0,2]
 // CHECK: Branch,File 0, 43:37 -> 43:38 = (#13 - #14), #14 [2,0,0]
-// CHECK-LABEL: Decision,File 0, 44:17 -> 44:43 = M:8, C:6
+// CHECK-LABEL: Decision,File 0, 44:17 -> 44:43 = M:25, C:6
 // CHECK-NEXT: Branch,File 0, 44:17 -> 44:18 = (#0 - #29), #29 [1,0,6]
 // CHECK: Branch,File 0, 44:22 -> 44:23 = (#29 - #30), #30 [6,0,5]
 // CHECK: Branch,File 0, 44:27 -> 44:28 = (#27 - #28), #28 [5,0,4]
@@ -81,26 +81,26 @@ bool func_scalar_mix(bool a, bool b, bool c, bool d, bool e, bool f) {
     return bar(res1, res2, res3, res4, res5);
 }
 
-// CHECK-LABEL:  Decision,File 0, 76:17 -> 76:23 = M:0, C:2
+// CHECK-LABEL:  Decision,File 0, 76:17 -> 76:23 = M:3, C:2
 // CHECK-NEXT:  Branch,File 0, 76:17 -> 76:18 = (#0 - #1), #1 [1,0,2]
 // CHECK:  Branch,File 0, 76:22 -> 76:23 = (#1 - #2), #2 [2,0,0]
-// CHECK-LABEL:  Decision,File 0, 77:17 -> 77:30 = M:1, C:3
+// CHECK-LABEL:  Decision,File 0, 77:17 -> 77:30 = M:7, C:3
 // CHECK-NEXT:  Branch,File 0, 77:17 -> 77:18 = #3, (#0 - #3) [1,2,0]
 // CHECK:  Branch,File 0, 77:23 -> 77:24 = (#3 - #4), #4 [2,0,3]
 // CHECK:  Branch,File 0, 77:28 -> 77:29 = (#4 - #5), #5 [3,0,0]
-// CHECK-LABEL:  Decision,File 0, 78:17 -> 78:37 = M:2, C:4
+// CHECK-LABEL:  Decision,File 0, 78:17 -> 78:37 = M:14, C:4
 // CHECK-NEXT:  File 0
 // CHECK-NEXT:  Branch,File 0, 78:18 -> 78:19 = (#0 - #7), #7 [1,2,3]
 // CHECK:  Branch,File 0, 78:23 -> 78:24 = (#7 - #8), #8 [3,2,0]
 // CHECK:  Branch,File 0, 78:30 -> 78:31 = (#6 - #9), #9 [2,0,4]
 // CHECK:  Branch,File 0, 78:35 -> 78:36 = (#9 - #10), #10 [4,0,0]
-// CHECK-LABEL:  Decision,File 0, 79:17 -> 79:42 = M:4, C:5
+// CHECK-LABEL:  Decision,File 0, 79:17 -> 79:42 = M:22, C:5
 // CHECK-NEXT:  Branch,File 0, 79:17 -> 79:18 = #12, (#0 - #12) [1,3,0]
 // CHECK:  Branch,File 0, 79:23 -> 79:24 = (#12 - #13), #13 [3,2,4]
 // CHECK:  Branch,File 0, 79:28 -> 79:29 = (#13 - #14), #14 [4,2,0]
 // CHECK:  Branch,File 0, 79:35 -> 79:36 = (#11 - #15), #15 [2,0,5]
 // CHECK:  Branch,File 0, 79:40 -> 79:41 = (#15 - #16), #16 [5,0,0]
-// CHECK-LABEL:  Decision,File 0, 80:17 -> 80:49 = M:8, C:6
+// CHECK-LABEL:  Decision,File 0, 80:17 -> 80:49 = M:37, C:6
 // CHECK-NEXT:  File 0
 // CHECK-NEXT:  Branch,File 0, 80:18 -> 80:19 = (#0 - #19), #19 [1,3,4]
 // CHECK:  Branch,File 0, 80:23 -> 80:24 = (#19 - #20), #20 [4,3,0]
diff --git a/clang/test/CoverageMapping/mcdc-logical-stmt-ids-all.cpp b/clang/test/CoverageMapping/mcdc-logical-stmt-ids-all.cpp
index 6f47a4b901a8a7..d7436079d18105 100644
--- a/clang/test/CoverageMapping/mcdc-logical-stmt-ids-all.cpp
+++ b/clang/test/CoverageMapping/mcdc-logical-stmt-ids-all.cpp
@@ -6,7 +6,7 @@ bool func_if_and(bool a, bool b, bool c, bool d, bool e, bool f) {
   return false;
 }
 
-// CHECK-LABEL:  Decision,File 0, 4:7 -> 4:33 = M:0, C:6
+// CHECK-LABEL:  Decision,File 0, 4:7 -> 4:33 = M:7, C:6
 // CHECK-NEXT:  Branch,File 0, 4:7 -> 4:8 = #10, (#0 - #10) [1,6,0]
 // CHECK:  Branch,File 0, 4:12 -> 4:13 = #11, (#10 - #11) [6,5,0]
 // CHECK:  Branch,File 0, 4:17 -> 4:18 = #9, (#8 - #9) [5,4,0]
@@ -20,7 +20,7 @@ bool func_if_or(bool a, bool b, bool c, bool d, bool e, bool f) {
   return false;
 }
 
-// CHECK-LABEL:  Decision,File 0, 18:7 -> 18:33 = M:0, C:6
+// CHECK-LABEL:  Decision,File 0, 18:7 -> 18:33 = M:7, C:6
 // CHECK-NEXT:  Branch,File 0, 18:7 -> 18:8 = (#0 - #10), #10 [1,0,6]
 // CHECK:  Branch,File 0, 18:12 -> 18:13 = (#10 - #11), #11 [6,0,5]
 // CHECK:  Branch,File 0, 18:17 -> 18:18 = (#8 - #9), #9 [5,0,4]
@@ -33,7 +33,7 @@ bool func_while_and(bool a, bool b, bool c, bool d, bool e, bool f) {
   return false;
 }
 
-// CHECK-LABEL:  Decision,File 0, 32:10 -> 32:36 = M:0, C:6
+// CHECK-LABEL:  Decision,File 0, 32:10 -> 32:36 = M:7, C:6
 // CHECK-NEXT:  Branch,File 0, 32:10 -> 32:11 = #10, (#0 - #10) [1,6,0]
 // CHECK:  Branch,File 0, 32:15 -> 32:16 = #11, (#10 - #11) [6,5,0]
 // CHECK:  Branch,File 0, 32:20 -> 32:21 = #9, (#8 - #9) [5,4,0]
@@ -46,7 +46,7 @@ bool func_while_or(bool a, bool b, bool c, bool d, bool e, bool f) {
   return false;
 }
 
-// CHECK-LABEL:  Decision,File 0, 45:10 -> 45:36 = M:0, C:6
+// CHECK-LABEL:  Decision,File 0, 45:10 -> 45:36 = M:7, C:6
 // CHECK-NEXT:  Branch,File 0, 45:10 -> 45:11 = (#0 - #10), #10 [1,0,6]
 // CHECK:  Branch,File 0, 45:15 -> 45:16 = (#10 - #11), #11 [6,0,5]
 // CHECK:  Branch,File 0, 45:20 -> 45:21 = (#8 - #9), #9 [5,0,4]
@@ -59,7 +59,7 @@ bool func_for_and(bool a, bool b, bool c, bool d, bool e, bool f) {
   return false;
 }
 
-// CHECK-LABEL:  Decision,File 0, 58:9 -> 58:35 = M:0, C:6
+// CHECK-LABEL:  Decision,File 0, 58:9 -> 58:35 = M:7, C:6
 // CHECK-NEXT:  Branch,File 0, 58:9 -> 58:10 = #10, (#0 - #10) [1,6,0]
 // CHECK:  Branch,File 0, 58:14 -> 58:15 = #11, (#10 - #11) [6,5,0]
 // CHECK:  Branch,File 0, 58:19 -> 58:20 = #9, (#8 - #9) [5,4,0]
@@ -72,7 +72,7 @@ bool func_for_or(bool a, bool b, bool c, bool d, bool e, bool f) {
   return false;
 }
 
-// CHECK-LABEL:  Decision,File 0, 71:9 -> 71:35 = M:0, C:6
+// CHECK-LABEL:  Decision,File 0, 71:9 -> 71:35 = M:7, C:6
 // CHECK-NEXT:  Branch,File 0, 71:9 -> 71:10 = (#0 - #10), #10 [1,0,6]
 // CHECK:  Branch,File 0, 71:14 -> 71:15 = (#10 - #11), #11 [6,0,5]
 // CHECK:  Branch,File 0, 71:19 -> 71:20 = (#8 - #9), #9 [5,0,4]
@@ -85,7 +85,7 @@ bool func_do_and(bool a, bool b, bool c, bool d, bool e, bool f) {
   return false;
 }
 
-// CHECK-LABEL:  Decision,File 0, 84:16 -> 84:42 = M:0, C:6
+// CHECK-LABEL:  Decision,File 0, 84:16 -> 84:42 = M:7, C:6
 // CHECK-NEXT:  Branch,File 0, 84:16 -> 84:17 = #10, ((#0 + #1) - #10) [1,6,0]
 // CHECK:  Branch,File 0, 84:21 -> 84:22 = #11, (#10 - #11) [6,5,0]
 // CHECK:  Branch,File 0, 84:26 -> 84:27 = #9, (#8 - #9) [5,4,0]
@@ -98,7 +98,7 @@ bool func_do_or(bool a, bool b, bool c, bool d, bool e, bool f) {
   return false;
 }
 
-// CHECK-LABEL:  Decision,File 0, 97:16 -> 97:42 = M:0, C:6
+// CHECK-LABEL:  Decision,File 0, 97:16 -> 97:42 = M:7, C:6
 // CHECK-NEXT:  Branch,File 0, 97:16 -> 97:17 = ((#0 + #1) - #10), #10 [1,0,6]
 // CHECK:  Branch,File 0, 97:21 -> 97:22 = (#10 - #11), #11 [6,0,5]
 // CHECK:  Branch,File 0, 97:26 -> 97:27 = (#8 - #9), #9 [5,0,4]
@@ -110,7 +110,7 @@ bool func_ternary_and(bool a, bool b, bool c, bool d, bool e, bool f) {
   return (a && b && c && d && e && f) ? true : false;
 }
 
-// CHECK-LABEL:  Decision,File 0, 110:11 -> 110:37 = M:0, C:6
+// CHECK-LABEL:  Decision,File 0, 110:11 -> 110:37 = M:7, C:6
 // CHECK-NEXT:  Branch,File 0, 110:11 -> 110:12 = #10, (#0 - #10) [1,6,0]
 // CHECK:  Branch,File 0, 110:16 -> 110:17 = #11, (#10 - #11) [6,5,0]
 // CHECK:  Branch,File 0, 110:21 -> 110:22 = #9, (#8 - #9) [5,4,0]
@@ -122,7 +122,7 @@ bool func_ternary_or(bool a, bool b, bool c, bool d, bool e, bool f) {
   return (a || b || c || d || e || f) ? true : false;
 }
 
-// CHECK-LABEL: Decision,File 0, 122:11 -> 122:37 = M:0, C:6
+// CHECK-LABEL: Decision,File 0, 122:11 -> 122:37 = M:7, C:6
 // CHECK-NEXT:  Branch,File 0, 122:11 -> 122:12 = (#0 - #10), #10 [1,0,6]
 // CHECK:  Branch,File 0, 122:16 -> 122:17 = (#10 - #11), #11 [6,0,5]
 // CHECK:  Branch,File 0, 122:21 -> 122:22 = (#8 - #9), #9 [5,0,4]
@@ -137,7 +137,7 @@ bool func_if_nested_if(bool a, bool b, bool c, bool d, bool e) {
     return false;
 }
 
-// CHECK-LABEL: Decision,File 0, 134:7 -> 134:30 = M:0, C:5
+// CHECK-LABEL: Decision,File 0, 134:7 -> 134:30 = M:8, C:5
 // CHECK-NEXT:  Branch,File 0, 134:7 -> 134:8 = (#0 - #6), #6 [1,0,4]
 // CHECK:  Branch,File 0, 134:13 -> 134:14 = #7, (#6 - #7) [4,5,3]
 // CHECK:  Branch,File 0, 134:18 -> 134:19 = #8, (#7 - #8) [5,0,3]
@@ -148,7 +148,7 @@ bool func_ternary_nested_if(bool a, bool b, bool c, bool d, bool e) {
   return (a || (b && c) || d || e) ? true : false;
 }
 
-// CHECK-LABEL: Decision,File 0, 148:11 -> 148:34 = M:0, C:5
+// CHECK-LABEL: Decision,File 0, 148:11 -> 148:34 = M:8, C:5
 // CHECK-NEXT:  Branch,File 0, 148:11 -> 148:12 = (#0 - #6), #6 [1,0,4]
 // CHECK:  Branch,File 0, 148:17 -> 148:18 = #7, (#6 - #7) [4,5,3]
 // CHECK:  Branch,File 0, 148:22 -> 148:23 = #8, (#7 - #8) [5,0,3]
@@ -162,7 +162,7 @@ bool func_if_nested_if_2(bool a, bool b, bool c, bool d, bool e) {
     return false;
 }
 
-// CHECK-LABEL: Decision,File 0, 159:7 -> 159:32 = M:0, C:5
+// CHECK-LABEL: Decision,File 0, 159:7 -> 159:32 = M:9, C:5
 // CHECK-NEXT:  Branch,File 0, 159:7 -> 159:8 = (#0 - #2), #2 [1,0,2]
 // CHECK:  Branch,File 0, 159:14 -> 159:15 = #7, (#2 - #7) [2,5,4]
 // CHECK:  Branch,File 0, 159:19 -> 159:20 = #8, (#7 - #8) [5,3,4]
@@ -173,7 +173,7 @@ bool func_ternary_nested_if_2(bool a, bool b, bool c, bool d, bool e) {
   return (a || ((b && c) || d) && e) ? true : false;
 }
 
-// CHECK-LABEL: Decision,File 0, 173:11 -> 173:36 = M:0, C:5
+// CHECK-LABEL: Decision,File 0, 173:11 -> 173:36 = M:9, C:5
 // CHECK-NEXT:  Branch,File 0, 173:11 -> 173:12 = (#0 - #2), #2 [1,0,2]
 // CHECK:  Branch,File 0, 173:18 -> 173:19 = #7, (#2 - #7) [2,5,4]
 // CHECK:  Branch,File 0, 173:23 -> 173:24 = #8, (#7 - #8) [5,3,4]
@@ -187,7 +187,7 @@ bool func_if_nested_if_3(bool a, bool b, bool c, bool d, bool e, bool f) {
     return false;
 }
 
-// CHECK-LABEL: Decision,File 0, 184:7 -> 184:39 = M:0, C:6
+// CHECK-LABEL: Decision,File 0, 184:7 -> 184:39 = M:12, C:6
 // CHECK:  Branch,File 0, 184:8 -> 184:9 = #5, (#0 - #5) [1,4,3]
 // CHECK:  Branch,File 0, 184:14 -> 184:15 = (#5 - #6), #6 [4,2,5]
 // CHECK:  Branch,File 0, 184:19 -> 184:20 = (#6 - #7), #7 [5,2,3]
@@ -199,7 +199,7 @@ bool func_ternary_nested_if_3(bool a, bool b, bool c, bool d, bool e, bool f) {
   return ((a && (b || c) || (d && e)) && f) ? true : false;
 }
 
-// CHECK-LABEL: Decision,File 0, 199:11 -> 199:43 = M:0, C:6
+// CHECK-LABEL: Decision,File 0, 199:11 -> 199:43 = M:12, C:6
 // CHECK:  Branch,File 0, 199:12 -> 199:13 = #5, (#0 - #5) [1,4,3]
 // CHECK:  Branch,File 0, 199:18 -> 199:19 = (#5 - #6), #6 [4,2,5]
 // CHECK:  Branch,File 0, 199:23 -> 199:24 = (#6 - #7), #7 [5,2,3]
diff --git a/clang/test/CoverageMapping/mcdc-logical-stmt-ids.cpp b/clang/test/CoverageMapping/mcdc-logical-stmt-ids.cpp
index 99854ec27a3fbd..655bbf25ee1031 100644
--- a/clang/test/CoverageMapping/mcdc-logical-stmt-ids.cpp
+++ b/clang/test/CoverageMapping/mcdc-logical-stmt-ids.cpp
@@ -10,25 +10,25 @@ bool func_if_and(bool a, bool b, bool c, bool d, bool e, bool f) {
   return false;
 }
 
-// CHECK-LABEL:  Decision,File 0, 4:7 -> 4:13 = M:0, C:2
+// CHECK-LABEL:  Decision,File 0, 4:7 -> 4:13 = M:3, C:2
 // CHECK-NEXT:  Branch,File 0, 4:7 -> 4:8 = #2, (#0 - #2) [1,2,0]
 // CHECK:  Branch,File 0, 4:12 -> 4:13 = #3, (#2 - #3) [2,0,0]
-// CHECK-LABEL:  Decision,File 0, 5:9 -> 5:20 = M:1, C:3
+// CHECK-LABEL:  Decision,File 0, 5:9 -> 5:20 = M:7, C:3
 // CHECK-NEXT:  Branch,File 0, 5:9 -> 5:10 = #7, (#1 - #7) [1,3,0]
 // CHECK:  Branch,File 0, 5:14 -> 5:15 = #8, (#7 - #8) [3,2,0]
 // CHECK:  Branch,File 0, 5:19 -> 5:20 = #6, (#5 - #6) [2,0,0]
-// CHECK-LABEL:  Decision,File 0, 6:11 -> 6:27 = M:2, C:4
+// CHECK-LABEL:  Decision,File 0, 6:11 -> 6:27 = M:12, C:4
 // CHECK-NEXT:  Branch,File 0, 6:11 -> 6:12 = #14, (#4 - #14) [1,4,0]
 // CHECK:  Branch,File 0, 6:16 -> 6:17 = #15, (#14 - #15) [4,3,0]
 // CHECK:  Branch,File 0, 6:21 -> 6:22 = #13, (#12 - #13) [3,2,0]
 // CHECK:  Branch,File 0, 6:26 -> 6:27 = #11, (#10 - #11) [2,0,0]
-// CHECK-LABEL:  Decision,File 0, 7:13 -> 7:34 = M:4, C:5
+// CHECK-LABEL:  Decision,File 0, 7:13 -> 7:34 = M:18, C:5
 // CHECK-NEXT:  Branch,File 0, 7:13 -> 7:14 = #23, (#9 - #23) [1,5,0]
 // CHECK:  Branch,File 0, 7:18 -> 7:19 = #24, (#23 - #24) [5,4,0]
 // CHECK:  Branch,File 0, 7:23 -> 7:24 = #22, (#21 - #22) [4,3,0]
 // CHECK:  Branch,File 0, 7:28 -> 7:29 = #20, (#19 - #20) [3,2,0]
 // CHECK:  Branch,File 0, 7:33 -> 7:34 = #18, (#17 - #18) [2,0,0]
-// CHECK-LABEL:  Decision,File 0, 8:16 -> 8:42 = M:8, C:6
+// CHECK-LABEL:  Decision,File 0, 8:16 -> 8:42 = M:25, C:6
 // CHECK-NEXT:  Branch,File 0, 8:16 -> 8:17 = #34, (#16 - #34) [1,6,0]
 // CHECK:  Branch,File 0, 8:21 -> 8:22 = #35, (#34 - #35) [6,5,0]
 // CHECK:  Branch,File 0, 8:26 -> 8:27 = #33, (#32 - #33) [5,4,0]
@@ -46,25 +46,25 @@ bool func_if_or(bool a, bool b, bool c, bool d, bool e, bool f) {
   return false;
 }
 
-// CHECK-LABEL:  Decision,File 0, 40:7 -> 40:13 = M:0, C:2
+// CHECK-LABEL:  Decision,File 0, 40:7 -> 40:13 = M:3, C:2
 // CHECK-NEXT:  Branch,File 0, 40:7 -> 40:8 = (#0 - #2), #2 [1,0,2]
 // CHECK:  Branch,File 0, 40:12 -> 40:13 = (#2 - #3), #3 [2,0,0]
-// CHECK-LABEL:  Decision,File 0, 41:9 -> 41:20 = M:1, C:3
+// CHECK-LABEL:  Decision,File 0, 41:9 -> 41:20 = M:7, C:3
 // CHECK-NEXT:  Branch,File 0, 41:9 -> 41:10 = (#1 - #7), #7 [1,0,3]
 // CHECK:  Branch,File 0, 41:14 -> 41:15 = (#7 - #8), #8 [3,0,2]
 // CHECK:  Branch,File 0, 41:19 -> 41:20 = (#5 - #6), #6 [2,0,0]
-// CHECK-LABEL:  Decision,File 0, 42:11 -> 42:27 = M:2, C:4
+// CHECK-LABEL:  Decision,File 0, 42:11 -> 42:27 = M:12, C:4
 // CHECK-NEXT:  Branch,File 0, 42:11 -> 42:12 = (#4 - #14), #14 [1,0,4]
 // CHECK:  Branch,File 0, 42:16 -> 42:17 = (#14 - #15), #15 [4,0,3]
 // CHECK:  Branch,File 0, 42:21 -> 42:22 = (#12 - #13), #13 [3,0,2]
 // CHECK:  Branch,File 0, 42:26 -> 42:27 = (#10 - #11), #11 [2,0,0]
-// CHECK-LABEL:  Decision,File 0, 43:13 -> 43:34 = M:4, C:5
+// CHECK-LABEL:  Decision,File 0, 43:13 -> 43:34 = M:18, C:5
 // CHECK-NEXT:  Branch,File 0, 43:13 -> 43:14 = (#9 - #23), #23 [1,0,5]
 // CHECK:  Branch,File 0, 43:18 -> 43:19 = (#23 - #24), #24 [5,0,4]
 // CHECK:  Branch,File 0, 43:23 -> 43:24 = (#21 - #22), #22 [4,0,3]
 // CHECK:  Branch,File 0, 43:28 -> 43:29 = (#19 - #20), #20 [3,0,2]
 // CHECK:  Branch,File 0, 43:33 -> 43:34 = (#17 - #18), #18 [2,0,0]
-// CHECK-LABEL:  Decision,File 0, 44:16 -> 44:42 = M:8, C:6
+// CHECK-LABEL:  Decision,File 0, 44:16 -> 44:42 = M:25, C:6
 // CHECK-NEXT:  Branch,File 0, 44:16 -> 44:17 = (#16 - #34), #34 [1,0,6]
 // CHECK:  Branch,File 0, 44:21 -> 44:22 = (#34 - #35), #35 [6,0,5]
 // CHECK:  Branch,File 0, 44:26 -> 44:27 = (#32 - #33), #33 [5,0,4]
@@ -82,26 +82,26 @@ bool func_if_mix(bool a, bool b, bool c, bool d, bool e, bool f) {
   return false;
 }
 
-// CHECK-LABEL:  Decision,File 0, 76:7 -> 76:13 = M:0, C:2
+// CHECK-LABEL:  Decision,File 0, 76:7 -> 76:13 = M:3, C:2
 // CHECK-NEXT:  Branch,File 0, 76:7 -> 76:8 = (#0 - #2), #2 [1,0,2]
 // CHECK:  Branch,File 0, 76:12 -> 76:13 = (#2 - #3), #3 [2,0,0]
-// CHECK-LABEL:  Decision,File 0, 77:9 -> 77:22 = M:1, C:3
+// CHECK-LABEL:  Decision,File 0, 77:9 -> 77:22 = M:7, C:3
 // CHECK-NEXT:  Branch,File 0, 77:9 -> 77:10 = #5, (#1 - #5) [1,2,0]
 // CHECK:  Branch,File 0, 77:15 -> 77:16 = (#5 - #6), #6 [2,0,3]
 // CHECK:  Branch,File 0, 77:20 -> 77:21 = (#6 - #7), #7 [3,0,0]
-// CHECK-LABEL:  Decision,File 0, 78:11 -> 78:31 = M:2, C:4
+// CHECK-LABEL:  Decision,File 0, 78:11 -> 78:31 = M:14, C:4
 // CHECK-NEXT:  File 0
 // CHECK-NEXT:  Branch,File 0, 78:12 -> 78:13 = (#4 - #10), #10 [1,2,3]
 // CHECK:  Branch,File 0, 78:17 -> 78:18 = (#10 - #11), #11 [3,2,0]
 // CHECK:  Branch,File 0, 78:24 -> 78:25 = (#9 - #12), #12 [2,0,4]
 // CHECK:  Branch,File 0, 78:29 -> 78:30 = (#12 - #13), #13 [4,0,0]
-// CHECK-LABEL:  Decision,File 0, 79:13 -> 79:38 = M:4, C:5
+// CHECK-LABEL:  Decision,File 0, 79:13 -> 79:38 = M:22, C:5
 // CHECK-NEXT:  Branch,File 0, 79:13 -> 79:14 = #16, (#8 - #16) [1,3,0]
 // CHECK:  Branch,File 0, 79:19 -> 79:20 = (#16 - #17), #17 [3,2,4]
 // CHECK:  Branch,File 0, 79:24 -> 79:25 = (#17 - #18), #18 [4,2,0]
 // CHECK:  Branch,File 0, 79:31 -> 79:32 = (#15 - #19), #19 [2,0,5]
 // CHECK:  Branch,File 0, 79:36 -> 79:37 = (#19 - #20), #20 [5,0,0]
-// CHECK-LABEL:  Decision,File 0, 80:15 -> 80:47 = M:8, C:6
+// CHECK-LABEL:  Decision,File 0, 80:15 -> 80:47 = M:37, C:6
 // CHECK-NEXT:  File 0
 // CHECK-NEXT:  Branch,File 0, 80:16 -> 80:17 = (#14 - #24), #24 [1,3,4]
 // CHECK:  Branch,File 0, 80:21 -> 80:22 = (#24 - #25), #25 [4,3,0]
diff --git a/clang/test/Profile/c-mcdc-logicalop-ternary.c b/clang/test/Profile/c-mcdc-logicalop-ternary.c
index 558643f422021c..04384d71bf2722 100644
--- a/clang/test/Profile/c-mcdc-logicalop-ternary.c
+++ b/clang/test/Profile/c-mcdc-logicalop-ternary.c
@@ -9,7 +9,7 @@ int test(int a, int b, int c, int d, int e, int f) {
 // NOMCDC-NOT: __profbm_test
 
 // MCDC BOOKKEEPING.
-// MCDC: @__profbm_test = private global [3 x i8] zeroinitializer
+// MCDC: @__profbm_test = private global [2 x i8] zeroinitializer
 
 // ALLOCATE MCDC TEMP AND ZERO IT.
 // MCDC-LABEL: @test(
@@ -39,7 +39,7 @@ int test(int a, int b, int c, int d, int e, int f) {
 // MCDC-DAG:  %[[TEMP:mcdc.temp[0-9]*]] = load i32, ptr %mcdc.addr, align 4
 // MCDC:  %[[LAB1:[0-9]+]] = lshr i32 %[[TEMP]], 3
 // MCDC:  %[[LAB2:[0-9]+]] = zext i32 %[[LAB1]] to i64
-// MCDC:  %[[LAB3:[0-9]+]] = add i64 ptrtoint (ptr getelementptr inbounds ([3 x i8], ptr @__profbm_test, i32 0, i32 1) to i64), %[[LAB2]]
+// MCDC:  %[[LAB3:[0-9]+]] = add i64 ptrtoint (ptr @__profbm_test to i64), %[[LAB2]]
 // MCDC:  %[[LAB4:[0-9]+]] = inttoptr i64 %[[LAB3]] to ptr
 // MCDC:  %[[LAB5:[0-9]+]] = and i32 %[[TEMP]], 7
 // MCDC:  %[[LAB6:[0-9]+]] = trunc i32 %[[LAB5]] to i8
@@ -71,7 +71,7 @@ int test(int a, int b, int c, int d, int e, int f) {
 // MCDC-DAG:  %[[TEMP:mcdc.temp[0-9]*]] = load i32, ptr %mcdc.addr, align 4
 // MCDC:  %[[LAB1:[0-9]+]] = lshr i32 %[[TEMP]], 3
 // MCDC:  %[[LAB2:[0-9]+]] = zext i32 %[[LAB1]] to i64
-// MCDC:  %[[LAB3:[0-9]+]] = add i64 ptrtoint (ptr getelementptr inbounds ([3 x i8], ptr @__profbm_test, i32 0, i32 2) to i64), %[[LAB2]]
+// MCDC:  %[[LAB3:[0-9]+]] = add i64 ptrtoint (ptr @__profbm_test to i64), %[[LAB2]]
 // MCDC:  %[[LAB4:[0-9]+]] = inttoptr i64 %[[LAB3]] to ptr
 // MCDC:  %[[LAB5:[0-9]+]] = and i32 %[[TEMP]], 7
 // MCDC:  %[[LAB6:[0-9]+]] = trunc i32 %[[LAB5]] to i8
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index 8e6205c4b61667..51cc29fd26ce8b 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -387,34 +387,31 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
       : NextIDsBuilder(Branches), TVIdxBuilder(this->NextIDs), Bitmap(Bitmap),
         Region(Region), DecisionParams(Region.getDecisionParams()),
         Branches(Branches), NumConditions(DecisionParams.NumConditions),
-        BitmapIdx(DecisionParams.BitmapIdx * CHAR_BIT),
-        Folded(NumConditions, false), IndependencePairs(NumConditions) {}
+        BitmapIdx(DecisionParams.BitmapIdx), Folded(NumConditions, false),
+        IndependencePairs(NumConditions) {}
 
 private:
   // Walk the binary decision diagram and try assigning both false and true to
   // each node. When a terminal node (ID == 0) is reached, fill in the value in
   // the truth table.
   void buildTestVector(MCDCRecord::TestVector &TV, mcdc::ConditionID ID,
-                       int TVIdx, unsigned Index) {
-    assert((Index & (1 << ID)) == 0);
-
+                       int TVIdx) {
     for (auto MCDCCond : {MCDCRecord::MCDC_False, MCDCRecord::MCDC_True}) {
       static_assert(MCDCRecord::MCDC_False == 0);
       static_assert(MCDCRecord::MCDC_True == 1);
-      Index |= MCDCCond << ID;
       TV[ID] = MCDCCond;
       auto NextID = NextIDs[ID][MCDCCond];
       auto NextTVIdx = TVIdx + Indices[ID][MCDCCond];
       assert(NextID == SavedNodes[ID].NextIDs[MCDCCond]);
       if (NextID >= 0) {
-        buildTestVector(TV, NextID, NextTVIdx, Index);
+        buildTestVector(TV, NextID, NextTVIdx);
         continue;
       }
 
       assert(TVIdx < SavedNodes[ID].Width);
       assert(TVIdxs.insert(NextTVIdx).second && "Duplicate TVIdx");
 
-      if (!Bitmap[BitmapIdx + Index])
+      if (!Bitmap[BitmapIdx - NumTestVectors + NextTVIdx])
         continue;
 
       // Copy the completed test vector to the vector of testvectors.
@@ -437,7 +434,7 @@ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
     // `TVIdx` starts with 0 and is in the traversal.
     // `Index` encodes the bitmask of true values and is initially 0.
     MCDCRecord::TestVector TV(NumConditions, MCDCRecord::MCDC_DontCare);
-    buildTestVector(TV, 0, 0, 0);
+    buildTestVector(TV, 0, 0);
     assert(TVIdxs.size() == unsigned(NumTestVectors) &&
            "TVIdxs wasn't fulfilled");
   }
@@ -615,21 +612,12 @@ static unsigned getMaxCounterID(const CounterMappingContext &Ctx,
 static unsigned getMaxBitmapSize(const CounterMappingContext &Ctx,
                                  const CoverageMappingRecord &Record) {
   unsigned MaxBitmapIdx = 0;
-  unsigned NumConditions = 0;
-  // Scan max(BitmapIdx).
-  // Note that `<=` is used insted of `<`, because `BitmapIdx == 0` is valid
-  // and `MaxBitmapIdx is `unsigned`. `BitmapIdx` is unique in the record.
   for (const auto &Region : reverse(Record.MappingRegions)) {
-    if (Region.Kind != CounterMappingRegion::MCDCDecisionRegion)
-      continue;
-    const auto &DecisionParams = Region.getDecisionParams();
-    if (MaxBitmapIdx <= DecisionParams.BitmapIdx) {
-      MaxBitmapIdx = DecisionParams.BitmapIdx;
-      NumConditions = DecisionParams.NumConditions;
-    }
+    if (Region.Kind == CounterMappingRegion::MCDCDecisionRegion)
+      MaxBitmapIdx =
+          std::max(MaxBitmapIdx, Region.getDecisionParams().BitmapIdx);
   }
-  unsigned SizeInBits = llvm::alignTo(uint64_t(1) << NumConditions, CHAR_BIT);
-  return MaxBitmapIdx * CHAR_BIT + SizeInBits;
+  return MaxBitmapIdx;
 }
 
 namespace {
diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-const-folding.o b/llvm/test/tools/llvm-cov/Inputs/mcdc-const-folding.o
index 4f54fa7b8a1a1492a9a455bbf6fa651844345c59..7a16162f29c00777d9a05f5fed1cc4cbf333c56c 100644
GIT binary patch
delta 5899
zcmai04Qx}_74|hDF*Lz(34QTOe!MP_Zf1!EB!NI3^V208h=$*kUq2ece}2FTA!&#M
zH4AGy)jC3}v@*q-rh(Q;F-g~IQmY_3+D at BV5TmH9T0C_t6J;YJqNS~tedqeV<i_o`
zC%xl)&i9?~o_p?n&+qN$?ZeO8UnmyC(MOAOtH-9=a7D&K52#^W+_L-LiS8;F_UM at s
zm_N=g7X9Ml1T)R|&aG({+ukp(3_GMqzlgRxOy3q+`EhYxT=}bG7E50|_1WaqZ&0ns
zwZ}#Da&Eow4QaxYOPCM_>C}BCqJF|7qV=1TLsie*3uUQLzlcw{l at _=AhRzH6yQs-f
z9_GydABzD*`|Pvl;x{susvn=yFEB^zc$IdFrR7XV>(YJi^ov{bN!Sazzsm9rjkiKo
z7r7TI9A6NxBxmwU;&$GGN$a1;9G_n9Q!0sGnc|$G$fxeJb`gcs3esgm?DUH%tGmY=
z^EGAh*5<49I95B>nw?S_nlQ27<9l~6H0e;Fe_th?7g%??Z-(sE_#AXJZH_&zTFLl$
zD<4d at a!hadKhxIdl&Rcs79TJBr4`?D+PL-EXxp4*P$YvmXa2aX<-AB9QI#6G;XFO$
zJdMmy?p<e-JiQIhFD~45cFS>c1Gqm_FxB1N3nD9u$c<2iHiP)O+#ktPAO3wBXH`GD
zkc&iD>n2s5Cgr{^UC}HRJ5;DAeYO|7 at v5l0@^O`8DJxcwT~bVhRY at w)JBwaVH|9(}
zCo6sTBDVw1)0bBI#v(T`cq^$zchXC#bgE;CzQ)OW`PJ0Gptiv)dh02evH1Va7r64#
z3P%wQWjt0Ixt(%c#;5Szj at +nnp8j3G_5$f$LEmxAllx+$I>$UQg-$xwz+RJf&NLpk
zNqb4!ho*C+LE7I;-zd^3>w(>{t<rud?aEA!{94*sSv>BN_HWXzp23k<q|I~kI3n$B
zX*XnZ<aM?KMXt(BQAB3m8rXQ=T<Xosq>u7u!xQ;4#R{60Ux{&T{#>z!j=~mEEWdKr
zV%|es*|>*<9NLO#B!A|kYm$ycZYsoztpN6=iZ#)^0*}}{u%;mDbQP(jH`8sl2W at s+
z8I63`aPL#mGWFY`&_42%81A@=TDhePy+*Y_r>kkK+&`iJtXxGsB}PrHRkG6fp+ehK
zoD1bEsN%m>@wLgYZIOy+QUY`3*^}WSh2Ba_&b5qOrG`7AP^$@N6nd2cKxa&uoV!M$
z^QooO=#D7VnpY_FeHFL1;RE=*Iu~%htV#w{yiCQd8lF?}NJ at N>ieF8}?Y5?YX}(|D
zMGnR18}5RnIOeh0GI6V9TL~rR8)6B$78qg`TlW@?=~8SC?V<qCCJlWE<1fdOS0}YV
z;aO>aN-;2ht}!3hnCIv+&_N9?)X<A078>q%H8fvC|4hDxhWJF<`(%PSRqZaX>k*CV
zq$rpLbOE-6t-DfV7HiDqGy=3nL+1hgLal2(dCCm;4h>xZGzT|dO;iiCQ$rUaYW3te
z^#J{G3OZY6+H9vO4m6g6^4{?E3MGKPuAz at 1YAL@*u5v>ROZzbe%8kI?6sDz<p-wRW
zEYTF4T6{UjDPBI4UM|mc7ivhgmQg~N%h5#*eOyCVlBh7;t2A^qP^(Yd$Op7O1+~s#
zh)kei4gG<p+)L34L%c*6U|(kI9?+QlbXhtVX$0uI8v2B$^FDbN8SalXbdy%$9jaYq
z)O?zPTFM!Cw)kRr18!>{Tv~jq7N1RV%;nY4%^F%p382*)Y67)-wUJzl4Y8d9u#If9
z!Wwf2buE6F!iyaOPZ=1$V(UJyF&dy{)%^xt26{z9>$N&QAW><!|DmD#wK_f}U!_s=
z?-bNho~{Pmk-eH`juvm$;*U at ibCqalqlPY`3qV(CXe&^wBU@>t(h&9JSz?F~TX$Gv
z9 at cbvsTQ1<s0a3Cw(bFq*#V|<Z5JuN#K?MAL)$5DsX?DC$rS%0*HS}#&bCJ2--0h*
zX9jL-=QFf853TowQ;YL6Xz at MNvea<T)zIl$)<TM5#+A~pqRU`z{4dOU$qBJ_AJ;fe
zZLU)!9y7!l^1+^C>wZ;Za#yXY-k>PZH#O9)RrLqD0Q4^!%I{)prMJoBH^hBu$EX(L
zEOJ#DBA0snhC3hs=zMYC^eivM!K{$hPYEzrYRpH#wrX1^)wWOon!DM$+cc*B1`ksU
z&{G<!zrmvv1NsvU)o1w`&*DC>p$kxhb at Hx~2;iNeP(CcrX%*fjU%=@8T+3aqq4K!E
z=MDsLTYYozF~Y at h{ry^)61QpyXz|C9WA&#t8K<`bE_YCIxWcH$X`&I--=-<(Z>f{y
zS!TG;YN-B}dW~v<zNIOj)|9VN56};_T>WVuq4+Yxm+e3TE?%krwCAfhSNkGvYen9H
z`^z$>iZT+_6CaQ)%NL9A-A6v4)(0e~^JSse$OLMAKn_W40<EGbQ0oKoW(wLy7l2xy
zi`m*ADywJG2vF;Du_6UsMxL69&&6O0dX;K{TAz!(Dd>Fa;av5i?N349r#MjS<M4V4
zioX)hRj)DG2GnYG<LZFx`%Z_5lV|Ps#B$oZwtQOu{N$?J>D=0K8s3mYqiemQmptqI
z6x^6Yp><wyU3$atM&T7xY(20|z}9<3yYz<Pjlz37iPZty;Kh^g+32TXc%$(4NH6##
zu#H~vS`vdd3eQ2YP0-v7Y?D_sOK%w7D7@=QYzweDuc)F}9W>#M!aFOy;8tKydPO#Q
zHUon<3a?#y!EL}cd+}`~F?gf!s>!nj^KA#V#Vh)yHw<qSUM|J9`l)XRu&rJZmR at 1d
zK{vNnh at 0%826LNVJVCK-ekwGPwT;)qUZ3fpJ=-g$74nBNuAOvlUAd^E#CAXTbcY`u
zGIxNtGlvFuc*Q6s;1xcVLkogl at fn#xKd)k^A6-rafz$&ry_n0aUq^!&LCf@`L(Hio
zb0 at TRL2D<k!ZeZ5fQ+ZO9_GC#dA*c)3dn9C_1q<MH?%OyC9}aVO3Aa!55BnzT6>_i
zi+3OauW&Ci8n~0pdqMJUQlbIKJ|Mfj&}UvByg_)^CGU>pL3<C7{Xq73F-KzmI$E&T
zi#NTwSN0CJni6}Vbr4$nywFc at 2E0LdFG^lN#lUMPb3c$qAp5=4cK~~_r-BNbkas|K
z?SNktlBdy+^N=_I#bzJ}y;RtU-8fi5eeeel@(D~Fl<NTVI+=~oYyr{;&88%?@DMVa
zcqPoVk*CFvvuU=>q|qkm9R}Kr-xjbBucE<bK1qpYxgTI+Z7t9YL9+##hrnt^ovp|^
zBzFW%oI@~C$syF)2IMgGLSVK*?=U}IW-Ir{6Y_HpLeM(`y%6+TvF;G`+L6^NI|SyC
zWWG&_R_GlC(gwXF&^rpfHh!|qcDct#{CvKSK(7OON1)dZy(7@;L{_`pWib2517<NL
z+M)L}kfYG+NHY824<7a6DPYZPign5}*a6KhARW-`1hWI0$B@~{r_}@p&k$@cB|4$m
z4diKPb|sm8 at CTpfHwQECNakx~c0n@?qzjtIzznaV1;^y+Ip!BZioxEb#4+d{hh8`I
z!eDh_ui+1N^P9m0=RL{HB{K}Y6F|by>p^#pqsC{D*~3pk;y6Fku^xFMd%!&Dpkij6
zkW8G+7#OG at wqNqv$vnZmioxEY1ngPzJi}uX_A|*jO9_lC$P at 7kKbf#~6q7aqd!0Nd
Nd0$LeygN?L{SRp}gY^Ia

delta 6068
zcmai2dr(x at 8Q*gSVHI6K;BrwBf|+1?Q(YBVFtTid5u!Fcd_Te?%0qmBg0dKetzsb6
z8OYb9WG0zNr)kr)X;@7<(SNc`G~&c*HBB;UO{daHGj at oRFt!X!?9ku2dk&m#)AY>T
zZ_oYxzVrLO^WAgKy>RP{Hh4zs&SZl<i!u|sf`t>2Hnfh3rYO<vsmo^5dioZ_+?Y2{
z>u2u?qM!L$$3(MT-1;?|$(BYqubyK)eF<7~GBrjfFFnV)20r|2bRrj(1KVfuJLU|$
z_igdWGc6%oXr4oWrZjOQe)3O_Hq8-zq!2Yc!x`|i;Rt`EGe9G(C^Cxo$*rZdeMhnp
zAKr?#W;!*W$(a6#em=4L{xhy0YKYxDQ^3xv&OrFg&Y>jM*kyMe2O_CCa(><aAJj2A
zIYmDrOf)5g1&$onoLBpq%$V10M7UtAd``S>)H*GGCYQKB#8X405p5MI!q4aqn at 1l_
zbGBIpat6+^@bs-GI at +8n#QhPFYK{%dMw59=RZfhXTnXP&Tv3_P=4FM6p(Vzv%=I&-
zQceAinqnjtRC;V^(9}a9d*p^TS%Z$7j^{D2sU`P*!9s@(&%#=9)sDk~YR5N&cO7lk
zeaFqFEHSzKXS4X4%y0i)bSH)s{%94yof<eb$Ukj3dCFU}yf=j0omV~m%=6)`g3!vE
ztlO2)g4blMPAgVnmlcBx at GKd!$rX;)J>Ncyp0yHfzZwzB${IMlO$dd&Bc%5NyYyys
zdisL0(59Qr;(f901kh<I7j{{aG6@@!khNUx9PPN{aXkP2YUf19O?0kAC(`Yx49bq0
zl`H2W2V&LZFt|B&7)1Q{@X&gro~ZliUX+7UqGvv6>$vkB at jP!qwxDZ-FE~Wb%R-1d
z-xk7or{iY6<N3=|d!(Rq*Fs0vR|Q?8x2ZTf$>9tXp12gd-Lu2<q^Er6d(;{I5VO&5
zqo07CZs&HBWq)qjQOiCygX1q)_KO*t&|fvP2KH6U&WhpvX3PHBva4rt<PFOv&gT7N
zmi?P$*E=}!wq at tX@_vV9?{Is5W8BIZmQFqMpI{j at H2(p%l<cVw0CA?yVQXl0>Pp}~
zAnWOu7JegjWul9(QM6cG0cLe=8I-<Y&Z7098;iLu7>N~tyC<-6+PNT|J$}AzL60LY
zT at 1Q3-DZooX||=5zF0S^1-e4~whHzoDgpb3Kr_Ve62V?4AJ_;HW~pF5#)-?7SCD_P
zUbIHAGVU{itrhqhF{(n~ZwkCr;5h<k6t_e-;<XSgGZ~Hu#mXWN*cQRcBD^fv%hU*V
zLa;KECj^^DeM|JVgVRFFGA<MBC4tMw at F(2!+1(R(hRE~0z!zW~Z!(9|0^b{k=Lq~l
z2-j at o=X0FD&{z@;Ez=E|BTqR7ml$mO9>p!!nTtHIh1?pOc`!8Y8HbB|^HxcXVCzFS
z7Mq0ry@^meLVZwp#<D-58}NKZ at tmu8zDg`hH~JMeO<~_9C)leBo2sy%P-T|RzOd|F
z>VfBk;>jx~^Rd$aJQHaI_I_>+r&tGkUYUw#4yCWq4Y$HR1oj&-uXR)ccC*4R2b+M4
zw at UJXtykC_pfZPp<Okap#?G at w+H9w22<&rVtgQCy6ql_V=M*+iQNB!`Y at K~<+0Upk
zTQ8E^mCufQN*%dnIsUMs5WxX7{_`j<nez;~fw+kZTd1%LiMe#+`wIJ*!n()_)~&F7
z&B|I8Qzh8VVXRz-HPi$4kixE2l#kMYOJ`?j1omZajh`u=e1}P$w<tYFHv$S<tmq6<
z3D`d<EMM(1!y)qJpps#%R320Cjf!Rj_8o7W-hoS2(m_LrWhm at 6h0UP2T;0f0*h;W6
z6AyWEbyh@;uv at t`_9>p_icT~2!KagM!1i)$yrOvWQ&{HzD`G2k<6VW_rRZECC)iIE
zmhW_#&*xORQZE_~W2N#x6}(Q-oKWxv1)og=h?Ojc^SbR<*!yS%>@tOI1}igpl+qv8
z*;*=r-OjC1qj(-tbPkXYK0flp_Hb+TDxR(I6t}k5Xb9|E3frRSd_ZxlboLQ>VE at 8x
z(HDwml;ZiNg5xDKd4~K$!TG+FD`YzLt<nvhyQ1+r%)lktg>(ZEms{3NEKg^TQDvTP
zY*hT!6L=@}z^Bf#O_t}0|Ka%@4M68bg;mezpVA1}*A+HR$;xjjzoW2f4j)juTW5cy
z64<|UTlAIUnW5<XOTiyh at agyx;Eh)!4VNgLEr$HiOrasz2e~zzis$|ClqX&`#pUa4
zHTmGVo;>JpwQM;x=Ht6W8MPRrWVH`aAJ`)byIf(9S(+y;&0b<2yuTDr{+%Lq0^|hy
zd%^PT&nPV3Umm^aGi9s?tbEseuHfpadoK)^dm)7e5Ni=%f at nNeH!hipi$=h%QP}4c
z_6L;yh;BS7Sb26y<#s9o+pUcKu`>1*@`3%0!oHxeZ<GHKz37Uf%=f-j{#?P;U4K_m
z>s8d)`M5`;A`M<*-uMB_8&8;D)#NPHjh8rtb~5xc$-Y6AV6O}G*I{e~^?+R=Ua=pA
zv1 at 1mto*3F7skFxBVZX%0d1kskXgl3dJztH!LAEqTd1T+FS;z)rZ851RCb2pY2q+_
zDGbL)2Grz7<)tuIepG%MhRcu2FT?P?6!*B!E}UQVxFedqNI9izSTgxav+eE6LR0Og
zfzoVNOTkh%+d?^IZq`6v*w?In3kA_1v-<7i-Qd;=?UY-VhZj^3H@%^oZt`w)YqzZ%
z8Y at kpm`$eUngPdBI*o28 at 8;218JNwc{ZoD_qE(S+!&*8GB!8wv27ttDG3~ESBA$)#
z0TL_DgDM&T60_B`w at f0QP4EG7YYHjLrm;<kx6RZFXHo8EWP)!0EV_tp%yv^to=v%1
zfTG(zn=Yaov%}PG1KkRAhiNZ%$fP`6Y%9cen%X-K%H0MBbkkz#BDyh8VurDlyB#RH
zUjs!qrrhN9EO*;``A0XJNuC{R=^F4$6fAe+8$GAOZ66dYp2|TNi=&Gbc`TNK6>b{a
znLz6*5hk9-%kx+<U8r=kObWv0(}fCdy;W{{r#ykKRbdj`t(4Y1W%7pur?Zw*0|lRQ
zldBS1yG(YAyp?5iZI@}k9UsaHaSyoI94qcw^6rLU6$E#iTK*gwuYzE;X)l~J>3m!|
zU#DO-gm*!>#zZjhE(q7)$xZn-OJ5s#YazTF!nLMmOQ7-H5Uw-r(c&0E7JFSR!OCI@
z1?wPO1K~ZUR)K$J)s)h;J*K^O%K4~tt{`tclxv|}Z?XUdYs+ZeUei7(d^3sFO5bh@
z?uGCk2=6nsC5hC!2g2yO&^_+P9~Zp%0rKvLVm%c1o7&k#8m~vL2Qab3P!Tf8_mnH-
ztbJWT;|KD{wGWyNrWTt-t^1(aVA_-UYZMI$RAp=VNtSjRc^jd<AKHz0Vo5Z<AKC{^
zd*_sQy$gTg at kEL#co69}K>Co$z9w%23Vg`a#t>w$o9UKQJ9(R+*a*cY6icV^MkqF;
zSh|ewt9A+JehM~2 at emXbo9sGy4?*#;seP(b>j5_o1|Iend5=J`35rLs2$E^M35qRP
z1j$m7Rk?(7ECpMjco>Rall7DLFciJmCCSu!P%7q=w-t&<pxBD#Y|!`-C>}NKnTAyK
z)w!5qg>RtXQ7C$$__V2Y8`SDWLDB6+x7jVc&XV^SBwHbQ3=1lS##<qI+|;7cJ?zGJ
z1)s`w3Lb~n)6i-&wT2XGeHvPAI5|>eVE%B<hP-X$ZHMMDXtwj65<G^b<in8wNw1sD
zwIr8N&<DvjNdC~&isw>m8zj-)g6>i2RYBepkZOn22~!KqrS$kDiuFBA>rR^X0RK2c
xi?&wAU`V%{f+yW9nsPea%t77`x0X5I8g;!RlW%&!0m?bWOX`K~qzk7W_&3g0Q!xMl

diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-const-folding.proftext b/llvm/test/tools/llvm-cov/Inputs/mcdc-const-folding.proftext
index 82335a8195faa4..97d78a39f43562 100644
--- a/llvm/test/tools/llvm-cov/Inputs/mcdc-const-folding.proftext
+++ b/llvm/test/tools/llvm-cov/Inputs/mcdc-const-folding.proftext
@@ -40,7 +40,7 @@ _Z5case2b
 # Num Bitmap Bytes:
 $1
 # Bitmap Byte Values:
-0xa
+0x6
 
 
 _Z5case3b
@@ -55,7 +55,7 @@ _Z5case3b
 # Num Bitmap Bytes:
 $1
 # Bitmap Byte Values:
-0x9
+0x5
 
 
 _Z5case4b
@@ -70,7 +70,7 @@ _Z5case4b
 # Num Bitmap Bytes:
 $1
 # Bitmap Byte Values:
-0x2
+0x1
 
 
 _Z5case5b
@@ -85,7 +85,7 @@ _Z5case5b
 # Num Bitmap Bytes:
 $1
 # Bitmap Byte Values:
-0x6
+0x5
 
 
 _Z5case6b
@@ -100,7 +100,7 @@ _Z5case6b
 # Num Bitmap Bytes:
 $1
 # Bitmap Byte Values:
-0x5
+0x6
 
 
 _Z5case7b
@@ -166,7 +166,7 @@ _Z5caseabb
 # Num Bitmap Bytes:
 $1
 # Bitmap Byte Values:
-0xa2
+0xe
 
 
 _Z5casebbb
@@ -183,7 +183,7 @@ _Z5casebbb
 # Num Bitmap Bytes:
 $1
 # Bitmap Byte Values:
-0xa1
+0xd
 
 
 _Z5casecbb
@@ -200,7 +200,7 @@ _Z5casecbb
 # Num Bitmap Bytes:
 $1
 # Bitmap Byte Values:
-0x2
+0x1
 
 
 _Z5casedbb
@@ -217,7 +217,7 @@ _Z5casedbb
 # Num Bitmap Bytes:
 $1
 # Bitmap Byte Values:
-0x12
+0x3
 
 
 _Z5caseebb
@@ -234,7 +234,7 @@ _Z5caseebb
 # Num Bitmap Bytes:
 $1
 # Bitmap Byte Values:
-0x14
+0xa
 
 
 _Z5casefbb
@@ -251,7 +251,7 @@ _Z5casefbb
 # Num Bitmap Bytes:
 $1
 # Bitmap Byte Values:
-0x6
+0x9
 
 
 _Z5casegbb
@@ -268,7 +268,7 @@ _Z5casegbb
 # Num Bitmap Bytes:
 $1
 # Bitmap Byte Values:
-0x23
+0x7
 
 
 _Z5casehbb
@@ -302,7 +302,7 @@ _Z5caseibb
 # Num Bitmap Bytes:
 $1
 # Bitmap Byte Values:
-0x83
+0xb
 
 
 _Z5casejbb
@@ -319,7 +319,7 @@ _Z5casejbb
 # Num Bitmap Bytes:
 $1
 # Bitmap Byte Values:
-0xa1
+0xd
 
 
 _Z5casekbb
@@ -336,7 +336,7 @@ _Z5casekbb
 # Num Bitmap Bytes:
 $1
 # Bitmap Byte Values:
-0x12
+0x3
 
 
 _Z5caselbb
@@ -353,7 +353,7 @@ _Z5caselbb
 # Num Bitmap Bytes:
 $1
 # Bitmap Byte Values:
-0x12
+0x3
 
 
 _Z5casembb
@@ -370,7 +370,7 @@ _Z5casembb
 # Num Bitmap Bytes:
 $1
 # Bitmap Byte Values:
-0x12
+0x3
 
 
 _Z5casenbb
@@ -387,7 +387,7 @@ _Z5casenbb
 # Num Bitmap Bytes:
 $1
 # Bitmap Byte Values:
-0x6
+0x9
 
 
 main
diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-const.o b/llvm/test/tools/llvm-cov/Inputs/mcdc-const.o
index 1232088ee60fa0e1c96960f1ba11a0e7e7e982eb..915125370cb3d5b7a40bde18c50fd9b2f0e3ae5a 100644
GIT binary patch
delta 68
zcmeyN{zH9&4<pw^Upq#oi9H^SEEBI<GqOw;WHbSj;*(<;fr68lF=jAwZ{}xmWMpL8
U9LUVh!^kwbky(Co1%Cqz0E3|r^#A|>

delta 70
zcmeyN{zH9&4<qM9Upq#|i9H^SOcSqKGcrvUWHbSj;*(<;fr68lF=j9_Z02WjWSp$Q
WE3i3%`3E;6%j8C8`OOvl4J-h+&Jwl&

diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-const.proftext b/llvm/test/tools/llvm-cov/Inputs/mcdc-const.proftext
index 10253f26e0a680..16eba3a0180803 100644
--- a/llvm/test/tools/llvm-cov/Inputs/mcdc-const.proftext
+++ b/llvm/test/tools/llvm-cov/Inputs/mcdc-const.proftext
@@ -14,12 +14,10 @@ _Z4testbbbb
 0
 0
 # Num Bitmap Bytes:
-$4
+$2
 # Bitmap Byte Values:
 0x1
-0x2
-0x0
-0x0
+0x4
 
 
 main
diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-general.o b/llvm/test/tools/llvm-cov/Inputs/mcdc-general.o
index afe6f95cf0b829a79efebe9718d3cbd04718d4aa..2d6934989b900ddc63bb498d2173b8a7127757ec 100644
GIT binary patch
delta 1562
zcmZ`(TWAzl7~X%zU1xTanVr34G8)?mq1jR&5>O%<GTG4JwzS3AhejK17lP?Sv07FU
z5shXj1{%ovSz5sd`_LlvC262^9|~RCf+dBxLd!xB5-HNM6e2?U5G6fl_DuI=!2|ho
zzRQ0*4EudgwP!X%)#A(j`$`lFg}miLEVmhEx6pi~mJ!!sZ?kYv+y~9?ewk^>PL&n!
z$HGh4LtSIF=p5Z&(fllL+4QDab|cgDK5gL1R$f{OS}4Qbdf`%l)Isl`!fAo(&Umq$
zy!^!c$gh3UJooEKbEEvkyzJu!-{5NF^~A{%@5BZ_yQ6loPLWU5PBn%Vtx5*7^4 at O?
zBH&HG#P0R~moLQ`!`|qXEki2!jdtax at 0R~kCs((BOZOk<X8b+1l$M+NS$j8oBKzL)
zpAK)Wo}2QQP#Rm*w?nUzHmA2VcpqcRfsPH|U*F|w at CJ3*iITE6zS(rHt8dbFyrqs)
z6bot}wW6l>Q(_^r?HZAa`S3C=VkXj&`htv1*618E+J}sI*3gEHo at 4kSvNKv?>xQyM
zTv=Lp7<oZqcGA1`MgFC*Q$epj;q=x)NMZkD?5{)Me$4B(lWS7D1U`;crcOwz&hAge
z2B%;}ZRf0{s*-vES*Cs>sdDaTIK$MhB$ZF~s=(jiXtZ13D^MAgsGVPG@{S4oyTr>K
z9!NZ|{f5AQO8ho<54QQ+pZBq(@~jU9COnSWd0o6|@QN3Ontl$yOXB%#8{*}9n)qOb
zArxaay at q_uc8*CNK1t9k&nIy{Zc;rl$yMxb>BjAtMza`cv7OH)AOA9gPG92+Q~h5P
z#`1mSw_Cz|i%oxEm3baW75E&%4v)A>>%Qk%lc$UM_)(E<wJC-(t+r$FChRo#%HT`p
zIq1hBRM`D>^cuEvMDj;iUNHHnUo-D}CM1tM{}sR54IVLTT%*MW$NZOAVaqy1w{X<z
z(?_|Vol)Gh`e+3e%cUx;gsZG6IFcA(R59VwX;fIe4J+v)o=9OlxktatKO1&btcG92
z`9vqG$^CQ>R?4LhFv8*-iYXWOk{YV1{d5Ob+9eGmEZ#wp#W~-#0;|nc*TNwbwKUek
qahz{!Ck4eemj+N_ at f}#UOQRUET_tYfx;;RHsMszJr!};<cm4;v&X1D-

delta 1631
zcmZ8fZD<r{5Z>9noV%CJ?tLYDS8a_{NLoUgrIx5@)(c5J at q@N#p`wToKMJKy+G|M*
zH4%@ZlxuSxXiNWv;*Ua=#6XCDG)HSOKl<Z>wg=~rC=`?+%^_-wmg~HGv$ENNoqgw-
zXP%jPcPl+}JrkWUSA1#Pm^u4Prl5b3pU-L8LX$+c{K~oO*}8kon6rNt^te{aFXnbK
zw!@sgR?tgS at ER9n>(aUFrMt at b?KPKR at lLkTB4pI0$`#qdb^+WKZn<qWHS2Nn)!e(x
zAI#Tt!+aiZ<T<hz2J??{M>rCb(Cn}8$luTHF8;7_jPd0yjVciI`p3`RJ41~dkZdn3
zk50kjlIrfq1($&cLgg?6{G#=LE9irQD*8GM)2Q8iTqRY!*o;*$pQkIO3tGKrV~zc4
z=o>lNf5vStKQKRV568_L?)!l`=Du0GF|o$GtO6B$Ti*KOCkwpPaq~%uX`Tj$__Mqz
zLF3Ex2osA6!xeciNZ6+gfs8*Yy`W%K*#@DRROl=~7$=*mP{z;0>yqDr(U~#Y`;An;
z5zQFtpwV*_FND`dDnch?MCCtb7Q-*dM6anGTA4dkaD#Rt{i@)QiT2I(tP=rQA5Lmk
z`mILrEW458AuMYae1^q{1$l&smHyJlROtM)-mnR at iF2Nq9XK3OcU|@IM85%!ulaC|
z&i`@!?>=1cH*s9WQp6hjJCHrZ at xMM?sIgexyIpVFJ<MCfcOvi*J>K*>;{r?i at I(WT
zKf9P5C55fU+szhq3vX}tiTZ~a at Zn-5ul4|*Znn~g0@?RmT}k=~Gr9$*@EyHl15>20
z1Kc6zev6a3l|Ike;P6+ltXuX?Uu~4?yp?bHa53EzzPrB=TCDVaUpDNkdML8+6pyx8
zw#>h>c!|9|1ucMkpE!m^QnmtF?~`?7iIg+0&ti?vZ{VATWgiUiy)MTBxYy-<QI*aG
zvR;?3T>VMmamqLg<(Vz!V}O^@j_rh>@Y7hYc2ev@)`^#6y|99{n1jQKBo4&8WJ$pf
z<9)c2P;oB48OE^|cVG(bgaiNJNW#%7;v<lSvD~yCE6H{oZPhW9?1Ck<lMamH2>A(|
zCLhHb`8l*(9qdV|#N15LbgKjNE^8j`Hb;@d5}sCDaj7Ya-?yb8j?--p?86%Q6KGow
YoWv3GE2NpgU#%`^#~Q_*Xs0^<2Ph|{3;+NC

diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-general.proftext b/llvm/test/tools/llvm-cov/Inputs/mcdc-general.proftext
index a83f036ddf2c94..2faca9da1b1e0b 100644
--- a/llvm/test/tools/llvm-cov/Inputs/mcdc-general.proftext
+++ b/llvm/test/tools/llvm-cov/Inputs/mcdc-general.proftext
@@ -24,14 +24,11 @@ _Z4testbbbb
 2
 1
 # Num Bitmap Bytes:
-$6
+$3
 # Bitmap Byte Values:
-0x2f
-0x8
-0xb
-0x9
-0x83
-0x80
+0xef
+0x77
+0x3
 
 
 main
diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.o b/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.o
index 667ccd132d2fb848ae86b9bbbc72f7b3a917feab..8f458b962fe9ba316297da6b6b50ce72162c5d58 100644
GIT binary patch
delta 1280
zcmZ`&Z%7ki7{B*6*G;#(+q`)<D4qBrF)Oz(ZU$Z_h<->&k|?6Thy;mkvce$zlbbZm
zNS+`+R3t>7U4vi{;^>Rk7d5aV2>TL=7!G3z7VCL$HyaBdcz?I&{r#Tb^FHt0rhJRO
z2eqsyPS({*r%%P+Yq3o1PkXk6!H8zV9h1ST)+CEbU_E@$*f$<YlfFGD=5r47b(eR+
z$XlZsAu^78qYLKPJOqg}WH8 at xlR-M%za?DPTlEMx7kY%9)UcgW+?Ft;Zx`yL8$#q2
zlK)C}bWL6x{VYW0kxwcJ?Grk;e$jB4A<L^=$zf!eTnje35$-j}B%u|#nT-cddj;l*
z%Q|5`K5>FL2ixEasXQcc27gYwaDI)t?M}N}c;o44O32MyLuGID>-*3C-CB1xo9#IQ
zes-2v;TNkB8w5-~;!gCMx>@*G;wNTsSb`(~cPvesADcDMju<QSz#1>M at QTKJM$Pw4
zW31^m;guF%)OfCy_w?m|BhN4r%6k*`eZV^PQcM?dIT at DOB=FMOM=GJZR3>%MiP%KZ
zt)YMhefRXG)YAl`6Go6dlS_8l{YHKj;>ZpZu{I-r1YePzE at I6_{sJ6jvO7`4b{Tm}
zuYJ1*y9A*!nXFI;@(rfZ=SP8(eyG3kwrON^wv^r=Mt-_TE at jGr*kp15s_inV(eWrO
zq31EUY?IwBMOBZDst%Y$wyTJ}XRy~Gg`Ok2+c>0A`Or|($z8beXM3V|d0ym`?=q`9
zEK`m5(;k|i1^dndXAU~;ADltsM09GpHc6t1&k!;OUa^gca7%2ou3B at VIY^3)<Rqj;
zmEE?0&(TaSLCB#J2I7c!A&tm^*Qt^qgb=47jwnJJ at ilnMRiZ!$aSq~$^N>b-23|>p
z8HWTBsou)z|51i9gJ!7$#p!`<$&U_R7p)2*E<)U;La>~JZI>TAdn;7Z4k1K51tJIO
v3YBGe at X5`TkX3RP;)wl_mR0M3B{$131e8X$froyjnG8T&QDIX;PsQ^WqhlLQ

delta 1379
zcmZ`&T}WG39KYw}-ZWRuz4@~D=0!7RX(B!t5mE=s%@u8h%FwM}w60YvZu+p*5(*oo
zb=Z`~VypZs^sNYc&_2}(8+%yEwFMg}MccxJQgE=%rlAi`kd1cB{^#bzrn3FvoO6F4
z|BrKXv)pvEX);V#)v5Y$%~A8nCtc|$W_qimAPE at hzuTjQRKZlImy%smgS8i<nU=gd
zoiQicmORNl+{KS*7PVW}gm~pbC8zSCXl7e&Pi?8w7RkyMd%AR$)qjv)v|c*ub|t<i
zX)E#g_l^m>Z^G3~dEN^)2PP!HLZY96Q8(LNo9dUgcThc-9aLXio9aay+X<;x$<uEQ
zuWg}Zh-OmH>^pQWiAjTZ%%A7|V1opX7h4dlqHy|0f<5yzn&p at u{C!w!l5CA-X-htN
z_&*G{GS-?XTP^tuF_<Ma`XQH8a*f at 0oiI<Dr#{VLeV8ZJDigQadxH?BcZmS&)FdKA
z98E-8=y42CSQA~4k at gWc{3V?s`(W7lL3an%XvD>0oegX%o>oO~RYIl`HkHOP>6&=m
zahW<62*V*;^O%aOU1>b=E+Ygm{rtjjPM|)!6vAa(K7k4Xg>m_dU at bxxNC@mFc~dAx
zGk7aB(q``m!K~1Ny{NJ%Ih%`6_zXr+{hFhaTE}q;W>EdEOs&M{QkS1#1-mRlU!~Uf
zsLaDA>EZZk8P9V0fQ9E}Jo9&Q{OW)BKUkOOKReVU$4>U9G1&YLT%`#Wc&|z$?}JsT
z1slpdtRs87EIxz{RQH#u<#T>)SLg at Rt&t(<uF`^IWlmP-Tf2%NjKepm&g at WcaP<ef
z%i<1ofU7I;3(ong?Gf1}FxcV4Rl17~Y4^{*QDj&!)i%<Fv&t4BAHk64013goCnmcp
zY>Utf8=e^Hg^1Unp<OWSjgvDl=QUt95P&z{267W3K7%yE5bmQe=QHG4v6xy1^WGSK
z(h<KwABwOd?uJo+m?U7%Z;)lk;l2uyfI&WoA>6xQE?~&I{U66K5k~wmattEXh8*VH
z9oX>4=&A(ufjIWfRkPH{ZiDL1?dmvOk$CBk(~y%{=>s<mYjLU9iE}}>*AE#jOhzE5
i8Fajunb5=XB$F{FVMLG7KizO!kK?d8o!u)E-1{#TAWf?P

diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.proftext b/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.proftext
index 35ecc42b5802a6..44057ffd7d885e 100644
--- a/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.proftext
+++ b/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.proftext
@@ -27,21 +27,12 @@ func
 0
 0
 # Num Bitmap Bytes:
-$13
+$4
 # Bitmap Byte Values:
 0x0
+0x9
 0x0
-0x0
-0x20
-0x8
-0x0
-0x20
-0x0
-0x0
-0x0
-0x0
-0x0
-0x0
+0x1
 
 
 func1
diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-maxbs.o b/llvm/test/tools/llvm-cov/Inputs/mcdc-maxbs.o
index 8e592cf6563da92b98429e83244084649d49fd81..3aee8e5e4489cb55a322385b9b90c570f2d72c73 100644
GIT binary patch
delta 680
zcmZ8eL1+_E5dAZM&32RBWLMBl=%r#YMHJjnn)I?-5y?RiJrycaJ=ufMuF#?gD)FGA
zP#MJD+T$LzLFszXNDHaAs234Iy;Z#FB}ieN-TYv1;Qu#o-kbS<_pgjDk1UU&Z9G1F
zbmDA1-Xl0}Tgk2|wgF5wdo}PrM3QO!QEIHm;(mv&f_rN`s~p&fr-HU>eU-E};+bpt
z$oSXw^QDr#R-~ndOF^hgQ6??iSb7=_4RqX9awEo at rpkY?F1*&JcyQ$l{f24C(iuDt
zvbl;5P*>X2l9yqU4r<=Mt;EY=^E#GhLJT+Ov^P-dOE0**SD@(gVVcUc;S}A`UARaG
zc%P%U85b7mobHw$sv*dz^E#sVlf+*N|5L{me@)L>Z4am>=euz)KGJvHEq+pJ@@EPI
zD%Fj9u+ at BTtO9=4Daf66zA9 at UG<ugSXT$VqgjfOklbgUbNfpzF5n3>hV<>6e^l9E4
zqOMspYRUCEM(Mg)#b=TN%Qr5lB2r{kaYNEC%g0%yO5Vp1DPTCE(>lX8YYaO`p4?B{
z));npM8P+9)Cij<^HuEjn&x$?*gn?S!f=vrV*4;dUZG4yrwFsOkT27;Q^Ym?I>*Nj
MAHwjB4{;9t1w9d>oB#j-

delta 1144
zcmah{O=uHA6rP#Q-|nVOTdixPP?2CmtThW_E6BE9B&a>82M_U*OQjXTG^Gt%NMt=!
zA=37N)RTgOl9MGA8!t@|e}V^#y@<DXD(%IJcu`p2?9P^LE)MLz_rC9Y- at KXK`NK=G
z`8YeME+mc*jHWC<!BuSI?~tfgDHd-XjOvY4$=2v!7Up^iQwkLfGp)0e4bk$3x0qHs
z*Iwmf(XzcFXuYO4Oe+(Cdg-D}C!e|SZ_~On5?Op-3h(3|x=qEgv4KeMJ+wh1XFk1V
zT5NVaWsTaS2-LJrO!w{Pr)MsR{6DAZ=Eiz0WwC{lcBAD$pLYGyxqbFUhy&SO+ph(!
z*Q(BmGm|d_RF%-yv~JHla at tfre#vPoVonJ3(rc8$EWJ!g<umQ1RDveU(jmAa>D}*a
z4Iv#ElOq3Cc`U8bs7tLN+(j5!cWKD_KhR-V4rnwDm+*ZZcKjNhg1Z4N`aq}{#vnfZ
zq6V&ymRs19qF#e0vKt;YjQL;7Sxx8+YSB#(%bi{J7u5Y)f$*Eb<?g%RDM`SC^UwH4
zc(!|R?&cHvLmu3#k9lye?-6>#!3*}ryulsoyr;oybk&1%qnI$d*@C+lH{F7}8{gl9
zA0foO%jbItLe7W{U?ez4*DH<S6Ux5JFd?7oEDNbnkPfKJeM&yy)awj>%BR>ZA0!lm
z{(y01nB{#?Rt#2Su%#Gsi2r at KVvtn^S<wd*sv-9aP=aN3kj?pEOEp+hf<)M0c?l*k
zq+}>#SV9iNsstH!0BUNSJw=N)12)wT7z!uZM at OEQA<=HI5Rw?Wa0Cp;e7tKh5@$&q
UFk-NmcqR;A(Hp}n^o|_;2mF=y4gdfE

diff --git a/llvm/test/tools/llvm-cov/mcdc-maxbs.test b/llvm/test/tools/llvm-cov/mcdc-maxbs.test
index bbb5fb8b6059ae..15f4e4dc481f3a 100644
--- a/llvm/test/tools/llvm-cov/mcdc-maxbs.test
+++ b/llvm/test/tools/llvm-cov/mcdc-maxbs.test
@@ -31,7 +31,7 @@
 # Instructions for regenerating the test object:
 
 cd %S/Inputs # or copy %S/Inputs/mcdc-maxbs.c into the working directory
-clang -O3 -fcoverage-mcdc -fprofile-instr-generate \
+clang -Os -fcoverage-mcdc -fprofile-instr-generate \
     -fcoverage-mapping -fcoverage-compilation-dir=. \
     -mllvm -enable-name-compression=false \
     mcdc-maxbs.c -c -o mcdc-maxbs.o
diff --git a/llvm/unittests/ProfileData/CoverageMappingTest.cpp b/llvm/unittests/ProfileData/CoverageMappingTest.cpp
index c5b7c26bef9a7e..fcfa65f6e29e1d 100644
--- a/llvm/unittests/ProfileData/CoverageMappingTest.cpp
+++ b/llvm/unittests/ProfileData/CoverageMappingTest.cpp
@@ -872,7 +872,7 @@ TEST_P(CoverageMappingTest, non_code_region_bitmask) {
   addCMR(Counter::getCounter(2), "file", 1, 1, 5, 5);
   addCMR(Counter::getCounter(3), "file", 1, 1, 5, 5);
 
-  addMCDCDecisionCMR(0, 2, "file", 7, 1, 7, 6);
+  addMCDCDecisionCMR(3, 2, "file", 7, 1, 7, 6);
   addMCDCBranchCMR(Counter::getCounter(0), Counter::getCounter(1), 0, {-1, 1},
                    "file", 7, 2, 7, 3);
   addMCDCBranchCMR(Counter::getCounter(2), Counter::getCounter(3), 1, {-1, -1},



More information about the llvm-commits mailing list