https://github.com/fmeum updated 
https://github.com/llvm/llvm-project/pull/233136

>From 7f0521f607c975cef45b9f8ad8ccde33a7b81fee Mon Sep 17 00:00:00 2001
From: Fabian Meumertzheim <[email protected]>
Date: Sat, 17 Oct 2026 22:56:52 +0200
Subject: [PATCH] [Coverage] Only look at skipped ranges near the regions of a
 function

For every used function, gatherSkippedRegions adjusted every skipped
range (comment, empty line, #if 0 block) seen so far in the translation
unit, which is quadratic. Instead, index the skipped ranges by file and
location and only look at those near the function's lines. The mappings
don't change, except that comments in _Pragma strings no longer hit the
"region spans multiple files" assertion.

Assisted-by: Claude Code, OpenAI Codex
---
 clang/lib/CodeGen/CoverageMappingGen.cpp    | 94 +++++++++++++++------
 clang/lib/CodeGen/CoverageMappingGen.h      | 17 +++-
 clang/test/CoverageMapping/pragma-comment.c | 11 +++
 3 files changed, 91 insertions(+), 31 deletions(-)
 create mode 100644 clang/test/CoverageMapping/pragma-comment.c

diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp 
b/clang/lib/CodeGen/CoverageMappingGen.cpp
index 970812f7b0f754..34d6732237fc54 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -103,6 +103,38 @@ void CoverageSourceInfo::updateNextTokLoc(SourceLocation 
Loc) {
     SkippedRanges.back().NextTokLoc = Loc;
 }
 
+SmallVector<SkippedRange, 0>
+CoverageSourceInfo::getSkippedRangesIn(SourceRange Range) {
+  // Index the skipped ranges added since the last call. As they are mostly
+  // added in source order, they are usually appended.
+  for (unsigned I = NumIndexedSkippedRanges; I < SkippedRanges.size(); ++I) {
+    SourceLocation Begin = SkippedRanges[I].Range.getBegin();
+    auto &Indices = SkippedRangesByFile[SourceMgr.getFileID(Begin)];
+    Indices.insert(llvm::upper_bound(Indices, Begin,
+                                     [&](SourceLocation Loc, unsigned J) {
+                                       return Loc <
+                                              
SkippedRanges[J].Range.getBegin();
+                                     }),
+                   I);
+  }
+  NumIndexedSkippedRanges = SkippedRanges.size();
+
+  SmallVector<SkippedRange, 0> Result;
+  auto It = SkippedRangesByFile.find(SourceMgr.getFileID(Range.getBegin()));
+  if (It == SkippedRangesByFile.end())
+    return Result;
+  ArrayRef<unsigned> Indices = It->second;
+  const unsigned *First = llvm::partition_point(Indices, [&](unsigned I) {
+    return SkippedRanges[I].Range.getBegin() < Range.getBegin();
+  });
+  for (unsigned I : llvm::make_range(First, Indices.end())) {
+    if (Range.getEnd() < SkippedRanges[I].Range.getBegin())
+      break;
+    Result.push_back(SkippedRanges[I]);
+  }
+  return Result;
+}
+
 namespace {
 /// A region of source code that can be mapped to a counter.
 class SourceMappingRegion {
@@ -479,34 +511,42 @@ class CoverageMappingBuilder {
           std::max(FileLineRanges[R.FileID].second, R.LineEnd);
     }
 
-    auto SkippedRanges = CVM.getSourceInfo().getSkippedRanges();
-    for (auto &I : SkippedRanges) {
-      SourceRange Range = I.Range;
-      auto LocStart = Range.getBegin();
-      auto LocEnd = Range.getEnd();
-      assert(SM.isWrittenInSameFile(LocStart, LocEnd) &&
-             "region spans multiple files");
-
-      auto CovFileID = getCoverageFileID(LocStart);
-      if (!CovFileID)
-        continue;
-      std::optional<SpellingRegion> SR;
-      if (I.isComment())
-        SR = adjustSkippedRange(SM, LocStart, LocEnd, I.PrevTokLoc,
-                                I.NextTokLoc);
-      else if (I.isPPIfElse() || I.isEmptyLine())
-        SR = {SM, LocStart, LocEnd};
-
-      if (!SR)
+    for (const auto &[File, Mapping] : FileIDMapping) {
+      unsigned CovFileID = Mapping.first;
+      auto [FirstLine, LastLine] = FileLineRanges[CovFileID];
+      // Ignore files without regions and macro expansions, whose skipped
+      // ranges (e.g. comments in _Pragma) don't correspond to lines.
+      if (!SM.getSLocEntry(File).isFile() || FirstLine > LastLine)
         continue;
-      auto Region = CounterMappingRegion::makeSkipped(
-          *CovFileID, SR->LineStart, SR->ColumnStart, SR->LineEnd,
-          SR->ColumnEnd);
-      // Make sure that we only collect the regions that are inside
-      // the source code of this function.
-      if (Region.LineStart >= FileLineRanges[*CovFileID].first &&
-          Region.LineEnd <= FileLineRanges[*CovFileID].second)
-        MappingRegions.push_back(Region);
+      // Only collect the skipped ranges inside the source code of this
+      // function. As adjusting a skipped range may move its start to the next
+      // line, also consider the ones that begin on the line before.
+      SourceLocation Begin =
+          SM.translateLineCol(File, std::max(FirstLine, 2u) - 1, 1);
+      SourceLocation End = SM.translateLineCol(File, LastLine + 1, 1);
+      for (const SkippedRange &I :
+           CVM.getSourceInfo().getSkippedRangesIn({Begin, End})) {
+        SourceRange Range = I.Range;
+        auto LocStart = Range.getBegin();
+        auto LocEnd = Range.getEnd();
+        assert(SM.isWrittenInSameFile(LocStart, LocEnd) &&
+               "region spans multiple files");
+
+        std::optional<SpellingRegion> SR;
+        if (I.isComment())
+          SR = adjustSkippedRange(SM, LocStart, LocEnd, I.PrevTokLoc,
+                                  I.NextTokLoc);
+        else if (I.isPPIfElse() || I.isEmptyLine())
+          SR = {SM, LocStart, LocEnd};
+
+        if (!SR)
+          continue;
+        auto Region = CounterMappingRegion::makeSkipped(
+            CovFileID, SR->LineStart, SR->ColumnStart, SR->LineEnd,
+            SR->ColumnEnd);
+        if (Region.LineStart >= FirstLine && Region.LineEnd <= LastLine)
+          MappingRegions.push_back(Region);
+      }
     }
   }
 
diff --git a/clang/lib/CodeGen/CoverageMappingGen.h 
b/clang/lib/CodeGen/CoverageMappingGen.h
index 0ed50597e1dc3e..aa2c2efa811581 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.h
+++ b/clang/lib/CodeGen/CoverageMappingGen.h
@@ -50,9 +50,9 @@ struct SkippedRange {
   // The nature of this skipped range
   Kind RangeKind;
 
-  bool isComment() { return RangeKind == Comment; }
-  bool isEmptyLine() { return RangeKind == EmptyLine; }
-  bool isPPIfElse() { return RangeKind == PPIfElse; }
+  bool isComment() const { return RangeKind == Comment; }
+  bool isEmptyLine() const { return RangeKind == EmptyLine; }
+  bool isPPIfElse() const { return RangeKind == PPIfElse; }
 
   SkippedRange(SourceRange Range, Kind K,
                SourceLocation PrevTokLoc = SourceLocation(),
@@ -70,6 +70,13 @@ class CoverageSourceInfo : public PPCallbacks,
   // A vector of skipped source ranges and PrevTokLoc with NextTokLoc.
   std::vector<SkippedRange> SkippedRanges;
 
+  // Indices into SkippedRanges by file, sorted by begin location. This is
+  // updated lazily by getSkippedRangesIn.
+  llvm::DenseMap<FileID, SmallVector<unsigned, 0>> SkippedRangesByFile;
+
+  // The number of SkippedRanges in SkippedRangesByFile.
+  unsigned NumIndexedSkippedRanges = 0;
+
   SourceManager &SourceMgr;
 
 public:
@@ -79,7 +86,9 @@ class CoverageSourceInfo : public PPCallbacks,
 
   CoverageSourceInfo(SourceManager &SourceMgr) : SourceMgr(SourceMgr) {}
 
-  std::vector<SkippedRange> &getSkippedRanges() { return SkippedRanges; }
+  /// Return the skipped ranges that begin within \p Range, which must be in a
+  /// single file, sorted by their begin locations.
+  SmallVector<SkippedRange, 0> getSkippedRangesIn(SourceRange Range);
 
   void AddSkippedRange(SourceRange Range, SkippedRange::Kind RangeKind);
 
diff --git a/clang/test/CoverageMapping/pragma-comment.c 
b/clang/test/CoverageMapping/pragma-comment.c
new file mode 100644
index 00000000000000..3c868b1ac5dcbc
--- /dev/null
+++ b/clang/test/CoverageMapping/pragma-comment.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping 
-dump-coverage-mapping -emit-llvm-only %s | FileCheck %s
+
+// Comments in _Pragma strings are lexed in macro expansions.
+
+void f(void) {
+  _Pragma("clang diagnostic push /* comment */")
+}
+
+// CHECK-LABEL: f:
+// CHECK-NEXT: File 0, [[@LINE-5]]:14 -> [[@LINE-3]]:2 = #0
+// CHECK-NOT: Skipped

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to