[clang] [llvm] [Coverage] Improve performance of propagating Counter of Expansions (PR #122589)

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


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

>From e5fbf846113591b0abff151d91b01a5dd40abef1 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Sat, 11 Jan 2025 18:42:10 +0900
Subject: [PATCH 1/6] [Coverage] Improve performance of propagating Counter of
 Expansions

This improves `-dump-coverage-mapping` (939,498 lines) for
`RISCVInstructionSelector.cpp` from 30m to 1m18s and also improves
`llvm-cov` for `check-llvm` from 33m to 24s.

The current implementation behaved O(N^2) order with hundreds
thousands of Expansions.

This assumes:
  - Records are partitioned by FileID.
    - ExpandedFileID doesn't point FileID==0, since it is the root.
  - The Count in Expansion is propagated from 1st Record in
    ExpandedFileID.

Therefore another fact below can be assumed.
  - Propagation chain consists of Expansions at each 1st Record.

This scans the Record at most a few times. O(N) is expected.

Fixes #113173
---
 .../Coverage/CoverageMappingReader.cpp        | 100 +++++++++++++++---
 1 file changed, 84 insertions(+), 16 deletions(-)

diff --git a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
index cdf4412c6477a..15c7004c45e7d 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
@@ -440,26 +440,94 @@ Error RawCoverageMappingReader::read() {
   // Set the counters for the expansion regions.
   // i.e. Counter of expansion region = counter of the first region
   // from the expanded file.
-  // Perform multiple passes to correctly propagate the counters through
-  // all the nested expansion regions.
-  SmallVector<CounterMappingRegion *, 8> FileIDExpansionRegionMapping;
-  FileIDExpansionRegionMapping.resize(VirtualFileMapping.size(), nullptr);
-  for (unsigned Pass = 1, S = VirtualFileMapping.size(); Pass < S; ++Pass) {
-    for (auto &R : MappingRegions) {
-      if (R.Kind != CounterMappingRegion::ExpansionRegion)
-        continue;
-      assert(!FileIDExpansionRegionMapping[R.ExpandedFileID]);
-      FileIDExpansionRegionMapping[R.ExpandedFileID] = &R;
+  // This assumes:
+  //   - Records are partitioned by FileID.
+  //     - ExpandedFileID doesn't point FileID==0, since it is the root.
+  //   - The Count in Expansion is propagated from 1st Record in
+  //     ExpandedFileID.
+  // Therefore another fact below can be assumed.
+  //   - Propagation chain consists of Expansions at each 1st Record.
+
+  /// Node per File.
+  struct FileNode {
+    /// 1st Record in the File.
+    CounterMappingRegion *FirstR = nullptr;
+    /// The Expansion Record out of this File.
+    CounterMappingRegion *ExpanderR = nullptr;
+    /// Count hasn't been propagated yet (for Expansion)
+    bool ExpansionPending = false;
+  };
+  SmallVector<FileNode> FileIDExpansionRegionMapping(VirtualFileMapping.size());
+  assert(VirtualFileMapping.size() == FileIDExpansionRegionMapping.size());
+
+  // Construct the tree.
+  unsigned PrevFileID = 0;
+  for (auto &R : MappingRegions) {
+    if (R.Kind == CounterMappingRegion::ExpansionRegion) {
+      // The File that contains Expansion may be a node.
+      assert(R.ExpandedFileID != 0 &&
+             "ExpandedFileID shouldn't point the root");
+      assert(!FileIDExpansionRegionMapping[R.ExpandedFileID].ExpanderR);
+      FileIDExpansionRegionMapping[R.ExpandedFileID].ExpanderR = &R;
+
+      // It will be the node if (isExpansion and ExpansionPending).
+      FileIDExpansionRegionMapping[R.ExpandedFileID].ExpansionPending = true;
     }
-    for (auto &R : MappingRegions) {
-      if (FileIDExpansionRegionMapping[R.FileID]) {
-        FileIDExpansionRegionMapping[R.FileID]->Count = R.Count;
-        FileIDExpansionRegionMapping[R.FileID] = nullptr;
-      }
+
+    // FileID==0 is not handled here but don't care since it's the root.
+    if (PrevFileID != R.FileID) {
+      // Record 1st Record for each File.
+      assert(!FileIDExpansionRegionMapping[R.FileID].FirstR);
+      FileIDExpansionRegionMapping[R.FileID].FirstR = &R;
+      PrevFileID = R.FileID;
     }
   }
 
-  return Error::success();
+  // Make sure the root [0] doesn't point others.
+  assert((FileIDExpansionRegionMapping.empty() ||
+          (!FileIDExpansionRegionMapping[0].ExpanderR &&
+           !FileIDExpansionRegionMapping[0].FirstR)) &&
+         "The root shouldn't point other nodes");
+
+  auto Propagate = [&](FileNode &X) {
+    // Skip already processed node.
+    if (!X.ExpanderR)
+      return false;
+    // Skip Pending Expansion node.
+    // Process non-Expansion Record and non-Pending Expansion.
+    if (X.ExpansionPending &&
+        X.FirstR->Kind == CounterMappingRegion::ExpansionRegion)
+      return false;
+
+    // Propagate.
+    X.ExpanderR->Count = X.FirstR->Count;
+    // Mark the destination ready.
+    FileIDExpansionRegionMapping[X.ExpanderR->FileID].ExpansionPending = false;
+    // Mark this processed.
+    X.ExpanderR = nullptr;
+    return true;
+  };
+
+  // This won't iterate in most cases but iterates finitely for
+  // unusual cases.
+  for (unsigned I = 0, E = FileIDExpansionRegionMapping.size(); I != E; ++I) {
+    // Propagate Descending.  All Files will be processed if each
+    // ExpandedFileID is greater than FileID.
+    for (auto &X : reverse(FileIDExpansionRegionMapping))
+      Propagate(X);
+
+    // Check whether all Files are processed (or propagate Ascending,
+    // not possible in the usual assumptions).
+    bool Changed = false;
+    for (auto &X : FileIDExpansionRegionMapping)
+      Changed = (Propagate(X) || Changed);
+
+    if (!Changed)
+      return Error::success();
+  }
+
+  return make_error<CoverageMapError>(coveragemap_error::malformed,
+                                      "unexpected Expansions");
 }
 
 Expected<bool> RawCoverageMappingDummyChecker::isDummy() {

>From 2aa0859cafca4eb8576cf5b8b23998038bf71ebf Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Sat, 11 Jan 2025 22:51:29 +0900
Subject: [PATCH 2/6] Get rid of the assumption "[0] is the root"

---
 .../ProfileData/Coverage/CoverageMappingReader.cpp | 14 ++------------
 1 file changed, 2 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
index 15c7004c45e7d..19733adeef9ba 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
@@ -36,6 +36,7 @@
 #include "llvm/Support/Path.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/TargetParser/Triple.h"
+#include <limits>
 #include <vector>
 
 using namespace llvm;
@@ -442,7 +443,6 @@ Error RawCoverageMappingReader::read() {
   // from the expanded file.
   // This assumes:
   //   - Records are partitioned by FileID.
-  //     - ExpandedFileID doesn't point FileID==0, since it is the root.
   //   - The Count in Expansion is propagated from 1st Record in
   //     ExpandedFileID.
   // Therefore another fact below can be assumed.
@@ -458,15 +458,12 @@ Error RawCoverageMappingReader::read() {
     bool ExpansionPending = false;
   };
   SmallVector<FileNode> FileIDExpansionRegionMapping(VirtualFileMapping.size());
-  assert(VirtualFileMapping.size() == FileIDExpansionRegionMapping.size());
 
   // Construct the tree.
-  unsigned PrevFileID = 0;
+  auto PrevFileID = std::numeric_limits<unsigned>::max(); // Invalid value
   for (auto &R : MappingRegions) {
     if (R.Kind == CounterMappingRegion::ExpansionRegion) {
       // The File that contains Expansion may be a node.
-      assert(R.ExpandedFileID != 0 &&
-             "ExpandedFileID shouldn't point the root");
       assert(!FileIDExpansionRegionMapping[R.ExpandedFileID].ExpanderR);
       FileIDExpansionRegionMapping[R.ExpandedFileID].ExpanderR = &R;
 
@@ -474,7 +471,6 @@ Error RawCoverageMappingReader::read() {
       FileIDExpansionRegionMapping[R.ExpandedFileID].ExpansionPending = true;
     }
 
-    // FileID==0 is not handled here but don't care since it's the root.
     if (PrevFileID != R.FileID) {
       // Record 1st Record for each File.
       assert(!FileIDExpansionRegionMapping[R.FileID].FirstR);
@@ -483,12 +479,6 @@ Error RawCoverageMappingReader::read() {
     }
   }
 
-  // Make sure the root [0] doesn't point others.
-  assert((FileIDExpansionRegionMapping.empty() ||
-          (!FileIDExpansionRegionMapping[0].ExpanderR &&
-           !FileIDExpansionRegionMapping[0].FirstR)) &&
-         "The root shouldn't point other nodes");
-
   auto Propagate = [&](FileNode &X) {
     // Skip already processed node.
     if (!X.ExpanderR)

>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 3/6] [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 489b1df5917bb27c56998f16ab535f2a4429c754 Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Sat, 15 Mar 2025 11:09:53 +0900
Subject: [PATCH 4/6] Dissolve one condition to invert the loop

---
 .../Coverage/CoverageMappingReader.cpp        | 30 ++++++++-----------
 1 file changed, 13 insertions(+), 17 deletions(-)

diff --git a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
index 19733adeef9ba..91cf8048f2b5e 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
@@ -460,23 +460,19 @@ Error RawCoverageMappingReader::read() {
   SmallVector<FileNode> FileIDExpansionRegionMapping(VirtualFileMapping.size());
 
   // Construct the tree.
-  auto PrevFileID = std::numeric_limits<unsigned>::max(); // Invalid value
-  for (auto &R : MappingRegions) {
-    if (R.Kind == CounterMappingRegion::ExpansionRegion) {
-      // The File that contains Expansion may be a node.
-      assert(!FileIDExpansionRegionMapping[R.ExpandedFileID].ExpanderR);
-      FileIDExpansionRegionMapping[R.ExpandedFileID].ExpanderR = &R;
-
-      // It will be the node if (isExpansion and ExpansionPending).
-      FileIDExpansionRegionMapping[R.ExpandedFileID].ExpansionPending = true;
-    }
-
-    if (PrevFileID != R.FileID) {
-      // Record 1st Record for each File.
-      assert(!FileIDExpansionRegionMapping[R.FileID].FirstR);
-      FileIDExpansionRegionMapping[R.FileID].FirstR = &R;
-      PrevFileID = R.FileID;
-    }
+  // Reverse loop finally sets FirstR as the top for each FileID.
+  for (auto &R : reverse(MappingRegions)) {
+    FileIDExpansionRegionMapping[R.FileID].FirstR = &R;
+
+    if (R.Kind != CounterMappingRegion::ExpansionRegion)
+      continue;
+
+    // The File that contains Expansion may be a node.
+    auto &ExpandedRegion = FileIDExpansionRegionMapping[R.ExpandedFileID];
+    assert(!ExpandedRegion.ExpanderR);
+    ExpandedRegion.ExpanderR = &R;
+    // It will be the node if (isExpansion and ExpansionPending).
+    ExpandedRegion.ExpansionPending = true;
   }
 
   auto Propagate = [&](FileNode &X) {

>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 5/6] 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%

>From 4d1ae4b1c0f5bc038a75e083a29afcc8c84bde6f Mon Sep 17 00:00:00 2001
From: NAKAMURA Takumi <geek4civic at gmail.com>
Date: Wed, 2 Apr 2025 20:21:14 +0900
Subject: [PATCH 6/6] Revise w/ expansion walker

---
 clang/test/CoverageMapping/comment-in-macro.c |  4 +-
 clang/test/CoverageMapping/comment.cpp        |  2 +-
 .../test/CoverageMapping/control-flow-macro.c |  2 +-
 clang/test/CoverageMapping/if.cpp             |  4 +-
 clang/test/CoverageMapping/include-macros.c   |  8 +--
 clang/test/CoverageMapping/includehell.cpp    | 16 +++---
 clang/test/CoverageMapping/label.cpp          |  4 +-
 clang/test/CoverageMapping/loopmacro.c        | 16 +++---
 clang/test/CoverageMapping/macro-expansion.c  |  2 +-
 .../CoverageMapping/macro-expressions.cpp     | 34 +++++------
 clang/test/CoverageMapping/macroception.c     | 24 ++++----
 clang/test/CoverageMapping/macroparams.c      |  4 +-
 clang/test/CoverageMapping/macroparams2.c     |  2 +-
 clang/test/CoverageMapping/macros.c           | 20 +++----
 clang/test/CoverageMapping/macroscopes.cpp    | 30 +++++-----
 .../test/CoverageMapping/mcdc-scratch-space.c | 10 ++--
 .../CoverageMapping/mcdc-system-headers.cpp   |  8 +--
 clang/test/CoverageMapping/moremacros.c       |  8 +--
 clang/test/CoverageMapping/switchmacro.c      |  4 +-
 clang/test/CoverageMapping/trymacro.cpp       |  6 +-
 .../ProfileData/Coverage/CoverageMapping.cpp  | 57 ++++++++++++++-----
 .../Coverage/CoverageMappingReader.cpp        | 22 -------
 .../ProfileData/CoverageMappingTest.cpp       | 15 +++--
 23 files changed, 155 insertions(+), 147 deletions(-)

diff --git a/clang/test/CoverageMapping/comment-in-macro.c b/clang/test/CoverageMapping/comment-in-macro.c
index 1afde46f1e4a5..90f6d373f7f37 100644
--- a/clang/test/CoverageMapping/comment-in-macro.c
+++ b/clang/test/CoverageMapping/comment-in-macro.c
@@ -4,8 +4,8 @@
 #define x2 return 0
 // CHECK: main
 int main(void) { // CHECK-NEXT: File 0, [[@LINE]]:16 -> [[@LINE+3]]:2 = #0
-  x1;            // CHECK-NEXT: Expansion,File 0, [[@LINE]]:3 -> [[@LINE]]:5 = #0
-  x2;            // CHECK-NEXT: Expansion,File 0, [[@LINE]]:3 -> [[@LINE]]:5 = #0
+  x1;            // CHECK-NEXT: Expansion,File 0, [[@LINE]]:3 -> [[@LINE]]:5 = 0
+  x2;            // CHECK-NEXT: Expansion,File 0, [[@LINE]]:3 -> [[@LINE]]:5 = 0
 }
 // CHECK-NEXT: File 1, 3:12 -> 3:14 = #0
 // CHECK-NEXT: File 2, 4:12 -> 4:20 = #0
diff --git a/clang/test/CoverageMapping/comment.cpp b/clang/test/CoverageMapping/comment.cpp
index f8e4b4912e182..90da003f01079 100644
--- a/clang/test/CoverageMapping/comment.cpp
+++ b/clang/test/CoverageMapping/comment.cpp
@@ -8,6 +8,6 @@ int f() {
 }
 
 // CHECK: File 0, 3:9 -> 8:2 = #0
-// CHECK-NEXT: Expansion,File 0, 5:10 -> 5:28 = #0
+// CHECK-NEXT: Expansion,File 0, 5:10 -> 5:28 = 0
 // CHECK-NEXT: Skipped,File 0, 6:1 -> 6:7 = 0
 // CHECK-NEXT: File 1, 1:1 -> 7:1 = #0
diff --git a/clang/test/CoverageMapping/control-flow-macro.c b/clang/test/CoverageMapping/control-flow-macro.c
index b73ac989057db..1a4e106fca6e2 100644
--- a/clang/test/CoverageMapping/control-flow-macro.c
+++ b/clang/test/CoverageMapping/control-flow-macro.c
@@ -5,7 +5,7 @@
 // CHECK: main
 // CHECK-NEXT: File 0, {{[0-9]+}}:40 -> [[END:[0-9]+]]:2 = #0
 int main(int argc, const char *argv[]) {
-  // CHECK: Expansion,File 0, [[@LINE+1]]:3 -> [[@LINE+1]]:6 = #0
+  // CHECK: Expansion,File 0, [[@LINE+1]]:3 -> [[@LINE+1]]:6 = 0
   ifc(1) return 0;
   // Expansion,File 0, [[@LINE+2]]:3 -> [[@LINE+2]]:6 = (#0 - #1)
   // File 0, [[@LINE+1]]:6 -> [[END]]:2 = (#0 - #1)
diff --git a/clang/test/CoverageMapping/if.cpp b/clang/test/CoverageMapping/if.cpp
index b6fd525e930f9..8166a374c1b53 100644
--- a/clang/test/CoverageMapping/if.cpp
+++ b/clang/test/CoverageMapping/if.cpp
@@ -121,7 +121,7 @@ int check_constexpr_init_with_if_def(int i) {   // CHECK-NEXT: [[@LINE]]:{{[0-9]
 
 // CHECK-LABEL: _Z32check_macro_constexpr_if_skippedi:
 int check_macro_constexpr_if_skipped(int i) {   // CHECK-NEXT: [[@LINE]]:{{[0-9]+}} -> {{[0-9]+}}:2 = #0
-#define IF_CONSTEXPR if constexpr               // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:3 -> [[@LINE+1]]:15 = #0 (Expanded file = 1)
+#define IF_CONSTEXPR if constexpr               // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:3 -> [[@LINE+1]]:15 = 0 (Expanded file = 1)
   IF_CONSTEXPR(false) {                         // CHECK-NEXT: Skipped,File 0, [[@LINE]]:3 -> [[@LINE+2]]:4 = 0
     i *= 2;                                     // CHECK-NEXT: File 1, [[@LINE-2]]:22 -> [[@LINE-2]]:34 = #0
   }
@@ -227,7 +227,7 @@ constexpr int check_notconsteval_branch_kept(int i) { // CHECK-NEXT: [[@LINE]]:{
 
 // CHECK-LABEL: _Z32check_macro_consteval_if_skippedi:
 constexpr int check_macro_consteval_if_skipped(int i) {   // CHECK-NEXT: [[@LINE]]:{{[0-9]+}} -> {{[0-9]+}}:2 = #0
-#define IF_RUNTIME if !consteval               // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:3 -> [[@LINE+1]]:13 = #0 (Expanded file = 1)
+#define IF_RUNTIME if !consteval               // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:3 -> [[@LINE+1]]:13 = 0 (Expanded file = 1)
   IF_RUNTIME {                                 // CHECK-NEXT: Skipped,File 0, [[@LINE]]:3 -> [[@LINE]]:14 = 0
     i *= 2;                                    // CHECK-NEXT: File 0, [[@LINE-1]]:14 -> [[@LINE+1]]:4 = #0
   }                                            // CHECK-NEXT: File 1, [[@LINE-3]]:20 -> [[@LINE-3]]:33 = #0
diff --git a/clang/test/CoverageMapping/include-macros.c b/clang/test/CoverageMapping/include-macros.c
index 8adb34bd22876..6f0ad4c7e2de1 100644
--- a/clang/test/CoverageMapping/include-macros.c
+++ b/clang/test/CoverageMapping/include-macros.c
@@ -8,11 +8,11 @@ void f1(void) {
 
 // CHECK-LABEL: f1:
 // CHECK-NEXT:   File 0, 5:15 -> 7:2 = #0
-// CHECK-NEXT:   Expansion,File 0, 6:3 -> 6:5 = #0 (Expanded file = 1)
+// CHECK-NEXT:   Expansion,File 0, 6:3 -> 6:5 = 0 (Expanded file = 1)
 // CHECK-NEXT:   File 1, 13:20 -> 13:50 = #0
-// CHECK-NEXT:   Expansion,File 1, 13:20 -> 13:22 = #0 (Expanded file = 2)
+// CHECK-NEXT:   Expansion,File 1, 13:20 -> 13:22 = 0 (Expanded file = 2)
 // CHECK-NEXT:   File 2, 7:20 -> 7:46 = #0
-// CHECK-NEXT:   Expansion,File 2, 7:33 -> 7:44 = #0 (Expanded file = 3)
+// CHECK-NEXT:   Expansion,File 2, 7:33 -> 7:44 = 0 (Expanded file = 3)
 // CHECK-NEXT:   File 3, 13:26 -> 13:34 = #0
-// CHECK-NEXT:   Expansion,File 3, 13:26 -> 13:33 = #0 (Expanded file = 4)
+// CHECK-NEXT:   Expansion,File 3, 13:26 -> 13:33 = 0 (Expanded file = 4)
 // CHECK-NEXT:   File 4, 3:17 -> 3:18 = #0
diff --git a/clang/test/CoverageMapping/includehell.cpp b/clang/test/CoverageMapping/includehell.cpp
index 3c67672fabc0f..bfa4e74a1e9c1 100644
--- a/clang/test/CoverageMapping/includehell.cpp
+++ b/clang/test/CoverageMapping/includehell.cpp
@@ -25,17 +25,17 @@ int main() {
 // RUN: FileCheck -input-file %tmapping %s --check-prefix=CHECK-END
 
 // CHECK-MAIN: File [[MAIN:[0-9]]], 3:12 -> 20:2 = #0
-// CHECK-MAIN-NEXT: Expansion,File [[MAIN]], 6:12 -> 6:35 = #0
+// 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 = #0
-// CHECK-MAIN-NEXT: Expansion,File [[MAIN]], 12:12 -> 12:35 = #0
+// CHECK-MAIN-NEXT: Expansion,File [[MAIN]], 8:14 -> 8:29 = 0
+// 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 = #0
-// CHECK-MAIN-NEXT: Expansion,File [[MAIN]], 16:12 -> 16:35 = #0
+// CHECK-MAIN-NEXT: Expansion,File [[MAIN]], 13:14 -> 13:29 = 0
+// 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 = #0
+// 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)
diff --git a/clang/test/CoverageMapping/label.cpp b/clang/test/CoverageMapping/label.cpp
index cf7cbe5d00f43..18786e7e08fe8 100644
--- a/clang/test/CoverageMapping/label.cpp
+++ b/clang/test/CoverageMapping/label.cpp
@@ -54,8 +54,8 @@ void test2(int x) {          // CHECK-NEXT: File 0, [[@LINE]]:19 -> {{[0-9]+}}:2
 void test3() {
   if (0)
     goto b; // CHECK: Gap,File 0, [[@LINE]]:12 -> [[@LINE+1]]:1 = (#0 - #1)
-a: // CHECK-NEXT: Expansion,File 0, [[@LINE]]:1 -> [[@LINE]]:2 = [[retnCount:#[0-9]+]] (Expanded file = 1)
-  return; // CHECK-NEXT: File 0, [[@LINE-1]]:2 -> [[@LINE]]:9 = [[retnCount]]
+a: // CHECK-NEXT: Expansion,File 0, [[@LINE]]:1 -> [[@LINE]]:2 = 0 (Expanded file = 1)
+  return; // CHECK-NEXT: File 0, [[@LINE-1]]:2 -> [[@LINE]]:9 = [[retnCount:#[0-9]+]]
 }
 #undef a
 
diff --git a/clang/test/CoverageMapping/loopmacro.c b/clang/test/CoverageMapping/loopmacro.c
index 1fbb1139abf04..1ad633fbbf761 100644
--- a/clang/test/CoverageMapping/loopmacro.c
+++ b/clang/test/CoverageMapping/loopmacro.c
@@ -3,27 +3,27 @@
 // CHECK: main
 // CHECK-NEXT: File 0, {{[0-9]+}}:16 -> {{[0-9]+}}:2 = #0
 // CHECK-NEXT: File 0, {{[0-9]+}}:6 -> {{[0-9]+}}:4 = (#0 + #1)
-// CHECK-NEXT: Expansion,File 0, {{[0-9]+}}:7 -> {{[0-9]+}}:20 = (#0 + #1)
+// CHECK-NEXT: Expansion,File 0, {{[0-9]+}}:7 -> {{[0-9]+}}:20 = 0
 // CHECK-NEXT: File 0, {{[0-9]+}}:12 -> {{[0-9]+}}:30 = (#0 + #1)
 
 // CHECK-NEXT: Branch,File 0, {{[0-9]+}}:12 -> {{[0-9]+}}:30 = #1, #0
 // CHECK-NEXT: File 1, [[@LINE+4]]:4 -> [[@LINE+6]]:23 = (#0 + #1)
-// CHECK-NEXT: Expansion,File 1, [[@LINE+3]]:5 -> [[@LINE+3]]:16 = (#0 + #1)
-// CHECK-NEXT: Expansion,File 1, [[@LINE+3]]:16 -> [[@LINE+3]]:21 = (#0 + #1)
+// CHECK-NEXT: Expansion,File 1, [[@LINE+3]]:5 -> [[@LINE+3]]:16 = 0
+// CHECK-NEXT: Expansion,File 1, [[@LINE+3]]:16 -> [[@LINE+3]]:21 = 0
 #define INSERT_STRING(s, match_head) \
    (UPDATE_HASH(ins_h, window[(s) + MIN_MATCH-1]), \
     prev[(s) & WMASK] = match_head = head[ins_h], \
     head[ins_h] = (s))
 // CHECK-NEXT: File 2, [[@LINE+3]]:26 -> [[@LINE+3]]:66 = (#0 + #1)
-// CHECK-NEXT: Expansion,File 2, [[@LINE+2]]:38 -> [[@LINE+2]]:45 = (#0 + #1)
-// CHECK-NEXT: Expansion,File 2, [[@LINE+1]]:56 -> [[@LINE+1]]:65 = (#0 + #1)
+// CHECK-NEXT: Expansion,File 2, [[@LINE+2]]:38 -> [[@LINE+2]]:45 = 0
+// CHECK-NEXT: Expansion,File 2, [[@LINE+1]]:56 -> [[@LINE+1]]:65 = 0
 #define UPDATE_HASH(h,c) (h = (((h)<<H_SHIFT) ^ (c)) & HASH_MASK)
 // CHECK-NEXT: File 3, [[@LINE+1]]:15 -> [[@LINE+1]]:21 = (#0 + #1)
 #define WMASK 0xFFFF
 // CHECK-NEXT: File 4, [[@LINE+4]]:18 -> [[@LINE+4]]:53 = (#0 + #1)
-// CHECK-NEXT: Expansion,File 4, [[@LINE+3]]:20 -> [[@LINE+3]]:29 = (#0 + #1)
-// CHECK-NEXT: Expansion,File 4, [[@LINE+2]]:30 -> [[@LINE+2]]:39 = (#0 + #1)
-// CHECK-NEXT: Expansion,File 4, [[@LINE+1]]:43 -> [[@LINE+1]]:52 = (#0 + #1)
+// CHECK-NEXT: Expansion,File 4, [[@LINE+3]]:20 -> [[@LINE+3]]:29 = 0
+// CHECK-NEXT: Expansion,File 4, [[@LINE+2]]:30 -> [[@LINE+2]]:39 = 0
+// CHECK-NEXT: Expansion,File 4, [[@LINE+1]]:43 -> [[@LINE+1]]:52 = 0
 #define H_SHIFT  ((HASH_BITS+MIN_MATCH-1)/MIN_MATCH)
 // CHECK-NEXT: File 5, [[@LINE+1]]:19 -> [[@LINE+1]]:25 = (#0 + #1)
 #define HASH_MASK 0xFFFF
diff --git a/clang/test/CoverageMapping/macro-expansion.c b/clang/test/CoverageMapping/macro-expansion.c
index 4cd2c93437193..b6fe1c7d2cf7e 100644
--- a/clang/test/CoverageMapping/macro-expansion.c
+++ b/clang/test/CoverageMapping/macro-expansion.c
@@ -24,7 +24,7 @@
 #define M2(x) do { if (x) {} } while (0)
 // CHECK-NEXT: File 4, [[@LINE+5]]:15 -> [[@LINE+5]]:38 = #0
 // CHECK-NEXT: File 4, [[@LINE+4]]:18 -> [[@LINE+4]]:28 = (#0 + #8)
-// CHECK-NEXT: Expansion,File 4, [[@LINE+3]]:20 -> [[@LINE+3]]:22 = (#0 + #8)
+// CHECK-NEXT: Expansion,File 4, [[@LINE+3]]:20 -> [[@LINE+3]]:22 = 0
 // CHECK-NEXT: File 4, [[@LINE+2]]:36 -> [[@LINE+2]]:37 = (#0 + #8)
 // CHECK-NEXT: Branch,File 4, [[@LINE+1]]:36 -> [[@LINE+1]]:37 = 0, #0
 #define M3(x) do { M2(x); } while (0)
diff --git a/clang/test/CoverageMapping/macro-expressions.cpp b/clang/test/CoverageMapping/macro-expressions.cpp
index 2b6a1b64c2594..57e5d1218f0fb 100644
--- a/clang/test/CoverageMapping/macro-expressions.cpp
+++ b/clang/test/CoverageMapping/macro-expressions.cpp
@@ -58,33 +58,33 @@ void foo(int i) {
   // CHECK-NEXT: File 0, [[@LINE+1]]:10 -> [[@LINE+1]]:12 = #1
   if (0) {}
 
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:7 -> [[@LINE+3]]:11 = #0
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:7 -> [[@LINE+3]]:11 = 0
   // CHECK-NEXT: Gap,File 0, [[@LINE+2]]:15 -> [[@LINE+2]]:16 = #2
   // CHECK-NEXT: File 0, [[@LINE+1]]:16 -> [[@LINE+1]]:18 = #2
   if (EXPR(i)) {}
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:9 -> [[@LINE+3]]:14 = (#0 + #3)
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:9 -> [[@LINE+3]]:14 = 0
   // CHECK-NEXT: Gap,File 0, [[@LINE+2]]:19 -> [[@LINE+2]]:20 = #3
   // CHECK-NEXT: File 0, [[@LINE+1]]:20 -> [[@LINE+1]]:22 = #3
   for (;NEXPR(i);) {}
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+5]]:8 -> [[@LINE+5]]:14 = #0
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+4]]:33 -> [[@LINE+4]]:35 = (#0 + #4)
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:43 -> [[@LINE+3]]:46 = #4
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+5]]:8 -> [[@LINE+5]]:14 = 0
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+4]]:33 -> [[@LINE+4]]:35 = 0
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:43 -> [[@LINE+3]]:46 = 0
   // CHECK-NEXT: Gap,File 0, [[@LINE+2]]:50 -> [[@LINE+2]]:51 = #4
   // CHECK: File 0, [[@LINE+1]]:51 -> [[@LINE+1]]:53 = #4
   for (ASSIGN(DECL(int, j), 0); LT(j, i); INC(j)) {}
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:3 -> [[@LINE+1]]:9 = #0
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:3 -> [[@LINE+1]]:9 = 0
   ASSIGN(DECL(int, k), 0);
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+4]]:10 -> [[@LINE+4]]:12 = (#0 + #5)
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+4]]:10 -> [[@LINE+4]]:12 = 0
   // CHECK-NEXT: Gap,File 0, [[@LINE+3]]:19 -> [[@LINE+3]]:20 = #5
   // CHECK-NEXT: File 0, [[@LINE+2]]:20 -> [[@LINE+2]]:31 = #5
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:22 -> [[@LINE+1]]:25 = #5
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:22 -> [[@LINE+1]]:25 = 0
   while (LT(k, i)) { INC(k); }
   // CHECK-NEXT: File 0, [[@LINE+2]]:6 -> [[@LINE+2]]:8 = (#0 + #6)
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:16 -> [[@LINE+1]]:21 = (#0 + #6)
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:16 -> [[@LINE+1]]:21 = 0
   do {} while (NEXPR(i));
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+5]]:8 -> [[@LINE+5]]:12 = #0
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+5]]:8 -> [[@LINE+5]]:12 = 0
   // CHECK-NEXT: Branch,File 0, [[@LINE+4]]:21 -> [[@LINE+4]]:22 = #7, #0
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:23 -> [[@LINE+3]]:26 = #0
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:23 -> [[@LINE+3]]:26 = 0
   // CHECK-NEXT: Gap,File 0, [[@LINE+2]]:41 -> [[@LINE+2]]:42 = #7
   // CHECK: File 0, [[@LINE+1]]:42 -> [[@LINE+1]]:44 = #7
   for (DECL(int, j) : ARR(int, 1, 2, 3)) {}
@@ -92,21 +92,21 @@ void foo(int i) {
   // CHECK-NEXT: File 0, [[@LINE+5]]:10 -> [[@LINE+5]]:11 = #0
   // CHECK-NEXT: Branch,File 0, [[@LINE+4]]:10 -> [[@LINE+4]]:11 = #8, (#0 - #8)
   // CHECK-NEXT: Gap,File 0, [[@LINE+3]]:13 -> [[@LINE+3]]:14 = #8
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+2]]:14 -> [[@LINE+2]]:20 = #0
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:23 -> [[@LINE+1]]:29 = #0
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+2]]:14 -> [[@LINE+2]]:20 = 0
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:23 -> [[@LINE+1]]:29 = 0
   (void)(i ? PRIo64 : PRIu64);
 
   // CHECK-NEXT: File 0, [[@LINE+6]]:10 -> [[@LINE+6]]:11 = #0
   // CHECK: File 0, [[@LINE+5]]:14 -> [[@LINE+5]]:15 = #9
   // CHECK-NEXT: File 0, [[@LINE+4]]:18 -> [[@LINE+4]]:33 = (#0 - #9)
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:18 -> [[@LINE+3]]:22 = (#0 - #9)
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:18 -> [[@LINE+3]]:22 = 0
   // CHECK: File 0, [[@LINE+2]]:28 -> [[@LINE+2]]:29 = #10
   // CHECK-NEXT: File 0, [[@LINE+1]]:32 -> [[@LINE+1]]:33 = ((#0 - #9) - #10)
   (void)(i ? i : EXPR(i) ? i : 0);
   // CHECK-NEXT: File 0, [[@LINE+5]]:10 -> [[@LINE+5]]:11 = #0
   // CHECK-NEXT: Branch,File 0, [[@LINE+4]]:10 -> [[@LINE+4]]:11 = #11, (#0 - #11)
   // CHECK-NEXT: File 0, [[@LINE+3]]:15 -> [[@LINE+3]]:27 = (#0 - #11)
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+2]]:15 -> [[@LINE+2]]:19 = (#0 - #11)
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+2]]:15 -> [[@LINE+2]]:19 = 0
   // CHECK-NEXT: File 0, [[@LINE+1]]:26 -> [[@LINE+1]]:27 = ((#0 - #11) - #12)
   (void)(i ?: EXPR(i) ?: 0);
 }
@@ -128,10 +128,10 @@ void foo(int i) {
 // CHECK-NEXT: File {{[0-9]+}}, 5:20 -> 5:23 = #0
 // CHECK-NEXT: File {{[0-9]+}}, 9:25 -> 9:40 = #0
 // CHECK-NEXT: File {{[0-9]+}}, 12:16 -> 12:42 = #0
-// CHECK-NEXT: Expansion,File {{[0-9]+}}, 12:16 -> 12:38 = #8
+// CHECK-NEXT: Expansion,File {{[0-9]+}}, 12:16 -> 12:38 = 0
 // CHECK-NEXT: File {{[0-9]+}}, 12:38 -> 12:42 = #8
 // CHECK-NEXT: File {{[0-9]+}}, 13:16 -> 13:42 = #0
-// CHECK-NEXT: Expansion,File {{[0-9]+}}, 13:16 -> 13:38 = (#0 - #8)
+// CHECK-NEXT: Expansion,File {{[0-9]+}}, 13:16 -> 13:38 = 0
 // CHECK-NEXT: File {{[0-9]+}}, 13:38 -> 13:42 = (#0 - #8)
 // CHECK-NEXT: File {{[0-9]+}}, 3:17 -> 3:20 = (#0 - #9)
 // CHECK-NEXT: Branch,File {{[0-9]+}}, 3:17 -> 3:20 = #10, ((#0 - #9) - #10)
diff --git a/clang/test/CoverageMapping/macroception.c b/clang/test/CoverageMapping/macroception.c
index 6d4b3ed427f7f..ddcee3e398abc 100644
--- a/clang/test/CoverageMapping/macroception.c
+++ b/clang/test/CoverageMapping/macroception.c
@@ -6,41 +6,41 @@
 #define M11 M22
 
 // CHECK-LABEL: main:
-// CHECK-NEXT: Expansion,File 0, [[@LINE+2]]:16 -> [[@LINE+2]]:18 = #0
+// CHECK-NEXT: Expansion,File 0, [[@LINE+2]]:16 -> [[@LINE+2]]:18 = 0
 // CHECK-NEXT: File 0, [[@LINE+1]]:18 -> [[@LINE+3]]:2 = #0
 int main(void) M1
   return 0;
 }
-// CHECK-NEXT: Expansion,File 1, 4:12 -> 4:14 = #0
+// CHECK-NEXT: Expansion,File 1, 4:12 -> 4:14 = 0
 // CHECK-NEXT: File 2, 3:12 -> 3:13 = #0
 
 // CHECK-LABEL: func2:
 // CHECK-NEXT: File 0, [[@LINE+2]]:18 -> [[@LINE+4]]:4 = #0
-// CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:1 -> [[@LINE+3]]:4 = #0
+// CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:1 -> [[@LINE+3]]:4 = 0
 void func2(void) {
   int x = 0;
 M11
-// CHECK-NEXT: Expansion,File 1, 6:13 -> 6:16 = #0
+// CHECK-NEXT: Expansion,File 1, 6:13 -> 6:16 = 0
 // CHECK-NEXT: File 2, 5:13 -> 5:14 = #0
 
 // CHECK-LABEL: func3:
-// CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:18 -> [[@LINE+3]]:20 = #0
+// CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:18 -> [[@LINE+3]]:20 = 0
 // CHECK-NEXT: File 0, [[@LINE+2]]:20 -> [[@LINE+4]]:4 = #0
-// CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:1 -> [[@LINE+3]]:4 = #0
+// CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:1 -> [[@LINE+3]]:4 = 0
 void func3(void) M1
   int x = 0;
 M11
-// CHECK-NEXT: Expansion,File 1, 4:12 -> 4:14 = #0
-// CHECK-NEXT: Expansion,File 2, 6:13 -> 6:16 = #0
+// CHECK-NEXT: Expansion,File 1, 4:12 -> 4:14 = 0
+// CHECK-NEXT: Expansion,File 2, 6:13 -> 6:16 = 0
 // CHECK-NEXT: File 3, 3:12 -> 3:13 = #0
 // CHECK-NEXT: File 4, 5:13 -> 5:14 = #0
 
 // CHECK-LABEL: func4:
-// CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:18 -> [[@LINE+3]]:20 = #0
+// CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:18 -> [[@LINE+3]]:20 = 0
 // CHECK-NEXT: File 0, [[@LINE+2]]:20 -> [[@LINE+2]]:24 = #0
-// CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:21 -> [[@LINE+1]]:24 = #0
+// CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:21 -> [[@LINE+1]]:24 = 0
 void func4(void) M1 M11
-// CHECK-NEXT: Expansion,File 1, 4:12 -> 4:14 = #0
-// CHECK-NEXT: Expansion,File 2, 6:13 -> 6:16 = #0
+// CHECK-NEXT: Expansion,File 1, 4:12 -> 4:14 = 0
+// CHECK-NEXT: Expansion,File 2, 6:13 -> 6:16 = 0
 // CHECK-NEXT: File 3, 3:12 -> 3:13 = #0
 // CHECK-NEXT: File 4, 5:13 -> 5:14 = #0
diff --git a/clang/test/CoverageMapping/macroparams.c b/clang/test/CoverageMapping/macroparams.c
index 2f60cffbfdb77..227ee2d0e355b 100644
--- a/clang/test/CoverageMapping/macroparams.c
+++ b/clang/test/CoverageMapping/macroparams.c
@@ -2,10 +2,10 @@
 
 // CHECK: main
 // CHECK-NEXT: File 0, {{[0-9]+}}:16 -> {{[0-9]+}}:2 = #0
-// CHECK-NEXT: Expansion,File 0, {{[0-9]+}}:3 -> {{[0-9]+}}:8 = #0
+// CHECK-NEXT: Expansion,File 0, {{[0-9]+}}:3 -> {{[0-9]+}}:8 = 0
 
 // CHECK-NEXT: File 1, [[@LINE+2]]:18 -> [[@LINE+2]]:27 = #0
-// CHECK-NEXT: Expansion,File 1, [[@LINE+1]]:18 -> [[@LINE+1]]:24 = #0
+// CHECK-NEXT: Expansion,File 1, [[@LINE+1]]:18 -> [[@LINE+1]]:24 = 0
 #define MACRO(X) MACRO2(x)
 // CHECK-NEXT: File 2, [[@LINE+1]]:20 -> [[@LINE+1]]:28 = #0
 #define MACRO2(X2) (X2 + 2)
diff --git a/clang/test/CoverageMapping/macroparams2.c b/clang/test/CoverageMapping/macroparams2.c
index 7873b6ac12a9a..27323bdb384fc 100644
--- a/clang/test/CoverageMapping/macroparams2.c
+++ b/clang/test/CoverageMapping/macroparams2.c
@@ -10,7 +10,7 @@ struct S {
 int main(void) {
   struct S arr[32] = { 0 };
   int n = 0;
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:7 -> [[@LINE+3]]:12 = #0
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:7 -> [[@LINE+3]]:12 = 0
   // CHECK-NEXT: Gap,File 0, [[@LINE+2]]:33 -> [[@LINE+2]]:34 = #1
   // CHECK-NEXT: File 0, [[@LINE+1]]:34 -> [[@LINE+3]]:4 = #1
   if (MACRO(arr[n].j, arr[n].i)) {
diff --git a/clang/test/CoverageMapping/macros.c b/clang/test/CoverageMapping/macros.c
index 00139f33229d5..a4acc8699e9fb 100644
--- a/clang/test/CoverageMapping/macros.c
+++ b/clang/test/CoverageMapping/macros.c
@@ -11,7 +11,7 @@ void bar(void) {}
 // CHECK: func
 void func(void) {  // CHECK-NEXT: File 0, [[@LINE]]:17 -> [[@LINE+5]]:2 = #0
   int i = 0;
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:3 -> [[@LINE+1]]:8 = #0
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:3 -> [[@LINE+1]]:8 = 0
   MACRO;       // CHECK-NEXT: File 0, [[@LINE]]:8 -> [[@LINE+2]]:2 = 0
   i = 2;
 }
@@ -21,7 +21,7 @@ void func(void) {  // CHECK-NEXT: File 0, [[@LINE]]:17 -> [[@LINE+5]]:2 = #0
 // CHECK-NEXT: func2
 void func2(void) { // CHECK-NEXT: File 0, [[@LINE]]:18 -> [[@LINE+5]]:2 = #0
   int i = 0;
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:3 -> [[@LINE+1]]:10 = #0
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:3 -> [[@LINE+1]]:10 = 0
   MACRO_1;     // CHECK-NEXT: File 0, [[@LINE]]:10 -> [[@LINE+2]]:2 = 0
   i = 2;
 }
@@ -31,8 +31,8 @@ void func2(void) { // CHECK-NEXT: File 0, [[@LINE]]:18 -> [[@LINE+5]]:2 = #0
 
 // CHECK-NEXT: func3
 void func3(void) { // CHECK-NEXT: File 0, [[@LINE]]:18 -> [[@LINE+3]]:2 = #0
-  MACRO_2; // CHECK-NEXT: Expansion,File 0, [[@LINE]]:3 -> [[@LINE]]:10 = #0
-  MACRO_2; // CHECK-NEXT: Expansion,File 0, [[@LINE]]:3 -> [[@LINE]]:10 = #0
+  MACRO_2; // CHECK-NEXT: Expansion,File 0, [[@LINE]]:3 -> [[@LINE]]:10 = 0
+  MACRO_2; // CHECK-NEXT: Expansion,File 0, [[@LINE]]:3 -> [[@LINE]]:10 = 0
 }
 // CHECK-NEXT: File 1, 4:17 -> 4:22 = #0
 // CHECK-NEXT: File 2, 4:17 -> 4:22 = #0
@@ -45,7 +45,7 @@ void func4(void) { // CHECK-NEXT: File 0, [[@LINE]]:18 -> [[@LINE+8]]:2 = #0
                // CHECK-NEXT: File 0, [[@LINE-1]]:9 -> [[@LINE-1]]:14 = #1
                // CHECK-NEXT: Branch,File 0, [[@LINE-2]]:9 -> [[@LINE-2]]:14 = #2, (#1 - #2)
                // CHECK-NEXT: Gap,File 0, [[@LINE-3]]:15 -> [[@LINE+1]]:7 = #2
-      MACRO_2; // CHECK-NEXT: Expansion,File 0, [[@LINE]]:7 -> [[@LINE]]:14 = #2
+      MACRO_2; // CHECK-NEXT: Expansion,File 0, [[@LINE]]:7 -> [[@LINE]]:14 = 0
 }
 // CHECK-NEXT: File 1, 4:17 -> 4:22 = #2
 // CHECK-NOT: File 1
@@ -56,9 +56,9 @@ void func5(void) { // CHECK-NEXT: File 0, [[@LINE]]:18 -> [[@LINE+6]]:2 = #0
   if (i > 5) // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:12 = #0
              // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:7 -> [[@LINE-1]]:12 = #1, (#0 - #1)
              // CHECK-NEXT: Gap,File 0, [[@LINE-2]]:13 -> [[@LINE+1]]:5 = #1
-    MACRO_3; // CHECK-NEXT: Expansion,File 0, [[@LINE]]:5 -> [[@LINE]]:12 = #1
+    MACRO_3; // CHECK-NEXT: Expansion,File 0, [[@LINE]]:5 -> [[@LINE]]:12 = 0
 }
-// CHECK-NEXT: Expansion,File 1, 6:17 -> 6:24 = #1
+// CHECK-NEXT: Expansion,File 1, 6:17 -> 6:24 = 0
 // CHECK-NEXT: File 2, 4:17 -> 4:22 = #1
 
 // CHECK-NEXT: func6
@@ -69,7 +69,7 @@ void func6(unsigned count) { // CHECK-NEXT: File 0, [[@LINE]]:28 -> [[@LINE+6]]:
                              // CHECK-NEXT: Gap,File 0, [[@LINE-2]]:17 -> [[@LINE+1]]:9 = #2
         GOTO begin;          // CHECK-NEXT: File 0, [[@LINE]]:9 -> [[@LINE]]:19 = #2
 }
-// CHECK-NEXT: Expansion,File 0, [[@LINE-2]]:9 -> [[@LINE-2]]:13 = #2
+// CHECK-NEXT: Expansion,File 0, [[@LINE-2]]:9 -> [[@LINE-2]]:13 = 0
 // CHECK-NEXT: File 1, 7:14 -> 7:18 = #2
 
 // Regression test for gap region between macros.
@@ -80,10 +80,10 @@ 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 = #0
+  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: Expansion,File 0, [[@LINE-2]]:9 -> [[@LINE-2]]:10 = 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)
diff --git a/clang/test/CoverageMapping/macroscopes.cpp b/clang/test/CoverageMapping/macroscopes.cpp
index 88a72116fa7dc..d81a481c06cd7 100644
--- a/clang/test/CoverageMapping/macroscopes.cpp
+++ b/clang/test/CoverageMapping/macroscopes.cpp
@@ -37,49 +37,49 @@
 // CHECK-NEXT: File 0, [[@LINE+1]]:12 -> {{[0-9]+}}:2 = #0
 int main() {
   int x = 0;
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+2]]:3 -> [[@LINE+2]]:17 = #0
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+2]]:3 -> [[@LINE+2]]:17 = 0
   // CHECK-NEXT: File 0, [[@LINE+1]]:17 -> [[@LINE+7]]:15 = #1
   starts_a_scope
     x = x;
-    // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:5 -> [[@LINE+1]]:14 = #1
+    // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:5 -> [[@LINE+1]]:14 = 0
     some_code
     x = x;
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:3 -> [[@LINE+1]]:15 = #1
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:3 -> [[@LINE+1]]:15 = 0
   ends_a_scope
 
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+4]]:3 -> [[@LINE+4]]:17 = #0
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+4]]:3 -> [[@LINE+4]]:17 = 0
   // CHECK-NEXT: File 0, [[@LINE+3]]:17 -> [[@LINE+5]]:15 = #4
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:5 -> [[@LINE+3]]:14 = #4
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:3 -> [[@LINE+3]]:15 = #4
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:5 -> [[@LINE+3]]:14 = 0
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:3 -> [[@LINE+3]]:15 = 0
   starts_a_scope
     some_code
   ends_a_scope
 
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:3 -> [[@LINE+3]]:17 = #0
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:3 -> [[@LINE+3]]:17 = 0
   // CHECK-NEXT: File 0, [[@LINE+2]]:17 -> [[@LINE+3]]:15 = #7
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+2]]:3 -> [[@LINE+2]]:15 = #7
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+2]]:3 -> [[@LINE+2]]:15 = 0
   starts_a_scope
   ends_a_scope
 
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:3 -> [[@LINE+3]]:17 = #0
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:3 -> [[@LINE+3]]:17 = 0
   // CHECK-NEXT: Gap,File 0, [[@LINE+2]]:17 -> [[@LINE+3]]:5 = #8
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+2]]:5 -> [[@LINE+2]]:16 = #8
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+2]]:5 -> [[@LINE+2]]:16 = 0
   starts_a_while
     simple_stmt;
 
   x = 0;
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+5]]:3 -> [[@LINE+5]]:17 = #0
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+5]]:3 -> [[@LINE+5]]:17 = 0
   // CHECK-NEXT: Gap,File 0, [[@LINE+4]]:17 -> [[@LINE+4]]:18 = #9
   // CHECK-NEXT: File 0, [[@LINE+3]]:18 -> [[@LINE+5]]:15 = #9
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:5 -> [[@LINE+3]]:16 = #9
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:3 -> [[@LINE+3]]:15 = #9
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:5 -> [[@LINE+3]]:16 = 0
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+3]]:3 -> [[@LINE+3]]:15 = 0
   starts_a_while {
     simple_stmt;
   ends_a_scope
 
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:3 -> [[@LINE+1]]:17 = #0
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:3 -> [[@LINE+1]]:17 = 0
   macro_with_for
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:3 -> [[@LINE+1]]:19 = #0
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:3 -> [[@LINE+1]]:19 = 0
   macro_with_while
 
   return 0;
diff --git a/clang/test/CoverageMapping/mcdc-scratch-space.c b/clang/test/CoverageMapping/mcdc-scratch-space.c
index 60e456948a518..b5252d6c5d406 100644
--- a/clang/test/CoverageMapping/mcdc-scratch-space.c
+++ b/clang/test/CoverageMapping/mcdc-scratch-space.c
@@ -19,7 +19,7 @@ int builtin_macro1(int a) {
 // CHECK: pre0:
 int pre0(int pre_a, int b_post) {
   // CHECK: Decision,File 0, [[@LINE+2]]:11 -> [[@LINE+3]]:20 = M:3, C:2
-  // CHECK: Expansion,File 0, [[@LINE+1]]:11 -> [[@LINE+1]]:14 = #0 (Expanded file = 1)
+  // CHECK: Expansion,File 0, [[@LINE+1]]:11 -> [[@LINE+1]]:14 = 0 (Expanded file = 1)
   return (PRE(a)
           && b_post);
   // CHECK: Branch,File 0, [[@LINE-1]]:14 -> [[@LINE-1]]:20 = #2, (#1 - #2) [2,0,0]
@@ -31,11 +31,11 @@ int pre0(int pre_a, int b_post) {
 // CHECK: pre1:
 int pre1(int pre_a, int b_post) {
   // CHECK: Decision,File 0, [[@LINE+3]]:11 -> [[@LINE+4]]:20 = M:3, C:2
-  // CHECK: Expansion,File 0, [[@LINE+2]]:11 -> [[@LINE+2]]:14 = #0 (Expanded file = 1)
+  // CHECK: Expansion,File 0, [[@LINE+2]]:11 -> [[@LINE+2]]:14 = 0 (Expanded file = 1)
   // CHECK: Branch,File 0, [[@LINE+2]]:14 -> [[@LINE+2]]:20 = #2, (#1 - #2) [2,0,0]
   return (PRE(foo)
           && b_post);
-  // CHECK: Expansion,File 1, 17:16 -> 17:20 = #0 (Expanded file = 2)
+  // CHECK: Expansion,File 1, 17:16 -> 17:20 = 0 (Expanded file = 2)
   // CHECK: Branch,File 2, 29:17 -> 29:22 = #1, (#0 - #1) [1,2,0]
 }
 
@@ -47,7 +47,7 @@ int post0(int pre_a, int b_post) {
   // CHECK: Branch,File 0, [[@LINE+1]]:11 -> [[@LINE+1]]:16 = (#0 - #1), #1 [1,0,2]
   return (pre_a
           || POST(b));
-  // CHECK: Expansion,File 0, [[@LINE-1]]:14 -> [[@LINE-1]]:18 = #1 (Expanded file = 1)
+  // CHECK: Expansion,File 0, [[@LINE-1]]:14 -> [[@LINE-1]]:18 = 0 (Expanded file = 1)
   // CHECK: Branch,File 1, [[@LINE-9]]:17 -> [[@LINE-9]]:20 = (#1 - #2), #2 [2,0,0]
 }
 
@@ -60,6 +60,6 @@ int post1(int pre_a, int b_post) {
   // CHECK: Expansion,File 0, [[@LINE+2]]:14 -> [[@LINE+2]]:18 = 0 (Expanded file = 1)
   return (pre_a
           || POST(bar));
-  // CHECK: Expansion,File 1, 42:17 -> 42:18 = #1 (Expanded file = 2)
+  // CHECK: Expansion,File 1, 42:17 -> 42:18 = 0 (Expanded file = 2)
   // CHECK: Branch,File 2, 54:18 -> 54:24 = (#1 - #2), #2 [2,0,0]
 }
diff --git a/clang/test/CoverageMapping/mcdc-system-headers.cpp b/clang/test/CoverageMapping/mcdc-system-headers.cpp
index cb1c8743c36e8..b2fa7af5872c1 100644
--- a/clang/test/CoverageMapping/mcdc-system-headers.cpp
+++ b/clang/test/CoverageMapping/mcdc-system-headers.cpp
@@ -16,7 +16,7 @@
 // CHECK: _Z5func0i:
 int func0(int a) {
   // CHECK: Decision,File 0, [[@LINE+3]]:11 -> [[@LINE+3]]:21 = M:3, C:2
-  // W_SYS: Expansion,File 0, [[@LINE+2]]:11 -> [[@LINE+2]]:16 = #0 (Expanded file = 1)
+  // W_SYS: Expansion,File 0, [[@LINE+2]]:11 -> [[@LINE+2]]:16 = 0 (Expanded file = 1)
   // X_SYS: Branch,File 0, [[@LINE+1]]:11 -> [[@LINE+1]]:11 = #1, 0 [1,2,0]
   return (CONST && a);
   // CHECK: Branch,File 0, [[@LINE-1]]:20 -> [[@LINE-1]]:21 = #2, (#1 - #2) [2,0,0]
@@ -28,7 +28,7 @@ int func1(int a, int b) {
   // CHECK: Decision,File 0, [[@LINE+2]]:11 -> [[@LINE+2]]:21 = M:3, C:2
   // CHECK: Branch,File 0, [[@LINE+1]]:11 -> [[@LINE+1]]:12 = (#0 - #1), #1 [1,0,2]
   return (a || EXPR1(b));
-  // W_SYS: Expansion,File 0, [[@LINE-1]]:16 -> [[@LINE-1]]:21 = #1 (Expanded file = 1)
+  // W_SYS: Expansion,File 0, [[@LINE-1]]:16 -> [[@LINE-1]]:21 = 0 (Expanded file = 1)
   // W_SYS: Branch,File 1, [[@LINE-24]]:18 -> [[@LINE-24]]:21 = (#1 - #2), #2 [2,0,0]
   // X_SYS: Branch,File 0, [[@LINE-3]]:16 -> [[@LINE-3]]:16 = (#1 - #2), #2 [2,0,0]
 }
@@ -37,8 +37,8 @@ int func1(int a, int b) {
 int func2(int a, int b) {
   // W_SYS: Decision,File 0, [[@LINE+5]]:11 -> [[@LINE+5]]:28 = M:4, C:3
   // X_SYS: Decision,File 0, [[@LINE+4]]:11 -> [[@LINE+4]]:28 = M:3, C:2
-  // W_SYS: Expansion,File 0, [[@LINE+3]]:11 -> [[@LINE+3]]:16 = #0 (Expanded file = 1)
-  // W_SYS: Expansion,File 0, [[@LINE+2]]:23 -> [[@LINE+2]]:28 = #1 (Expanded file = 2)
+  // W_SYS: Expansion,File 0, [[@LINE+3]]:11 -> [[@LINE+3]]:16 = 0 (Expanded file = 1)
+  // W_SYS: Expansion,File 0, [[@LINE+2]]:23 -> [[@LINE+2]]:28 = 0 (Expanded file = 2)
   // X_SYS: Branch,File 0, [[@LINE+1]]:11 -> [[@LINE+1]]:11 = #1, (#0 - #1) [1,2,0]
   return (EXPR2(a) && EXPR1(a));
   // W_SYS: Branch,File 1, [[@LINE-35]]:19 -> [[@LINE-35]]:22 = #3, (#0 - #3) [1,3,0]
diff --git a/clang/test/CoverageMapping/moremacros.c b/clang/test/CoverageMapping/moremacros.c
index 64e5c62bfac37..aeda4e81699bd 100644
--- a/clang/test/CoverageMapping/moremacros.c
+++ b/clang/test/CoverageMapping/moremacros.c
@@ -12,18 +12,18 @@ int main(int argc, const char *argv[]) {
   // CHECK-NEXT: File 0, [[@LINE+5]]:7 -> [[@LINE+5]]:12 = #0
   // CHECK-NEXT: Branch,File 0, [[@LINE+4]]:7 -> [[@LINE+4]]:12 = #2, (#0 - #2)
   // CHECK-NEXT: Gap,File 0, [[@LINE+3]]:13 -> [[@LINE+3]]:14 = #2
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+2]]:14 -> [[@LINE+2]]:19 = #2
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+2]]:14 -> [[@LINE+2]]:19 = 0
   // CHECK-NEXT: File 0, [[@LINE+1]]:19 -> [[@LINE+4]]:8 = #2
   if (!argc) LBRAC
     return 0;
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:3 -> [[@LINE+1]]:8 = #2
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:3 -> [[@LINE+1]]:8 = 0
   RBRAC // CHECK-NEXT: [[@LINE]]:8 -> [[@LINE+8]]:3 = (#0 - #2)
 
   // CHECK-NEXT: File 0, [[@LINE+6]]:3 -> [[@LINE+17]]:2 = (#0 - #2)
   // CHECK-NEXT: File 0, [[@LINE+5]]:7 -> [[@LINE+5]]:12 = (#0 - #2)
   // CHECK-NEXT: Branch,File 0, [[@LINE+4]]:7 -> [[@LINE+4]]:12 = #3, ((#0 - #2) - #3)
   // CHECK-NEXT: Gap,File 0, [[@LINE+3]]:13 -> [[@LINE+3]]:14 = #3
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+2]]:14 -> [[@LINE+2]]:19 = #3
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+2]]:14 -> [[@LINE+2]]:19 = 0
   // CHECK-NEXT: File 0, [[@LINE+1]]:19 -> [[@LINE+3]]:4 = #3
   if (!argc) LBRAC
     return 0;
