[clang] [llvm] [MC/DC] Make covmap tolerant of nested Decisions (PR #125407)

NAKAMURA Takumi via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 2 04:22:41 PDT 2025


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

>From 06d0d51dce35916ebabcbb219c2d868df375e601 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Sun, 2 Feb 2025 21:58:41 +0900
Subject: [PATCH 1/2] [MC/DC] Make covmap tolerant of nested Decisions

CoverageMappingWriter reorders `Region`s by `endLoc DESC` to
prioritize wider `Decision` with the same `startLoc`.

In `llvm-cov`, tweak seeking Decisions by reversal order to find
smaller Decision first.
---
 clang/test/CoverageMapping/ctor.cpp            |  4 ++--
 clang/test/CoverageMapping/includehell.cpp     | 18 +++++++++---------
 clang/test/CoverageMapping/macros.c            |  6 +++---
 .../ProfileData/Coverage/CoverageMapping.cpp   |  4 ++--
 .../Coverage/CoverageMappingWriter.cpp         |  9 ++++++++-
 5 files changed, 24 insertions(+), 17 deletions(-)

diff --git a/clang/test/CoverageMapping/ctor.cpp b/clang/test/CoverageMapping/ctor.cpp
index 1cf12cd738c2c..191f73f5693e1 100644
--- a/clang/test/CoverageMapping/ctor.cpp
+++ b/clang/test/CoverageMapping/ctor.cpp
@@ -11,8 +11,8 @@ class B: public A {
     int c;
     B(int x, int y)
     : A(x),                 // CHECK:      File 0, [[@LINE]]:7 -> [[@LINE]]:11 = #0
-                            // CHECK-NEXT: File 0, [[@LINE+1]]:7 -> [[@LINE+1]]:13 = #0
-    b(x == 0? 1: 2),        // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:19 = #0
+                            // CHECK-NEXT: File 0, [[@LINE+1]]:7 -> [[@LINE+1]]:19 = #0
+    b(x == 0? 1: 2),        // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:13 = #0
                             // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:7 -> [[@LINE-1]]:13 = #1, (#0 - #1)
                             // CHECK-NEXT: Gap,File 0, [[@LINE-2]]:14 -> [[@LINE-2]]:15 = #1
                             // CHECK-NEXT: File 0, [[@LINE-3]]:15 -> [[@LINE-3]]:16 = #1
diff --git a/clang/test/CoverageMapping/includehell.cpp b/clang/test/CoverageMapping/includehell.cpp
index 09e03e77799d5..3c67672fabc0f 100644
--- a/clang/test/CoverageMapping/includehell.cpp
+++ b/clang/test/CoverageMapping/includehell.cpp
@@ -28,14 +28,14 @@ int main() {
 // CHECK-MAIN-NEXT: Expansion,File [[MAIN]], 6:12 -> 6:35 = #0
 // CHECK-MAIN-NEXT: File [[MAIN]], 6:35 -> 10:33 = #1
 // CHECK-MAIN-NEXT: Expansion,File [[MAIN]], 8:14 -> 8:29 = #1
-// CHECK-MAIN-NEXT: Expansion,File [[MAIN]], 10:12 -> 10:33 = #1
+// CHECK-MAIN-NEXT: Expansion,File [[MAIN]], 10:12 -> 10:33 = #0
 // CHECK-MAIN-NEXT: Expansion,File [[MAIN]], 12:12 -> 12:35 = #0
 // CHECK-MAIN-NEXT: File [[MAIN]], 12:35 -> 14:33 = #5
 // CHECK-MAIN-NEXT: Expansion,File [[MAIN]], 13:14 -> 13:29 = #5
-// CHECK-MAIN-NEXT: Expansion,File [[MAIN]], 14:12 -> 14:33 = #5
+// CHECK-MAIN-NEXT: Expansion,File [[MAIN]], 14:12 -> 14:33 = #0
 // CHECK-MAIN-NEXT: Expansion,File [[MAIN]], 16:12 -> 16:35 = #0
 // CHECK-MAIN-NEXT: File [[MAIN]], 16:35 -> 17:33 = #9
-// CHECK-MAIN-NEXT: Expansion,File [[MAIN]], 17:12 -> 17:33 = #9
+// CHECK-MAIN-NEXT: Expansion,File [[MAIN]], 17:12 -> 17:33 = #0
 
 // CHECK-START: File [[START1:[0-9]]], 1:1 -> 5:1 = #0
 // CHECK-START: File [[START1]], 4:17 -> 4:22 = (#0 + #1)
@@ -65,15 +65,15 @@ int main() {
 // CHECK-CODE: File [[CODE2]], 9:11 -> 11:2 = #7
 // CHECK-CODE: File [[CODE2]], 11:8 -> 13:2 = (#5 - #7)
 
-// CHECK-END: File [[END1:[0-9]]], 1:1 -> 3:2 = #1
-// CHECK-END: File [[END1]], 1:1 -> 6:1 = #0
+// CHECK-END: File [[END1:[0-9]]], 1:1 -> 6:1 = #0
+// CHECK-END: File [[END1]], 1:1 -> 3:2 = #1
 // CHECK-END: File [[END1]], 5:5 -> 5:9 = #0
 // CHECK-END: File [[END1]], 5:11 -> 5:16 = #4
-// CHECK-END: File [[END2:[0-9]]], 1:1 -> 3:2 = #5
-// CHECK-END: File [[END2]], 1:1 -> 6:1 = #0
+// CHECK-END: File [[END2:[0-9]]], 1:1 -> 6:1 = #0
+// CHECK-END: File [[END2]], 1:1 -> 3:2 = #5
 // CHECK-END: File [[END2]], 5:5 -> 5:9 = #0
 // CHECK-END: File [[END2]], 5:11 -> 5:16 = #8
-// CHECK-END: File [[END3:[0-9]]], 1:1 -> 3:2 = #9
-// CHECK-END: File [[END3]], 1:1 -> 6:1 = #0
+// CHECK-END: File [[END3:[0-9]]], 1:1 -> 6:1 = #0
+// CHECK-END: File [[END3]], 1:1 -> 3:2 = #9
 // CHECK-END: File [[END3]], 5:5 -> 5:9 = #0
 // CHECK-END: File [[END3]], 5:11 -> 5:16 = #10
diff --git a/clang/test/CoverageMapping/macros.c b/clang/test/CoverageMapping/macros.c
index fcf21170ef135..00139f33229d5 100644
--- a/clang/test/CoverageMapping/macros.c
+++ b/clang/test/CoverageMapping/macros.c
@@ -80,12 +80,12 @@ void func7(void) { // CHECK-NEXT: File 0, [[@LINE]]:18 -> [[@LINE+6]]:2 = #0
   int kk,ll;       // CHECK-NEXT: File 0, [[@LINE+1]]:7 -> [[@LINE+1]]:8 = #0
   if (k)           // CHECK-NEXT: Branch,File 0, [[@LINE]]:7 -> [[@LINE]]:8 = #1
     m(k);          // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:9 -> [[@LINE]]:5 = #1
-  else             // CHECK-NEXT: Expansion,File 0, [[@LINE-1]]:5 -> [[@LINE-1]]:6 = #1
+  else             // CHECK-NEXT: Expansion,File 0, [[@LINE-1]]:5 -> [[@LINE-1]]:6 = #0
     l = m(l);      // CHECK-NEXT: Gap,File 0, [[@LINE-2]]:7 -> [[@LINE]]:5 = (#0 - #1)
 }                  // CHECK-NEXT: File 0, [[@LINE-1]]:5 -> [[@LINE-1]]:10 = (#0 - #1)
                    // CHECK-NEXT: Expansion,File 0, [[@LINE-2]]:9 -> [[@LINE-2]]:10 = (#0 - #1)
-                   // CHECK-NEXT: File 1, [[@LINE-9]]:14 -> [[@LINE-9]]:17 = #1
-                   // CHECK-NEXT: File 1, [[@LINE-10]]:14 -> [[@LINE-10]]:18 = #0
+                   // CHECK-NEXT: File 1, [[@LINE-9]]:14 -> [[@LINE-9]]:18 = #0
+                   // CHECK-NEXT: File 1, [[@LINE-10]]:14 -> [[@LINE-10]]:17 = #1
                    // CHECK-NEXT: File 2, [[@LINE-11]]:14 -> [[@LINE-11]]:17 = (#0 - #1)
                    // CHECK-NEXT: File 2, [[@LINE-12]]:14 -> [[@LINE-12]]:15 = (#0 - #1)
 
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index c39585681911a..3205863331c91 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -800,7 +800,7 @@ class MCDCDecisionRecorder {
   std::optional<DecisionAndBranches>
   processBranch(const CounterMappingRegion &Branch) {
     // Seek each Decision and apply Region to it.
-    for (auto DecisionIter = Decisions.begin(), DecisionEnd = Decisions.end();
+    for (auto DecisionIter = Decisions.rbegin(), DecisionEnd = Decisions.rend();
          DecisionIter != DecisionEnd; ++DecisionIter)
       switch (DecisionIter->addBranch(Branch)) {
       case DecisionRecord::NotProcessed:
@@ -811,7 +811,7 @@ class MCDCDecisionRecorder {
         DecisionAndBranches Result =
             std::make_pair(DecisionIter->DecisionRegion,
                            std::move(DecisionIter->MCDCBranches));
-        Decisions.erase(DecisionIter); // No longer used.
+        Decisions.erase(std::next(DecisionIter).base()); // No longer used.
         return Result;
       }
 
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp
index 12b1687af69db..e0a1aae2a8cc1 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMappingWriter.cpp
@@ -174,7 +174,14 @@ void CoverageMappingWriter::write(raw_ostream &OS) {
                   : 2 * Kind);
     };
 
-    return getKindKey(LHS.Kind) < getKindKey(RHS.Kind);
+    auto LHSKindKey = getKindKey(LHS.Kind);
+    auto RHSKindKey = getKindKey(RHS.Kind);
+    if (LHSKindKey != RHSKindKey)
+      return LHSKindKey < RHSKindKey;
+
+    // Compares endLoc in descending order,
+    // to prioritize wider Regions with the same startLoc.
+    return LHS.endLoc() > RHS.endLoc();
   });
 
   // Write out the fileid -> filename mapping.

>From 3f04e8ca5deec5e2829e7ce112a088925a5fb16b Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Wed, 2 Apr 2025 20:18:49 +0900
Subject: [PATCH 2/2] Refactor with expansion walking

---
 .../ProfileData/Coverage/CoverageMapping.cpp  | 303 ++++++++----------
 llvm/test/tools/llvm-cov/mcdc-macro.test      |  14 +-
 2 files changed, 142 insertions(+), 175 deletions(-)

diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index 3205863331c91..8c5eae9015abe 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -668,154 +668,166 @@ static unsigned getMaxBitmapSize(const CoverageMappingRecord &Record,
 
 namespace {
 
-/// Collect Decisions, Branchs, and Expansions and associate them.
-class MCDCDecisionRecorder {
-private:
-  /// This holds the DecisionRegion and MCDCBranches under it.
-  /// Also traverses Expansion(s).
-  /// The Decision has the number of MCDCBranches and will complete
-  /// when it is filled with unique ConditionID of MCDCBranches.
+/// Walk MappingRegions along Expansions and emit CountedRegions.
+struct CountedRegionEmitter {
+  /// A nestable Decision.
   struct DecisionRecord {
     const CounterMappingRegion *DecisionRegion;
-
-    /// They are reflected from DecisionRegion for convenience.
-    mcdc::DecisionParameters DecisionParams;
-    LineColPair DecisionStartLoc;
-    LineColPair DecisionEndLoc;
-
-    /// This is passed to `MCDCRecordProcessor`, so this should be compatible
-    /// to`ArrayRef<const CounterMappingRegion *>`.
+    unsigned NumConditions; ///< Copy of DecisionRegion.NumConditions
+    /// Pushed by traversal order.
     SmallVector<const CounterMappingRegion *> MCDCBranches;
-
-    /// IDs that are stored in MCDCBranches
-    /// Complete when all IDs (1 to NumConditions) are met.
+#ifndef NDEBUG
     DenseSet<mcdc::ConditionID> ConditionIDs;
-
-    /// Set of IDs of Expansion(s) that are relevant to DecisionRegion
-    /// and its children (via expansions).
-    /// FileID  pointed by ExpandedFileID is dedicated to the expansion, so
-    /// the location in the expansion doesn't matter.
-    DenseSet<unsigned> ExpandedFileIDs;
+#endif
 
     DecisionRecord(const CounterMappingRegion &Decision)
         : DecisionRegion(&Decision),
-          DecisionParams(Decision.getDecisionParams()),
-          DecisionStartLoc(Decision.startLoc()),
-          DecisionEndLoc(Decision.endLoc()) {
+          NumConditions(Decision.getDecisionParams().NumConditions) {
       assert(Decision.Kind == CounterMappingRegion::MCDCDecisionRegion);
     }
 
-    /// Determine whether DecisionRecord dominates `R`.
-    bool dominates(const CounterMappingRegion &R) const {
-      // Determine whether `R` is included in `DecisionRegion`.
-      if (R.FileID == DecisionRegion->FileID &&
-          R.startLoc() >= DecisionStartLoc && R.endLoc() <= DecisionEndLoc)
-        return true;
-
-      // Determine whether `R` is pointed by any of Expansions.
-      return ExpandedFileIDs.contains(R.FileID);
+    bool pushBranch(const CounterMappingRegion &B) {
+      assert(B.Kind == CounterMappingRegion::MCDCBranchRegion);
+      assert(ConditionIDs.insert(B.getBranchParams().ID).second &&
+             "Duplicate CondID");
+      MCDCBranches.push_back(&B);
+      assert(MCDCBranches.size() <= NumConditions &&
+             "MCDCBranch exceeds NumConds");
+      return (MCDCBranches.size() == NumConditions);
     }
+  };
 
-    enum Result {
-      NotProcessed = 0, /// Irrelevant to this Decision
-      Processed,        /// Added to this Decision
-      Completed,        /// Added and filled this Decision
-    };
+  const CoverageMappingRecord &Record;
+  CounterMappingContext &Ctx;
+  FunctionRecord &Function;
+  bool IsVersion11;
 
-    /// Add Branch into the Decision
-    /// \param Branch expects MCDCBranchRegion
-    /// \returns NotProcessed/Processed/Completed
-    Result addBranch(const CounterMappingRegion &Branch) {
-      assert(Branch.Kind == CounterMappingRegion::MCDCBranchRegion);
+  /// Evaluated Counters.
+  std::map<Counter, uint64_t> CounterValues;
 
-      auto ConditionID = Branch.getBranchParams().ID;
+  /// Decisions are nestable.
+  SmallVector<DecisionRecord, 1> DecisionStack;
 
-      if (ConditionIDs.contains(ConditionID) ||
-          ConditionID >= DecisionParams.NumConditions)
-        return NotProcessed;
+  /// A File pointed by Expansion
+  struct FileInfo {
+    /// The last index(+1) for each FileID in MappingRegions.
+    unsigned LastIndex = 0;
+    /// Mark Files pointed by Expansions.
+    /// Non-marked Files are root Files.
+    bool IsExpanded = false;
+  };
 
-      if (!this->dominates(Branch))
-        return NotProcessed;
+  /// The last element is a sentinel with Index=NumRegions.
+  std::vector<FileInfo> Files;
+#ifndef NDEBUG
+  DenseSet<unsigned> Visited;
+#endif
 
-      assert(MCDCBranches.size() < DecisionParams.NumConditions);
+  CountedRegionEmitter(const CoverageMappingRecord &Record,
+                       CounterMappingContext &Ctx, FunctionRecord &Function,
+                       bool IsVersion11)
+      : Record(Record), Ctx(Ctx), Function(Function), IsVersion11(IsVersion11),
+        Files(Record.Filenames.size()) {
+    // Scan MappingRegions and mark each last index by FileID.
+    for (auto [I, Region] : enumerate(Record.MappingRegions)) {
+      if (Region.FileID >= Files.size()) {
+        // Extend (only possible in CoverageMappingTests)
+        Files.resize(Region.FileID + 1);
+      }
+      Files[Region.FileID].LastIndex = I + 1;
+      if (Region.Kind == CounterMappingRegion::ExpansionRegion) {
+        if (Region.ExpandedFileID >= Files.size()) {
+          // Extend (only possible in CoverageMappingTests)
+          Files.resize(Region.ExpandedFileID + 1);
+        }
+        Files[Region.ExpandedFileID].IsExpanded = true;
+      }
+    }
+  }
 
-      // Put `ID=0` in front of `MCDCBranches` for convenience
-      // even if `MCDCBranches` is not topological.
-      if (ConditionID == 0)
-        MCDCBranches.insert(MCDCBranches.begin(), &Branch);
-      else
-        MCDCBranches.push_back(&Branch);
+  /// Evaluate C and store its evaluated Value into CounterValues.
+  Error evaluateAndCacheCounter(Counter C) {
+    if (CounterValues.count(C) > 0)
+      return Error::success();
 
-      // Mark `ID` as `assigned`.
-      ConditionIDs.insert(ConditionID);
+    auto ValueOrErr = Ctx.evaluate(C);
+    if (!ValueOrErr)
+      return ValueOrErr.takeError();
+    CounterValues[C] = *ValueOrErr;
+    return Error::success();
+  }
 
-      // `Completed` when `MCDCBranches` is full
-      return (MCDCBranches.size() == DecisionParams.NumConditions ? Completed
-                                                                  : Processed);
-    }
+  Error walk(unsigned Idx) {
+    assert(Idx < Files.size());
+    unsigned B = (Idx == 0 ? 0 : Files[Idx - 1].LastIndex);
+    unsigned E = Files[Idx].LastIndex;
+    assert(B != E && "Empty FileID");
+    assert(Visited.insert(Idx).second && "Duplicate Expansions");
+    for (unsigned I = B; I != E; ++I) {
+      const auto &Region = Record.MappingRegions[I];
+      if (Region.FileID != Idx)
+        break;
 
-    /// Record Expansion if it is relevant to this Decision.
-    /// Each `Expansion` may nest.
-    /// \returns true if recorded.
-    bool recordExpansion(const CounterMappingRegion &Expansion) {
-      if (!this->dominates(Expansion))
-        return false;
+      if (Region.Kind == CounterMappingRegion::ExpansionRegion)
+        if (auto E = walk(Region.ExpandedFileID))
+          return E;
 
-      ExpandedFileIDs.insert(Expansion.ExpandedFileID);
-      return true;
-    }
-  };
+      if (auto E = evaluateAndCacheCounter(Region.Count))
+        return E;
 
-private:
-  /// Decisions in progress
-  /// DecisionRecord is added for each MCDCDecisionRegion.
-  /// DecisionRecord is removed when Decision is completed.
-  SmallVector<DecisionRecord> Decisions;
+      if (Region.Kind == CounterMappingRegion::MCDCDecisionRegion) {
+        // Start the new Decision on the stack.
+        DecisionStack.emplace_back(Region);
+      } else if (Region.Kind == CounterMappingRegion::MCDCBranchRegion) {
+        assert(!DecisionStack.empty() && "Orphan MCDCBranch");
+        auto &D = DecisionStack.back();
+
+        if (D.pushBranch(Region)) {
+          // All Branches have been found in the Decision.
+          auto RecordOrErr = Ctx.evaluateMCDCRegion(
+              *D.DecisionRegion, D.MCDCBranches, IsVersion11);
+          if (!RecordOrErr)
+            return RecordOrErr.takeError();
+
+          // Finish the stack.
+          Function.pushMCDCRecord(std::move(*RecordOrErr));
+          DecisionStack.pop_back();
+        }
+      }
 
-public:
-  ~MCDCDecisionRecorder() {
-    assert(Decisions.empty() && "All Decisions have not been resolved");
-  }
+      // Evaluate FalseCount
+      // It may have the Counter in Branches, or Zero.
+      if (auto E = evaluateAndCacheCounter(Region.FalseCount))
+        return E;
+    }
 
-  /// Register Region and start recording.
-  void registerDecision(const CounterMappingRegion &Decision) {
-    Decisions.emplace_back(Decision);
-  }
+    assert((Idx != 0 || DecisionStack.empty()) && "Decision wasn't closed");
 
-  void recordExpansion(const CounterMappingRegion &Expansion) {
-    any_of(Decisions, [&Expansion](auto &Decision) {
-      return Decision.recordExpansion(Expansion);
-    });
+    return Error::success();
   }
 
-  using DecisionAndBranches =
-      std::pair<const CounterMappingRegion *,             /// Decision
-                SmallVector<const CounterMappingRegion *> /// Branches
-                >;
-
-  /// Add MCDCBranchRegion to DecisionRecord.
-  /// \param Branch to be processed
-  /// \returns DecisionsAndBranches if DecisionRecord completed.
-  ///     Or returns nullopt.
-  std::optional<DecisionAndBranches>
-  processBranch(const CounterMappingRegion &Branch) {
-    // Seek each Decision and apply Region to it.
-    for (auto DecisionIter = Decisions.rbegin(), DecisionEnd = Decisions.rend();
-         DecisionIter != DecisionEnd; ++DecisionIter)
-      switch (DecisionIter->addBranch(Branch)) {
-      case DecisionRecord::NotProcessed:
-        continue;
-      case DecisionRecord::Processed:
-        return std::nullopt;
-      case DecisionRecord::Completed:
-        DecisionAndBranches Result =
-            std::make_pair(DecisionIter->DecisionRegion,
-                           std::move(DecisionIter->MCDCBranches));
-        Decisions.erase(std::next(DecisionIter).base()); // No longer used.
-        return Result;
-      }
+  Error emitCountedRegions() {
+    // Walk MappingRegions along Expansions.
+    // - Evaluate Counters
+    // - Emit MCDCRecords
+    for (auto [I, F] : enumerate(Files)) {
+      if (!F.IsExpanded)
+        if (auto E = walk(I))
+          return E;
+    }
+    assert(Visited.size() == Files.size() && "Dangling FileID");
+
+    // Emit CountedRegions in the same order as MappingRegions.
+    for (const auto &Region : Record.MappingRegions) {
+      if (Region.Kind == CounterMappingRegion::MCDCDecisionRegion)
+        continue; // Don't emit.
+      // Adopt values from the CounterValues.
+      // FalseCount may be Zero unless Branches.
+      Function.pushRegion(Region, CounterValues[Region.Count],
+                          CounterValues[Region.FalseCount]);
+    }
 
-    llvm_unreachable("Branch not found in Decisions");
+    return Error::success();
   }
 };
 
@@ -880,57 +892,12 @@ Error CoverageMapping::loadFunctionRecord(
       Record.MappingRegions[0].Count.isZero() && Counts[0] > 0)
     return Error::success();
 
-  MCDCDecisionRecorder MCDCDecisions;
   FunctionRecord Function(OrigFuncName, Record.Filenames);
-  for (const auto &Region : Record.MappingRegions) {
-    // MCDCDecisionRegion should be handled first since it overlaps with
-    // others inside.
-    if (Region.Kind == CounterMappingRegion::MCDCDecisionRegion) {
-      MCDCDecisions.registerDecision(Region);
-      continue;
-    }
-    Expected<int64_t> ExecutionCount = Ctx.evaluate(Region.Count);
-    if (auto E = ExecutionCount.takeError()) {
-      consumeError(std::move(E));
-      return Error::success();
-    }
-    Expected<int64_t> AltExecutionCount = Ctx.evaluate(Region.FalseCount);
-    if (auto E = AltExecutionCount.takeError()) {
-      consumeError(std::move(E));
-      return Error::success();
-    }
-    Function.pushRegion(Region, *ExecutionCount, *AltExecutionCount);
-
-    // Record ExpansionRegion.
-    if (Region.Kind == CounterMappingRegion::ExpansionRegion) {
-      MCDCDecisions.recordExpansion(Region);
-      continue;
-    }
-
-    // Do nothing unless MCDCBranchRegion.
-    if (Region.Kind != CounterMappingRegion::MCDCBranchRegion)
-      continue;
 
-    auto Result = MCDCDecisions.processBranch(Region);
-    if (!Result) // Any Decision doesn't complete.
-      continue;
-
-    auto MCDCDecision = Result->first;
-    auto &MCDCBranches = Result->second;
-
-    // Since the bitmap identifies the executed test vectors for an MC/DC
-    // DecisionRegion, all of the information is now available to process.
-    // This is where the bulk of the MC/DC progressing takes place.
-    Expected<MCDCRecord> Record =
-        Ctx.evaluateMCDCRegion(*MCDCDecision, MCDCBranches, IsVersion11);
-    if (auto E = Record.takeError()) {
-      consumeError(std::move(E));
-      return Error::success();
-    }
-
-    // Save the MC/DC Record so that it can be visualized later.
-    Function.pushMCDCRecord(std::move(*Record));
-  }
+  // Emit CountedRegions into FunctionRecord.
+  if (auto E = CountedRegionEmitter(Record, Ctx, Function, IsVersion11)
+                   .emitCountedRegions())
+    return E;
 
   // Don't create records for (filenames, function) pairs we've already seen.
   auto FilenamesHash = hash_combine_range(Record.Filenames.begin(),
diff --git a/llvm/test/tools/llvm-cov/mcdc-macro.test b/llvm/test/tools/llvm-cov/mcdc-macro.test
index 14dd5ebd68eb1..d68f4aeb67bcb 100644
--- a/llvm/test/tools/llvm-cov/mcdc-macro.test
+++ b/llvm/test/tools/llvm-cov/mcdc-macro.test
@@ -13,19 +13,19 @@
 // CHECK-NEXT:  |
 // CHECK-NEXT:  |  Number of Conditions: 5
 // CHECK-NEXT:  |     Condition C1 --> (9:7)
-// CHECK-NEXT:  |     Condition C2 --> (9:22)
-// CHECK-NEXT:  |     Condition C3 --> (2:11)
-// CHECK-NEXT:  |     Condition C4 --> (3:11)
-// CHECK-NEXT:  |     Condition C5 --> (3:23)
+// CHECK-NEXT:  |     Condition C2 --> (2:11)
+// CHECK-NEXT:  |     Condition C3 --> (3:11)
+// CHECK-NEXT:  |     Condition C4 --> (3:23)
+// CHECK-NEXT:  |     Condition C5 --> (9:22)
 // CHECK-NEXT:  |
 // CHECK-NEXT:  |  Executed MC/DC Test Vectors:
 // CHECK-NEXT:  |
 // CHECK-NEXT:  |     C1, C2, C3, C4, C5    Result
-// CHECK-NEXT:  |  1 { T,  -,  C,  T,  T  = T      }
+// CHECK-NEXT:  |  1 { T,  C,  T,  T,  -  = T      }
 // CHECK-NEXT:  |
 // CHECK-NEXT:  |  C1-Pair: not covered
-// CHECK-NEXT:  |  C2-Pair: not covered
-// CHECK-NEXT:  |  C3-Pair: constant folded
+// CHECK-NEXT:  |  C2-Pair: constant folded
+// CHECK-NEXT:  |  C3-Pair: not covered
 // CHECK-NEXT:  |  C4-Pair: not covered
 // CHECK-NEXT:  |  C5-Pair: not covered
 // CHECK-NEXT:  |  MC/DC Coverage for Decision: 0.00%



More information about the llvm-commits mailing list