[clang] [clang] Add a one-entry cache to DiagStateMap::getFile() (PR #228956)

via cfe-commits cfe-commits at lists.llvm.org
Sun Oct 4 17:00:22 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Nico Weber (nico)

<details>
<summary>Changes</summary>

Once a TU has seen a `#pragma clang diagnostic` (libc++ has them in most headers), every DiagnosticsEngine::isIgnored() / getDiagnosticSeverity() call with a location looks up the location's FileID in a std::map<FileID, File>. The map has an entry for every FileID a state was ever looked up for, including macro expansions, so it gets large. For blink's logical_box_fragment.cc, it has 60755 entries, and 92.4% of the 3.28M lookups are for the same FileID as the previous lookup.

std::map has stable addresses, so remember the result of the last lookup.

For 60 random Chromium TUs (linux x64, -O2) picked with probability proportional to their compile time, sum over all TUs:

    CPU time: 192.6 s => 191.4 s, -0.65%
    instructions: 1903.0e9 => 1888.3e9, -0.77%

(To check noise level, running this with the same binary twice: -0.37% CPU time, +0.01% instructions)

No behavior change.

---
Full diff: https://github.com/llvm/llvm-project/pull/228956.diff


2 Files Affected:

- (modified) clang/include/clang/Basic/Diagnostic.h (+7) 
- (modified) clang/lib/Basic/Diagnostic.cpp (+11) 


``````````diff
diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h
index 72b1414638203cc..39b88c0624dfbef 100644
--- a/clang/include/clang/Basic/Diagnostic.h
+++ b/clang/include/clang/Basic/Diagnostic.h
@@ -437,6 +437,7 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
     void clear(bool Soft) {
       // Just clear the cache when in soft mode.
       Files.clear();
+      LastLookupFile = nullptr;
       if (!Soft) {
         FirstDiagState = CurDiagState = nullptr;
         CurDiagStateLoc = SourceLocation();
@@ -495,6 +496,11 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
     /// The diagnostic states for each file.
     mutable std::map<FileID, File> Files;
 
+    /// One-entry cache for getFile(): Files gets large, and most
+    /// lookups are for the same FileID as the previous one.
+    mutable FileID LastLookupFileID;
+    mutable File *LastLookupFile = nullptr;
+
     /// The initial diagnostic state.
     DiagState *FirstDiagState;
 
@@ -506,6 +512,7 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
 
     /// Get the diagnostic state information for a file.
     File *getFile(SourceManager &SrcMgr, FileID ID) const;
+    File *getFileUncached(SourceManager &SrcMgr, FileID ID) const;
   };
 
   DiagStateMap DiagStatesByLoc;
diff --git a/clang/lib/Basic/Diagnostic.cpp b/clang/lib/Basic/Diagnostic.cpp
index 48dd9559ab8e631..5a05a3ff647465b 100644
--- a/clang/lib/Basic/Diagnostic.cpp
+++ b/clang/lib/Basic/Diagnostic.cpp
@@ -218,6 +218,17 @@ DiagnosticsEngine::DiagStateMap::File::lookup(unsigned Offset) const {
 DiagnosticsEngine::DiagStateMap::File *
 DiagnosticsEngine::DiagStateMap::getFile(SourceManager &SrcMgr,
                                          FileID ID) const {
+  if (!LastLookupFile || LastLookupFileID != ID) {
+    // getFileUncached() can recurse into getFile(), so update the cache after.
+    LastLookupFile = getFileUncached(SrcMgr, ID);
+    LastLookupFileID = ID;
+  }
+  return LastLookupFile;
+}
+
+DiagnosticsEngine::DiagStateMap::File *
+DiagnosticsEngine::DiagStateMap::getFileUncached(SourceManager &SrcMgr,
+                                                 FileID ID) const {
   // Get or insert the File for this ID.
   auto Range = Files.equal_range(ID);
   if (Range.first != Range.second)

``````````

</details>


https://github.com/llvm/llvm-project/pull/228956


More information about the cfe-commits mailing list