@@ -34,7 +34,7 @@ int main(int argc, const char *argv[]) {
   // CHECK: File 0, [[@LINE+1]]:14 -> [[@LINE+4]]:8 = #4
   if (!argc) {
     return 0;
-  // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:3 -> [[@LINE+1]]:8 = #4
+  // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:3 -> [[@LINE+1]]:8 = 0
   RBRAC
 }
 
diff --git a/clang/test/CoverageMapping/switchmacro.c b/clang/test/CoverageMapping/switchmacro.c
index 4c98cc7d9403a..e65529a33d3bb 100644
--- a/clang/test/CoverageMapping/switchmacro.c
+++ b/clang/test/CoverageMapping/switchmacro.c
@@ -11,7 +11,7 @@ int foo(int i) { // CHECK-NEXT: File 0, [[@LINE]]:16 -> {{[0-9]+}}:2 = #0
                  // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:9 -> [[@LINE-1]]:15 = #3, (#2 - #3)
       return 0;  // CHECK: File 0, [[@LINE]]:7 -> [[@LINE]]:15 = #3
                  // CHECK-NEXT: File 0, [[@LINE-1]]:16 -> [[@LINE+3]]:5 = (#2 - #3)
-    // CHECK-NEXT: Expansion,File 0, [[@LINE+2]]:5 -> [[@LINE+2]]:8 = (#2 - #3) (Expanded file = 1)
+    // CHECK-NEXT: Expansion,File 0, [[@LINE+2]]:5 -> [[@LINE+2]]:8 = 0 (Expanded file = 1)
     // CHECK-NEXT: File 0, [[@LINE+1]]:8 -> {{[0-9]+}}:11 = (#2 - #3)
     FOO(1);
   case 0:        // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:13 = ((#2 + #4) - #3)
@@ -41,7 +41,7 @@ default: ;
 #define START2 switch (0) default:
 void baz(void) {
   for (;;)
-    START2 return; // CHECK: Expansion,File 0, [[@LINE]]:5 -> [[@LINE]]:11 = #1 (Expanded file = 1)
+    START2 return; // CHECK: Expansion,File 0, [[@LINE]]:5 -> [[@LINE]]:11 = 0 (Expanded file = 1)
 }
 
 int main(int argc, const char *argv[]) {
diff --git a/clang/test/CoverageMapping/trymacro.cpp b/clang/test/CoverageMapping/trymacro.cpp
index 22de2ccb07769..6876908be6cdc 100644
--- a/clang/test/CoverageMapping/trymacro.cpp
+++ b/clang/test/CoverageMapping/trymacro.cpp
@@ -19,7 +19,7 @@ CATCH(...) {}              // CHECK: [[@LINE]]:12 -> [[@LINE]]:14 = #2
 
 // CHECK: Z3fn4v:
 #define TRY2 try { // CHECK-DAG: File 1, [[@LINE]]:18 -> [[@LINE]]:19 = #1
-void fn4() TRY2 // CHECK-DAG: Expansion,File 0, [[@LINE]]:12 -> [[@LINE]]:16 = #1 (Expanded file = 1)
+void fn4() TRY2 // CHECK-DAG: Expansion,File 0, [[@LINE]]:12 -> [[@LINE]]:16 = 0 (Expanded file = 1)
   for (;;)
     return;
 }
@@ -27,10 +27,10 @@ catch (...) {}
 
 // CHECK: Z3fn5v:
 #define TRY3 try { return; } catch (...) // CHECK-DAG: File 2, [[@LINE]]:18 -> [[@LINE]]:29 = #1
-#define TRY4 try { TRY3 { return; } } catch (...) // CHECK-DAG: Expansion,File 1, [[@LINE]]:20 -> [[@LINE]]:24 = #1 (Expanded file = 2)
+#define TRY4 try { TRY3 { return; } } catch (...) // CHECK-DAG: Expansion,File 1, [[@LINE]]:20 -> [[@LINE]]:24 = 0 (Expanded file = 2)
 void fn5() {
   for (;;) {
-    TRY4 { return; } // CHECK-DAG: Expansion,File 0, [[@LINE]]:5 -> [[@LINE]]:9 = #1 (Expanded file = 1)
+    TRY4 { return; } // CHECK-DAG: Expansion,File 0, [[@LINE]]:5 -> [[@LINE]]:9 = 0 (Expanded file = 1)
   }                  // CHECK-DAG: File 0, [[@LINE-1]]:10 -> [[@LINE-1]]:21 = #5
 }
 
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index 8c5eae9015abe..5cfd4330479ad 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -704,6 +704,8 @@ struct CountedRegionEmitter {
 
   /// Evaluated Counters.
   std::map<Counter, uint64_t> CounterValues;
+  /// Induced Counter values for Expansions.
+  DenseMap<const CounterMappingRegion *, uint64_t> ExpansionCounterValues;
 
   /// Decisions are nestable.
   SmallVector<DecisionRecord, 1> DecisionStack;
@@ -746,18 +748,20 @@ struct CountedRegionEmitter {
   }
 
   /// Evaluate C and store its evaluated Value into CounterValues.
-  Error evaluateAndCacheCounter(Counter C) {
-    if (CounterValues.count(C) > 0)
-      return Error::success();
+  Expected<uint64_t> evaluateAndCacheCounter(Counter C) {
+    auto C1 = CounterValues.find(C);
+    if (C1 != CounterValues.end())
+      return C1->second; // Cached
 
     auto ValueOrErr = Ctx.evaluate(C);
     if (!ValueOrErr)
       return ValueOrErr.takeError();
     CounterValues[C] = *ValueOrErr;
-    return Error::success();
+    return ValueOrErr;
   }
 
-  Error walk(unsigned Idx) {
+  Expected<uint64_t> walk(unsigned Idx) {
+    std::optional<uint64_t> FirstCnt;
     assert(Idx < Files.size());
     unsigned B = (Idx == 0 ? 0 : Files[Idx - 1].LastIndex);
     unsigned E = Files[Idx].LastIndex;
@@ -768,12 +772,27 @@ struct CountedRegionEmitter {
       if (Region.FileID != Idx)
         break;
 
-      if (Region.Kind == CounterMappingRegion::ExpansionRegion)
-        if (auto E = walk(Region.ExpandedFileID))
-          return E;
+      if (Region.Kind == CounterMappingRegion::ExpansionRegion) {
+        auto ExpandedCntOrErr = walk(Region.ExpandedFileID);
+        if (!ExpandedCntOrErr)
+          return ExpandedCntOrErr.takeError();
 
-      if (auto E = evaluateAndCacheCounter(Region.Count))
-        return E;
+        // Expansion doesn't have Counters.
+        assert(Region.Count.isZero());
+        ExpansionCounterValues[&Region] = *ExpandedCntOrErr;
+        // Propagate Expanded Count to parent.
+        if (!FirstCnt)
+          FirstCnt = *ExpandedCntOrErr;
+
+        continue;
+      }
+
+      auto TrueCntOrErr = evaluateAndCacheCounter(Region.Count);
+      if (!TrueCntOrErr)
+        return TrueCntOrErr.takeError();
+      // Propagate 1st Count to parent.
+      if (!FirstCnt)
+        FirstCnt = *TrueCntOrErr;
 
       if (Region.Kind == CounterMappingRegion::MCDCDecisionRegion) {
         // Start the new Decision on the stack.
@@ -797,13 +816,13 @@ struct CountedRegionEmitter {
 
       // Evaluate FalseCount
       // It may have the Counter in Branches, or Zero.
-      if (auto E = evaluateAndCacheCounter(Region.FalseCount))
-        return E;
+      if (auto E = evaluateAndCacheCounter(Region.FalseCount); !E)
+        return E.takeError();
     }
 
     assert((Idx != 0 || DecisionStack.empty()) && "Decision wasn't closed");
 
-    return Error::success();
+    return (FirstCnt ? *FirstCnt : 0);
   }
 
   Error emitCountedRegions() {
@@ -812,8 +831,8 @@ struct CountedRegionEmitter {
     // - Emit MCDCRecords
     for (auto [I, F] : enumerate(Files)) {
       if (!F.IsExpanded)
-        if (auto E = walk(I))
-          return E;
+        if (auto E = walk(I); !E)
+          return E.takeError();
     }
     assert(Visited.size() == Files.size() && "Dangling FileID");
 
@@ -821,6 +840,14 @@ struct CountedRegionEmitter {
     for (const auto &Region : Record.MappingRegions) {
       if (Region.Kind == CounterMappingRegion::MCDCDecisionRegion)
         continue; // Don't emit.
+
+      if (auto EI = ExpansionCounterValues.find(&Region);
+          EI != ExpansionCounterValues.end()) {
+        // Adopt the Counter value induced in the Recorder.
+        Function.pushRegion(Region, EI->second, 0);
+        continue;
+      }
+
       // Adopt values from the CounterValues.
       // FalseCount may be Zero unless Branches.
       Function.pushRegion(Region, CounterValues[Region.Count],
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
index cdf4412c6477a..d15355dc6e07d 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
@@ -437,28 +437,6 @@ Error RawCoverageMappingReader::read() {
       return Err;
   }
 
-  // Set the counters for the expansion regions.
-  // i.e. Counter of expansion region = counter of the first region
-  // from the expanded file.
-  // Perform multiple passes to correctly propagate the counters through
-  // all the nested expansion regions.
-  SmallVector<CounterMappingRegion *, 8> FileIDExpansionRegionMapping;
-  FileIDExpansionRegionMapping.resize(VirtualFileMapping.size(), nullptr);
-  for (unsigned Pass = 1, S = VirtualFileMapping.size(); Pass < S; ++Pass) {
-    for (auto &R : MappingRegions) {
-      if (R.Kind != CounterMappingRegion::ExpansionRegion)
-        continue;
-      assert(!FileIDExpansionRegionMapping[R.ExpandedFileID]);
-      FileIDExpansionRegionMapping[R.ExpandedFileID] = &R;
-    }
-    for (auto &R : MappingRegions) {
-      if (FileIDExpansionRegionMapping[R.FileID]) {
-        FileIDExpansionRegionMapping[R.FileID]->Count = R.Count;
-        FileIDExpansionRegionMapping[R.FileID] = nullptr;
-      }
-    }
-  }
-
   return Error::success();
 }
 
diff --git a/llvm/unittests/ProfileData/CoverageMappingTest.cpp b/llvm/unittests/ProfileData/CoverageMappingTest.cpp
index 46f881ecddb5f..945d0acdc7026 100644
--- a/llvm/unittests/ProfileData/CoverageMappingTest.cpp
+++ b/llvm/unittests/ProfileData/CoverageMappingTest.cpp
@@ -707,13 +707,16 @@ TEST_P(CoverageMappingTest, expansion_gets_first_counter) {
   addCMR(Counter::getCounter(2), "foo", 1, 1, 20, 1);
   addExpansionCMR("bar", "foo", 3, 3, 3, 3);
 
-  writeAndReadCoverageRegions();
-  ASSERT_EQ(1u, OutputFunctions.size());
-  OutputFunctionCoverageData &Output = OutputFunctions.back();
+  ProfileWriter.addRecord({"func", 0x1234, {1, 2, 4}}, Err);
+  EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());
+
+  auto FunctionRecords = LoadedCoverage->getCoveredFunctions();
+  ASSERT_EQ(1u, std::distance(FunctionRecords.begin(), FunctionRecords.end()));
 
-  ASSERT_EQ(CounterMappingRegion::ExpansionRegion, Output.Regions[2].Kind);
-  ASSERT_EQ(Counter::getCounter(2), Output.Regions[2].Count);
-  ASSERT_EQ(3U, Output.Regions[2].LineStart);
+  const auto &CR = (*FunctionRecords.begin()).CountedRegions;
+  ASSERT_EQ(CounterMappingRegion::ExpansionRegion, CR[2].Kind);
+  ASSERT_EQ(4u, CR[2].ExecutionCount);
+  ASSERT_EQ(3U, CR[2].LineStart);
 }
 
 TEST_P(CoverageMappingTest, basic_coverage_iteration) {



More information about the llvm-commits mailing list