[clang] [clang] SourceManager: Cache offsets for LastFileIDLookup to speed up getFileID (PR #146782)
Haojian Wu via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 3 01:53:46 PDT 2025
https://github.com/hokein updated https://github.com/llvm/llvm-project/pull/146782
>From 50c6fcb2a1167b65255d2edce9ef34789b85a7a5 Mon Sep 17 00:00:00 2001
From: Haojian Wu <hokein.wu at gmail.com>
Date: Wed, 2 Jul 2025 16:22:48 +0200
Subject: [PATCH 1/2] Cache the Offset for LastFileIDLookup.
---
clang/include/clang/Basic/SourceManager.h | 5 +++--
clang/lib/Basic/SourceManager.cpp | 24 +++++++++++++++--------
2 files changed, 19 insertions(+), 10 deletions(-)
diff --git a/clang/include/clang/Basic/SourceManager.h b/clang/include/clang/Basic/SourceManager.h
index eefd4885534c85..a90cc70825ffdc 100644
--- a/clang/include/clang/Basic/SourceManager.h
+++ b/clang/include/clang/Basic/SourceManager.h
@@ -767,6 +767,8 @@ class SourceManager : public RefCountedBase<SourceManager> {
/// LastFileIDLookup records the last FileID looked up or created, because it
/// is very common to look up many tokens from the same file.
mutable FileID LastFileIDLookup;
+ mutable SourceLocation::UIntTy LastLookupStartOffset;
+ mutable SourceLocation::UIntTy LastLookupEndOffset; // exclude
/// Holds information for \#line directives.
///
@@ -1901,9 +1903,8 @@ class SourceManager : public RefCountedBase<SourceManager> {
FileID getFileID(SourceLocation::UIntTy SLocOffset) const {
// If our one-entry cache covers this offset, just return it.
- if (isOffsetInFileID(LastFileIDLookup, SLocOffset))
+ if (SLocOffset >= LastLookupStartOffset && SLocOffset < LastLookupEndOffset)
return LastFileIDLookup;
-
return getFileIDSlow(SLocOffset);
}
diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp
index 82096421f85791..8c1d9662d4579b 100644
--- a/clang/lib/Basic/SourceManager.cpp
+++ b/clang/lib/Basic/SourceManager.cpp
@@ -334,6 +334,7 @@ void SourceManager::clearIDTables() {
LastLineNoFileIDQuery = FileID();
LastLineNoContentCache = nullptr;
LastFileIDLookup = FileID();
+ LastLookupStartOffset = LastLookupEndOffset = 0;
IncludedLocMap.clear();
if (LineTable)
@@ -639,9 +640,11 @@ FileID SourceManager::createFileIDImpl(ContentCache &File, StringRef Filename,
LocalSLocEntryTable.push_back(
SLocEntry::get(NextLocalOffset,
FileInfo::get(IncludePos, File, FileCharacter, Filename)));
+ LastLookupStartOffset = NextLocalOffset;
// We do a +1 here because we want a SourceLocation that means "the end of the
// file", e.g. for the "no newline at the end of the file" diagnostic.
NextLocalOffset += FileSize + 1;
+ LastLookupEndOffset = NextLocalOffset;
updateSlocUsageStats();
// Set LastFileIDLookup to the newly created file. The next getFileID call is
@@ -832,13 +835,11 @@ FileID SourceManager::getFileIDLocal(SourceLocation::UIntTy SLocOffset) const {
unsigned LessIndex = 0;
// upper bound of the search range.
unsigned GreaterIndex = LocalSLocEntryTable.size();
- if (LastFileIDLookup.ID >= 0) {
- // Use the LastFileIDLookup to prune the search space.
- if (LocalSLocEntryTable[LastFileIDLookup.ID].getOffset() < SLocOffset)
- LessIndex = LastFileIDLookup.ID;
- else
- GreaterIndex = LastFileIDLookup.ID;
- }
+ // Use the LastFileIDLookup to prune the search space.
+ if (LastLookupStartOffset < SLocOffset)
+ LessIndex = LastFileIDLookup.ID;
+ else
+ GreaterIndex = LastFileIDLookup.ID;
// Find the FileID that contains this.
unsigned NumProbes = 0;
@@ -849,7 +850,12 @@ FileID SourceManager::getFileIDLocal(SourceLocation::UIntTy SLocOffset) const {
FileID Res = FileID::get(int(GreaterIndex));
// Remember it. We have good locality across FileID lookups.
LastFileIDLookup = Res;
- NumLinearScans += NumProbes+1;
+ LastLookupStartOffset = LocalSLocEntryTable[GreaterIndex].getOffset();
+ LastLookupEndOffset =
+ GreaterIndex + 1 >= LocalSLocEntryTable.size()
+ ? NextLocalOffset
+ : LocalSLocEntryTable[GreaterIndex + 1].getOffset();
+ NumLinearScans += NumProbes + 1;
return Res;
}
if (++NumProbes == 8)
@@ -873,6 +879,8 @@ FileID SourceManager::getFileIDLocal(SourceLocation::UIntTy SLocOffset) const {
// At this point, LessIndex is the index of the *first element greater than*
// SLocOffset. The element we are actually looking for is the one immediately
// before it.
+ LastLookupStartOffset = LocalSLocEntryTable[LessIndex - 1].getOffset();
+ LastLookupEndOffset = LocalSLocEntryTable[LessIndex].getOffset();
return LastFileIDLookup = FileID::get(LessIndex - 1);
}
>From 1ad5668b6f8e0a54fa258144a765ed3ea0ea8ad0 Mon Sep 17 00:00:00 2001
From: Haojian Wu <hokein.wu at gmail.com>
Date: Thu, 3 Jul 2025 10:53:10 +0200
Subject: [PATCH 2/2] Address review comments.
---
clang/include/clang/Basic/SourceManager.h | 6 +++++-
clang/lib/Basic/SourceManager.cpp | 3 ++-
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/clang/include/clang/Basic/SourceManager.h b/clang/include/clang/Basic/SourceManager.h
index a90cc70825ffdc..111141a33901c7 100644
--- a/clang/include/clang/Basic/SourceManager.h
+++ b/clang/include/clang/Basic/SourceManager.h
@@ -1903,7 +1903,7 @@ class SourceManager : public RefCountedBase<SourceManager> {
FileID getFileID(SourceLocation::UIntTy SLocOffset) const {
// If our one-entry cache covers this offset, just return it.
- if (SLocOffset >= LastLookupStartOffset && SLocOffset < LastLookupEndOffset)
+ if (isOffsetInFileID(LastFileIDLookup, SLocOffset))
return LastFileIDLookup;
return getFileIDSlow(SLocOffset);
}
@@ -1927,6 +1927,10 @@ class SourceManager : public RefCountedBase<SourceManager> {
/// specified SourceLocation offset. This is a very hot method.
inline bool isOffsetInFileID(FileID FID,
SourceLocation::UIntTy SLocOffset) const {
+ if (FID == LastFileIDLookup)
+ return SLocOffset >= LastLookupStartOffset &&
+ SLocOffset < LastLookupEndOffset;
+
const SrcMgr::SLocEntry &Entry = getSLocEntry(FID);
// If the entry is after the offset, it can't contain it.
if (SLocOffset < Entry.getOffset()) return false;
diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp
index 8c1d9662d4579b..873b4be234a853 100644
--- a/clang/lib/Basic/SourceManager.cpp
+++ b/clang/lib/Basic/SourceManager.cpp
@@ -814,8 +814,9 @@ FileID SourceManager::getFileIDSlow(SourceLocation::UIntTy SLocOffset) const {
/// loaded one.
FileID SourceManager::getFileIDLocal(SourceLocation::UIntTy SLocOffset) const {
assert(SLocOffset < NextLocalOffset && "Bad function choice");
- assert(SLocOffset >= LocalSLocEntryTable[0].getOffset() &&
+ assert(SLocOffset >= LocalSLocEntryTable[0].getOffset() && SLocOffset > 0 &&
"Invalid SLocOffset");
+ assert(LastFileIDLookup.ID >= 0 && "Only cache local file sloc entry");
// After the first and second level caches, I see two common sorts of
// behavior: 1) a lot of searched FileID's are "near" the cached file
More information about the cfe-commits
mailing list