[clang] [llvm] [CIR][AMDGPU] Add support for AMDGCN trig_preop builtins (PR #197399)
Ayokunle Amodu via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 30 08:57:47 PDT 2026
https://github.com/ayokunle321 updated https://github.com/llvm/llvm-project/pull/197399
>From 773c65fb06e087abdb67a94b9ad6be96d0c594b7 Mon Sep 17 00:00:00 2001
From: Ayokunle Amodu <ayokunle321 at gmail.com>
Date: Mon, 29 Jun 2026 19:45:46 -0400
Subject: [PATCH 01/15] add detection of duplicate files
---
clang/include/clang/Basic/SourceManager.h | 27 +
clang/include/clang/Serialization/ASTReader.h | 8 +
clang/lib/Basic/SourceManager.cpp | 5 +
clang/lib/Serialization/ASTReader.cpp | 58 ++
dedup-test/a.h | 5 +
dedup-test/b.h | 5 +
dedup-test/module.modulemap | 2 +
dedup-test/one_module_stats.txt | 352 ++++++++++++
dedup-test/shared.h | 403 +++++++++++++
dedup-test/two_modules_stats.txt | 535 ++++++++++++++++++
dedup-test/use.cpp | 3 +
dedup-test/use1.cpp | 2 +
12 files changed, 1405 insertions(+)
create mode 100644 dedup-test/a.h
create mode 100644 dedup-test/b.h
create mode 100644 dedup-test/module.modulemap
create mode 100644 dedup-test/one_module_stats.txt
create mode 100644 dedup-test/shared.h
create mode 100644 dedup-test/two_modules_stats.txt
create mode 100644 dedup-test/use.cpp
create mode 100644 dedup-test/use1.cpp
diff --git a/clang/include/clang/Basic/SourceManager.h b/clang/include/clang/Basic/SourceManager.h
index 1939d1aa4915e..fe9dd42989e50 100644
--- a/clang/include/clang/Basic/SourceManager.h
+++ b/clang/include/clang/Basic/SourceManager.h
@@ -755,6 +755,33 @@ class SourceManager : public RefCountedBase<SourceManager> {
static const SourceLocation::UIntTy MaxLoadedOffset =
1ULL << (8 * sizeof(SourceLocation::UIntTy) - 1);
+ /// --- Source-location de-duplication: detection (prototype, Stage 1) ---
+ /// The first global offset at which each file's SLoc entry was loaded.
+ /// Keyed by FileEntry identity (the same identity Clang uses to dedup file
+ /// content), so we recognize when a later module re-loads the *same file*
+ /// already present in the loaded address space (e.g. a shared header).
+ llvm::DenseMap<const FileEntry *, SourceLocation::UIntTy>
+ LoadedFileFirstOffset;
+ /// Number of loaded file SLoc entries that duplicated an already-loaded file.
+ unsigned NumDuplicateLoadedFiles = 0;
+ /// SLoc address-space bytes occupied by those duplicates (the reuse prize).
+ uint64_t DuplicateLoadedBytes = 0;
+
+public:
+ /// Record a loaded file SLoc entry. If the *same file* was already loaded,
+ /// count it as a duplicate and add its size to the reusable total. Detection
+ /// only -- no behavior change.
+ void noteLoadedFileSLocEntry(const FileEntry *FE,
+ SourceLocation::UIntTy Offset, uint64_t Size) {
+ if (!FE)
+ return;
+ if (!LoadedFileFirstOffset.try_emplace(FE, Offset).second) {
+ ++NumDuplicateLoadedFiles;
+ DuplicateLoadedBytes += Size;
+ }
+ }
+
+private:
/// A bitmap that indicates whether the entries of LoadedSLocEntryTable
/// have already been loaded from the external source.
///
diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h
index d800af83d350b..2afc4c199afda 100644
--- a/clang/include/clang/Serialization/ASTReader.h
+++ b/clang/include/clang/Serialization/ASTReader.h
@@ -2399,6 +2399,14 @@ class ASTReader : public ExternalPreprocessorSource,
llvm::Expected<SourceLocation::UIntTy> readSLocOffset(ModuleFile *F,
unsigned Index);
+ /// Walk module \p F's SLoc entry records (read-only). Fills \p Offsets[i]
+ /// with each entry's local offset and \p Files[i] with its FileEntry (null
+ /// for non-file entries). Returns false if the records couldn't be read.
+ /// Shared scaffolding for source-location de-duplication.
+ bool scanLoadedSLocEntries(ModuleFile &F,
+ SmallVectorImpl<uint32_t> &Offsets,
+ SmallVectorImpl<const FileEntry *> &Files);
+
/// Retrieve the module import location and module name for the
/// given source manager entry ID.
std::pair<SourceLocation, StringRef> getModuleImportLoc(int ID) override;
diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp
index 5540aade05ef5..194426ae2f145 100644
--- a/clang/lib/Basic/SourceManager.cpp
+++ b/clang/lib/Basic/SourceManager.cpp
@@ -2152,6 +2152,11 @@ void SourceManager::PrintStats() const {
<< " bytes of capacity), "
<< MaxLoadedOffset - CurrentLoadedOffset
<< "B of SLoc address space used.\n";
+ if (NumDuplicateLoadedFiles)
+ llvm::errs() << NumDuplicateLoadedFiles
+ << " duplicate loaded file SLocEntries detected ("
+ << DuplicateLoadedBytes
+ << "B of SLoc address space reusable).\n";
unsigned NumLineNumsComputed = 0;
unsigned NumFileBytesMapped = 0;
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 3455b729be696..2283a9ee90b65 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -1815,6 +1815,44 @@ llvm::Error ASTReader::ReadSourceManagerBlock(ModuleFile &F) {
}
}
+bool ASTReader::scanLoadedSLocEntries(
+ ModuleFile &F, SmallVectorImpl<uint32_t> &Offsets,
+ SmallVectorImpl<const FileEntry *> &Files) {
+ unsigned N = F.LocalNumSLocEntries;
+ Offsets.assign(N, 0);
+ Files.assign(N, nullptr);
+
+ BitstreamCursor &Cursor = F.SLocEntryCursor;
+ SavedStreamPosition SavedPosition(Cursor);
+ for (unsigned I = 0; I != N; ++I) {
+ if (llvm::Error Err = Cursor.JumpToBit(F.SLocEntryOffsetsBase +
+ F.SLocEntryOffsets[I])) {
+ consumeError(std::move(Err));
+ return false;
+ }
+ Expected<llvm::BitstreamEntry> Entry = Cursor.advance();
+ if (!Entry) {
+ consumeError(Entry.takeError());
+ return false;
+ }
+ if (Entry->Kind != llvm::BitstreamEntry::Record)
+ return false;
+
+ RecordData Record;
+ StringRef Blob;
+ Expected<unsigned> Code = Cursor.readRecord(Entry->ID, Record, &Blob);
+ if (!Code) {
+ consumeError(Code.takeError());
+ return false;
+ }
+ Offsets[I] = (uint32_t)Record[0];
+ if (Code.get() == SM_SLOC_FILE_ENTRY)
+ if (OptionalFileEntryRef File = getInputFile(F, Record[4]).getFile())
+ Files[I] = &File->getFileEntry();
+ }
+ return true;
+}
+
llvm::Expected<SourceLocation::UIntTy>
ASTReader::readSLocOffset(ModuleFile *F, unsigned Index) {
BitstreamCursor &Cursor = F->SLocEntryCursor;
@@ -4259,6 +4297,26 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
- SLocSpaceSize,&F));
TotalNumSLocEntries += F.LocalNumSLocEntries;
+
+ // De-duplication detection (prototype, Stage 1). Walk this module's SLoc
+ // file entries and recognize when the same file was already loaded by an
+ // earlier module, measuring the address space a future reuse (Stage 2)
+ // could reclaim. Detection only: no allocation/translation change here.
+ {
+ SmallVector<uint32_t, 64> Offsets;
+ SmallVector<const FileEntry *, 64> Files;
+ if (scanLoadedSLocEntries(F, Offsets, Files)) {
+ unsigned N = Offsets.size();
+ for (unsigned I = 0; I != N; ++I) {
+ if (!Files[I])
+ continue;
+ uint64_t Size =
+ (I + 1 < N ? Offsets[I + 1] : SLocSpaceSize) - Offsets[I];
+ SourceMgr.noteLoadedFileSLocEntry(
+ Files[I], F.SLocEntryBaseOffset + Offsets[I], Size);
+ }
+ }
+ }
break;
}
diff --git a/dedup-test/a.h b/dedup-test/a.h
new file mode 100644
index 0000000000000..1fe7fc27db549
--- /dev/null
+++ b/dedup-test/a.h
@@ -0,0 +1,5 @@
+#ifndef A_H
+#define A_H
+#include "shared.h"
+inline int a_entry(int x) { return shared_fn_0(x); }
+#endif
diff --git a/dedup-test/b.h b/dedup-test/b.h
new file mode 100644
index 0000000000000..85839261fc602
--- /dev/null
+++ b/dedup-test/b.h
@@ -0,0 +1,5 @@
+#ifndef B_H
+#define B_H
+#include "shared.h"
+inline int b_entry(int x) { return shared_fn_1(x); }
+#endif
diff --git a/dedup-test/module.modulemap b/dedup-test/module.modulemap
new file mode 100644
index 0000000000000..2da1c03a22211
--- /dev/null
+++ b/dedup-test/module.modulemap
@@ -0,0 +1,2 @@
+module A { header "a.h" export * }
+module B { header "b.h" export * }
diff --git a/dedup-test/one_module_stats.txt b/dedup-test/one_module_stats.txt
new file mode 100644
index 0000000000000..373fe97b5e1d8
--- /dev/null
+++ b/dedup-test/one_module_stats.txt
@@ -0,0 +1,352 @@
+
+STATISTICS:
+
+*** Semantic Analysis Stats:
+
+Number of memory regions: 0
+Bytes used: 0
+Bytes allocated: 0
+Bytes wasted: 0 (includes alignment, etc)
+
+*** Analysis Based Warnings Stats:
+401 functions analyzed (0 w/o CFGs).
+ 1203 CFG blocks built.
+ 3 average CFG blocks per function.
+ 3 max CFG blocks per function.
+0 functions analyzed for uninitialiazed variables
+ 0 variables analyzed.
+ 0 average variables per function.
+ 0 max variables per function.
+ 0 block visits.
+ 0 average block visits per function.
+ 0 max block visits per function.
+
+*** LifetimeSafety Missing Origin per QualType: (QualType : count) :
+
+
+
+*** LifetimeSafety Missing Origin per StmtClassName: (StmtClassName : count) :
+
+
+Total missing origins: 0
+
+****************************************
+
+*** AST Context Stats:
+ 156 types total.
+ 120 Builtin types, 32 each (3840 bytes)
+ 1 FunctionProto types, 48 each (48 bytes)
+ 5 Pointer types, 48 each (240 bytes)
+ 1 Record types, 32 each (32 bytes)
+ 1 Typedef types, 32 each (32 bytes)
+ 28 Vector types, 48 each (1344 bytes)
+Total bytes = 5536
+0/0 implicit default constructors created
+0/0 implicit copy constructors created
+0/0 implicit move constructors created
+0/0 implicit copy assignment operators created
+0/0 implicit move assignment operators created
+0/0 implicit destructors created
+
+*** AST File Statistics:
+
+*** PCH/ModuleFile Remappings:
+
+*** PCH/Modules Loaded:
+
+Number of memory regions: 62
+Bytes used: 248400
+Bytes allocated: 253952
+Bytes wasted: 5552 (includes alignment, etc)
+
+*** Decl Stats:
+ 995 decls total.
+ 1 TranslationUnit decls, 104 each (104 bytes)
+ 1 ExternCContext decls, 72 each (72 bytes)
+ 401 Function decls, 168 each (67368 bytes)
+ 401 ParmVar decls, 104 each (41704 bytes)
+ 8 Field decls, 80 each (640 bytes)
+ 2 CXXRecord decls, 144 each (288 bytes)
+ 180 Typedef decls, 88 each (15840 bytes)
+ 1 Import decls, 56 each (56 bytes)
+Total bytes = 126072
+
+*** Stmt/Expr Stats:
+ 2408 stmts/exprs total.
+ 1 UnresolvedLookupExpr, 64 each (64 bytes)
+ 400 IntegerLiteral, 32 each (12800 bytes)
+ 402 DeclRefExpr, 32 each (12864 bytes)
+ 402 ImplicitCastExpr, 24 each (9648 bytes)
+ 1 CallExpr, 24 each (24 bytes)
+ 400 BinaryOperator, 32 each (12800 bytes)
+ 401 ReturnStmt, 16 each (6416 bytes)
+ 401 CompoundStmt, 16 each (6416 bytes)
+Total bytes = 61032
+
+STATISTICS FOR './module.modulemap':
+
+*** Preprocessor Stats:
+564 directives found:
+ 553 #define.
+ 0 #undef.
+ #include/#include_next/#import:
+ 4 source files entered.
+ 1 max include stack depth
+ 2 #if/#ifndef/#ifdef.
+ 0 #else/#elif/#elifdef/#elifndef.
+ 2 #endif.
+ 2 #pragma.
+0 #if/#ifndef#ifdef regions skipped
+0/0/0 obj/fn/builtin macros expanded, 0 on the fast path.
+0 token paste (##) operations performed, 0 on the fast path.
+
+Preprocessor Memory: 110103B total
+ BumpPtr: 57344
+ Macro Expanded Tokens: 384
+ Predefines Buffer: 32767
+ Macros: 16512
+ #pragma push_macro Info: 2056
+ Poison Reasons: 1032
+ Comment Handlers: 8
+
+*** Identifier Table Stats:
+# Identifiers: 13432
+# Empty Buckets: 19336
+Hash density (#identifiers per bucket): 0.409912
+Ave identifier length: 26.735631
+Max identifier length: 49
+
+Number of memory regions: 182
+Bytes used: 909825
+Bytes allocated: 966656
+Bytes wasted: 56831 (includes alignment, etc)
+
+*** HeaderSearch Stats:
+3 files tracked.
+ 0 #import/#pragma once files.
+ 2 #include/#include_next/#import.
+ 0 #includes skipped due to the multi-include optimization.
+0 framework lookups.
+0 subframework lookups.
+
+*** Source Manager Stats:
+3 files mapped, 3 mem buffers mapped.
+7 local SLocEntries allocated (168 bytes of capacity), 43765B of SLoc address space used.
+0 loaded SLocEntries allocated (0 bytes of capacity), 0B of SLoc address space used.
+20795 bytes of files mapped, 2 files with line #'s computed, 0 files with macro args computed.
+FileID scans: 32 linear, 0 binary.
+
+
+*** File Manager Stats:
+5 real files found, 7 real dirs found.
+0 virtual files found, 0 virtual dirs found.
+28 dir lookups, 9 dir cache misses.
+19 file lookups, 8 file cache misses.
+
+*** Virtual File System Stats:
+14 status() calls
+5 openFileForRead() calls
+0 dir_begin() calls
+1 getRealPath() calls
+0 exists() calls
+0 isLocal() calls
+
+===-------------------------------------------------------------------------===
+ ... Statistics Collected ...
+===-------------------------------------------------------------------------===
+
+ 2 file-search - Number of attempted #includes.
+43765 source-manager - Maximum number of bytes used by source locations (both loaded and local).
+
+
+STATISTICS:
+
+*** Semantic Analysis Stats:
+
+Number of memory regions: 0
+Bytes used: 0
+Bytes allocated: 0
+Bytes wasted: 0 (includes alignment, etc)
+
+*** Analysis Based Warnings Stats:
+0 functions analyzed (0 w/o CFGs).
+ 0 CFG blocks built.
+ 0 average CFG blocks per function.
+ 0 max CFG blocks per function.
+0 functions analyzed for uninitialiazed variables
+ 0 variables analyzed.
+ 0 average variables per function.
+ 0 max variables per function.
+ 0 block visits.
+ 0 average block visits per function.
+ 0 max block visits per function.
+
+*** LifetimeSafety Missing Origin per QualType: (QualType : count) :
+
+
+
+*** LifetimeSafety Missing Origin per StmtClassName: (StmtClassName : count) :
+
+
+Total missing origins: 0
+
+****************************************
+
+*** AST Context Stats:
+ 157 types total.
+ 120 Builtin types, 32 each (3840 bytes)
+ 2 FunctionProto types, 48 each (96 bytes)
+ 6 Pointer types, 48 each (288 bytes)
+ 1 Record types, 32 each (32 bytes)
+ 28 Vector types, 48 each (1344 bytes)
+Total bytes = 5600
+0/0 implicit default constructors created
+0/0 implicit copy constructors created
+0/0 implicit move constructors created
+0/0 implicit copy assignment operators created
+0/0 implicit move assignment operators created
+0/0 implicit destructors created
+
+*** AST File Statistics:
+ 0/6 source location entries read (0.000000%)
+ 2/32 types read (6.250000%)
+ 516/888 declarations read (58.108109%)
+ 7/496 identifiers read (1.411290%)
+ 0/2 macros read (0.000000%)
+ 7/2407 statements read (0.290818%)
+ 0/2 macros read (0.000000%)
+ 0/401 lexical declcontexts read (0.000000%)
+
+*** PCH/ModuleFile Remappings:
+Global bit offset map:
+ 0 -> /Users/ayokunleamodu/Repos/llvm-project/dedup-test/cache1/71GTEYCXW85I/A-CAAI8SHN1D31.pcm
+Global source location entry map:
+ 2 -> /Users/ayokunleamodu/Repos/llvm-project/dedup-test/cache1/71GTEYCXW85I/A-CAAI8SHN1D31.pcm
+Global submodule map:
+ 1 -> /Users/ayokunleamodu/Repos/llvm-project/dedup-test/cache1/71GTEYCXW85I/A-CAAI8SHN1D31.pcm
+
+*** PCH/Modules Loaded:
+Module: /Users/ayokunleamodu/Repos/llvm-project/dedup-test/cache1/71GTEYCXW85I/A-CAAI8SHN1D31.pcm
+ Base source location offset: 2147439884
+ Base identifier ID: 0
+ Number of identifiers: 496
+ Base macro ID: 0
+ Number of macros: 2
+ Base submodule ID: 0
+ Number of submodules: 1
+ Submodule ID local -> global map:
+ 0 -> 0
+ Base selector ID: 0
+ Number of selectors: 0
+ Base preprocessed entity ID: 0
+ Number of preprocessed entities: 0
+ Base type index: 0
+ Number of types: 32
+ Base decl index: 0
+ Number of decls: 888
+
+
+Number of memory regions: 5
+Bytes used: 18452
+Bytes allocated: 20480
+Bytes wasted: 2028 (includes alignment, etc)
+
+*** Decl Stats:
+ 1002 decls total.
+ 1 TranslationUnit decls, 104 each (104 bytes)
+ 2 ExternCContext decls, 72 each (144 bytes)
+ 404 Function decls, 168 each (67872 bytes)
+ 403 ParmVar decls, 104 each (41912 bytes)
+ 8 Field decls, 80 each (640 bytes)
+ 2 CXXRecord decls, 144 each (288 bytes)
+ 180 Typedef decls, 88 each (15840 bytes)
+ 2 Import decls, 56 each (112 bytes)
+Total bytes = 126912
+
+*** Stmt/Expr Stats:
+ 2422 stmts/exprs total.
+ 2 UnresolvedLookupExpr, 64 each (128 bytes)
+ 401 IntegerLiteral, 32 each (12832 bytes)
+ 405 DeclRefExpr, 32 each (12960 bytes)
+ 405 ImplicitCastExpr, 24 each (9720 bytes)
+ 3 CallExpr, 24 each (72 bytes)
+ 400 BinaryOperator, 32 each (12800 bytes)
+ 403 ReturnStmt, 16 each (6448 bytes)
+ 403 CompoundStmt, 16 each (6448 bytes)
+Total bytes = 61408
+
+STATISTICS FOR 'use1.cpp':
+
+*** Preprocessor Stats:
+558 directives found:
+ 552 #define.
+ 0 #undef.
+ #include/#include_next/#import:
+ 2 source files entered.
+ 0 max include stack depth
+ 0 #if/#ifndef/#ifdef.
+ 0 #else/#elif/#elifdef/#elifndef.
+ 0 #endif.
+ 2 #pragma.
+0 #if/#ifndef#ifdef regions skipped
+0/0/0 obj/fn/builtin macros expanded, 0 on the fast path.
+0 token paste (##) operations performed, 0 on the fast path.
+
+Preprocessor Memory: 106007B total
+ BumpPtr: 53248
+ Macro Expanded Tokens: 384
+ Predefines Buffer: 32767
+ Macros: 16512
+ #pragma push_macro Info: 2056
+ Poison Reasons: 1032
+ Comment Handlers: 8
+
+*** Identifier Table Stats:
+# Identifiers: 13033
+# Empty Buckets: 19735
+Hash density (#identifiers per bucket): 0.397736
+Ave identifier length: 27.165119
+Max identifier length: 49
+
+Number of memory regions: 180
+Bytes used: 888396
+Bytes allocated: 950272
+Bytes wasted: 61876 (includes alignment, etc)
+
+*** HeaderSearch Stats:
+3 files tracked.
+ 0 #import/#pragma once files.
+ 2 #include/#include_next/#import.
+ 0 #includes skipped due to the multi-include optimization.
+0 framework lookups.
+0 subframework lookups.
+
+*** Source Manager Stats:
+2 files mapped, 2 mem buffers mapped.
+5 local SLocEntries allocated (168 bytes of capacity), 23108B of SLoc address space used.
+6 loaded SLocEntries allocated (768 bytes of capacity), 43764B of SLoc address space used.
+119 bytes of files mapped, 0 files with line #'s computed, 0 files with macro args computed.
+FileID scans: 11 linear, 0 binary.
+
+
+*** File Manager Stats:
+6 real files found, 8 real dirs found.
+0 virtual files found, 0 virtual dirs found.
+31 dir lookups, 11 dir cache misses.
+27 file lookups, 9 file cache misses.
+
+*** Virtual File System Stats:
+17 status() calls
+6 openFileForRead() calls
+0 dir_begin() calls
+1 getRealPath() calls
+0 exists() calls
+0 isLocal() calls
+
+===-------------------------------------------------------------------------===
+ ... Statistics Collected ...
+===-------------------------------------------------------------------------===
+
+ 2 file-search - Number of attempted #includes.
+66872 source-manager - Maximum number of bytes used by source locations (both loaded and local).
+
diff --git a/dedup-test/shared.h b/dedup-test/shared.h
new file mode 100644
index 0000000000000..3ac57a45355f9
--- /dev/null
+++ b/dedup-test/shared.h
@@ -0,0 +1,403 @@
+#ifndef SHARED_H
+#define SHARED_H
+inline int shared_fn_0(int x) { return x + 0; }
+inline int shared_fn_1(int x) { return x + 1; }
+inline int shared_fn_2(int x) { return x + 2; }
+inline int shared_fn_3(int x) { return x + 3; }
+inline int shared_fn_4(int x) { return x + 4; }
+inline int shared_fn_5(int x) { return x + 5; }
+inline int shared_fn_6(int x) { return x + 6; }
+inline int shared_fn_7(int x) { return x + 7; }
+inline int shared_fn_8(int x) { return x + 8; }
+inline int shared_fn_9(int x) { return x + 9; }
+inline int shared_fn_10(int x) { return x + 10; }
+inline int shared_fn_11(int x) { return x + 11; }
+inline int shared_fn_12(int x) { return x + 12; }
+inline int shared_fn_13(int x) { return x + 13; }
+inline int shared_fn_14(int x) { return x + 14; }
+inline int shared_fn_15(int x) { return x + 15; }
+inline int shared_fn_16(int x) { return x + 16; }
+inline int shared_fn_17(int x) { return x + 17; }
+inline int shared_fn_18(int x) { return x + 18; }
+inline int shared_fn_19(int x) { return x + 19; }
+inline int shared_fn_20(int x) { return x + 20; }
+inline int shared_fn_21(int x) { return x + 21; }
+inline int shared_fn_22(int x) { return x + 22; }
+inline int shared_fn_23(int x) { return x + 23; }
+inline int shared_fn_24(int x) { return x + 24; }
+inline int shared_fn_25(int x) { return x + 25; }
+inline int shared_fn_26(int x) { return x + 26; }
+inline int shared_fn_27(int x) { return x + 27; }
+inline int shared_fn_28(int x) { return x + 28; }
+inline int shared_fn_29(int x) { return x + 29; }
+inline int shared_fn_30(int x) { return x + 30; }
+inline int shared_fn_31(int x) { return x + 31; }
+inline int shared_fn_32(int x) { return x + 32; }
+inline int shared_fn_33(int x) { return x + 33; }
+inline int shared_fn_34(int x) { return x + 34; }
+inline int shared_fn_35(int x) { return x + 35; }
+inline int shared_fn_36(int x) { return x + 36; }
+inline int shared_fn_37(int x) { return x + 37; }
+inline int shared_fn_38(int x) { return x + 38; }
+inline int shared_fn_39(int x) { return x + 39; }
+inline int shared_fn_40(int x) { return x + 40; }
+inline int shared_fn_41(int x) { return x + 41; }
+inline int shared_fn_42(int x) { return x + 42; }
+inline int shared_fn_43(int x) { return x + 43; }
+inline int shared_fn_44(int x) { return x + 44; }
+inline int shared_fn_45(int x) { return x + 45; }
+inline int shared_fn_46(int x) { return x + 46; }
+inline int shared_fn_47(int x) { return x + 47; }
+inline int shared_fn_48(int x) { return x + 48; }
+inline int shared_fn_49(int x) { return x + 49; }
+inline int shared_fn_50(int x) { return x + 50; }
+inline int shared_fn_51(int x) { return x + 51; }
+inline int shared_fn_52(int x) { return x + 52; }
+inline int shared_fn_53(int x) { return x + 53; }
+inline int shared_fn_54(int x) { return x + 54; }
+inline int shared_fn_55(int x) { return x + 55; }
+inline int shared_fn_56(int x) { return x + 56; }
+inline int shared_fn_57(int x) { return x + 57; }
+inline int shared_fn_58(int x) { return x + 58; }
+inline int shared_fn_59(int x) { return x + 59; }
+inline int shared_fn_60(int x) { return x + 60; }
+inline int shared_fn_61(int x) { return x + 61; }
+inline int shared_fn_62(int x) { return x + 62; }
+inline int shared_fn_63(int x) { return x + 63; }
+inline int shared_fn_64(int x) { return x + 64; }
+inline int shared_fn_65(int x) { return x + 65; }
+inline int shared_fn_66(int x) { return x + 66; }
+inline int shared_fn_67(int x) { return x + 67; }
+inline int shared_fn_68(int x) { return x + 68; }
+inline int shared_fn_69(int x) { return x + 69; }
+inline int shared_fn_70(int x) { return x + 70; }
+inline int shared_fn_71(int x) { return x + 71; }
+inline int shared_fn_72(int x) { return x + 72; }
+inline int shared_fn_73(int x) { return x + 73; }
+inline int shared_fn_74(int x) { return x + 74; }
+inline int shared_fn_75(int x) { return x + 75; }
+inline int shared_fn_76(int x) { return x + 76; }
+inline int shared_fn_77(int x) { return x + 77; }
+inline int shared_fn_78(int x) { return x + 78; }
+inline int shared_fn_79(int x) { return x + 79; }
+inline int shared_fn_80(int x) { return x + 80; }
+inline int shared_fn_81(int x) { return x + 81; }
+inline int shared_fn_82(int x) { return x + 82; }
+inline int shared_fn_83(int x) { return x + 83; }
+inline int shared_fn_84(int x) { return x + 84; }
+inline int shared_fn_85(int x) { return x + 85; }
+inline int shared_fn_86(int x) { return x + 86; }
+inline int shared_fn_87(int x) { return x + 87; }
+inline int shared_fn_88(int x) { return x + 88; }
+inline int shared_fn_89(int x) { return x + 89; }
+inline int shared_fn_90(int x) { return x + 90; }
+inline int shared_fn_91(int x) { return x + 91; }
+inline int shared_fn_92(int x) { return x + 92; }
+inline int shared_fn_93(int x) { return x + 93; }
+inline int shared_fn_94(int x) { return x + 94; }
+inline int shared_fn_95(int x) { return x + 95; }
+inline int shared_fn_96(int x) { return x + 96; }
+inline int shared_fn_97(int x) { return x + 97; }
+inline int shared_fn_98(int x) { return x + 98; }
+inline int shared_fn_99(int x) { return x + 99; }
+inline int shared_fn_100(int x) { return x + 100; }
+inline int shared_fn_101(int x) { return x + 101; }
+inline int shared_fn_102(int x) { return x + 102; }
+inline int shared_fn_103(int x) { return x + 103; }
+inline int shared_fn_104(int x) { return x + 104; }
+inline int shared_fn_105(int x) { return x + 105; }
+inline int shared_fn_106(int x) { return x + 106; }
+inline int shared_fn_107(int x) { return x + 107; }
+inline int shared_fn_108(int x) { return x + 108; }
+inline int shared_fn_109(int x) { return x + 109; }
+inline int shared_fn_110(int x) { return x + 110; }
+inline int shared_fn_111(int x) { return x + 111; }
+inline int shared_fn_112(int x) { return x + 112; }
+inline int shared_fn_113(int x) { return x + 113; }
+inline int shared_fn_114(int x) { return x + 114; }
+inline int shared_fn_115(int x) { return x + 115; }
+inline int shared_fn_116(int x) { return x + 116; }
+inline int shared_fn_117(int x) { return x + 117; }
+inline int shared_fn_118(int x) { return x + 118; }
+inline int shared_fn_119(int x) { return x + 119; }
+inline int shared_fn_120(int x) { return x + 120; }
+inline int shared_fn_121(int x) { return x + 121; }
+inline int shared_fn_122(int x) { return x + 122; }
+inline int shared_fn_123(int x) { return x + 123; }
+inline int shared_fn_124(int x) { return x + 124; }
+inline int shared_fn_125(int x) { return x + 125; }
+inline int shared_fn_126(int x) { return x + 126; }
+inline int shared_fn_127(int x) { return x + 127; }
+inline int shared_fn_128(int x) { return x + 128; }
+inline int shared_fn_129(int x) { return x + 129; }
+inline int shared_fn_130(int x) { return x + 130; }
+inline int shared_fn_131(int x) { return x + 131; }
+inline int shared_fn_132(int x) { return x + 132; }
+inline int shared_fn_133(int x) { return x + 133; }
+inline int shared_fn_134(int x) { return x + 134; }
+inline int shared_fn_135(int x) { return x + 135; }
+inline int shared_fn_136(int x) { return x + 136; }
+inline int shared_fn_137(int x) { return x + 137; }
+inline int shared_fn_138(int x) { return x + 138; }
+inline int shared_fn_139(int x) { return x + 139; }
+inline int shared_fn_140(int x) { return x + 140; }
+inline int shared_fn_141(int x) { return x + 141; }
+inline int shared_fn_142(int x) { return x + 142; }
+inline int shared_fn_143(int x) { return x + 143; }
+inline int shared_fn_144(int x) { return x + 144; }
+inline int shared_fn_145(int x) { return x + 145; }
+inline int shared_fn_146(int x) { return x + 146; }
+inline int shared_fn_147(int x) { return x + 147; }
+inline int shared_fn_148(int x) { return x + 148; }
+inline int shared_fn_149(int x) { return x + 149; }
+inline int shared_fn_150(int x) { return x + 150; }
+inline int shared_fn_151(int x) { return x + 151; }
+inline int shared_fn_152(int x) { return x + 152; }
+inline int shared_fn_153(int x) { return x + 153; }
+inline int shared_fn_154(int x) { return x + 154; }
+inline int shared_fn_155(int x) { return x + 155; }
+inline int shared_fn_156(int x) { return x + 156; }
+inline int shared_fn_157(int x) { return x + 157; }
+inline int shared_fn_158(int x) { return x + 158; }
+inline int shared_fn_159(int x) { return x + 159; }
+inline int shared_fn_160(int x) { return x + 160; }
+inline int shared_fn_161(int x) { return x + 161; }
+inline int shared_fn_162(int x) { return x + 162; }
+inline int shared_fn_163(int x) { return x + 163; }
+inline int shared_fn_164(int x) { return x + 164; }
+inline int shared_fn_165(int x) { return x + 165; }
+inline int shared_fn_166(int x) { return x + 166; }
+inline int shared_fn_167(int x) { return x + 167; }
+inline int shared_fn_168(int x) { return x + 168; }
+inline int shared_fn_169(int x) { return x + 169; }
+inline int shared_fn_170(int x) { return x + 170; }
+inline int shared_fn_171(int x) { return x + 171; }
+inline int shared_fn_172(int x) { return x + 172; }
+inline int shared_fn_173(int x) { return x + 173; }
+inline int shared_fn_174(int x) { return x + 174; }
+inline int shared_fn_175(int x) { return x + 175; }
+inline int shared_fn_176(int x) { return x + 176; }
+inline int shared_fn_177(int x) { return x + 177; }
+inline int shared_fn_178(int x) { return x + 178; }
+inline int shared_fn_179(int x) { return x + 179; }
+inline int shared_fn_180(int x) { return x + 180; }
+inline int shared_fn_181(int x) { return x + 181; }
+inline int shared_fn_182(int x) { return x + 182; }
+inline int shared_fn_183(int x) { return x + 183; }
+inline int shared_fn_184(int x) { return x + 184; }
+inline int shared_fn_185(int x) { return x + 185; }
+inline int shared_fn_186(int x) { return x + 186; }
+inline int shared_fn_187(int x) { return x + 187; }
+inline int shared_fn_188(int x) { return x + 188; }
+inline int shared_fn_189(int x) { return x + 189; }
+inline int shared_fn_190(int x) { return x + 190; }
+inline int shared_fn_191(int x) { return x + 191; }
+inline int shared_fn_192(int x) { return x + 192; }
+inline int shared_fn_193(int x) { return x + 193; }
+inline int shared_fn_194(int x) { return x + 194; }
+inline int shared_fn_195(int x) { return x + 195; }
+inline int shared_fn_196(int x) { return x + 196; }
+inline int shared_fn_197(int x) { return x + 197; }
+inline int shared_fn_198(int x) { return x + 198; }
+inline int shared_fn_199(int x) { return x + 199; }
+inline int shared_fn_200(int x) { return x + 200; }
+inline int shared_fn_201(int x) { return x + 201; }
+inline int shared_fn_202(int x) { return x + 202; }
+inline int shared_fn_203(int x) { return x + 203; }
+inline int shared_fn_204(int x) { return x + 204; }
+inline int shared_fn_205(int x) { return x + 205; }
+inline int shared_fn_206(int x) { return x + 206; }
+inline int shared_fn_207(int x) { return x + 207; }
+inline int shared_fn_208(int x) { return x + 208; }
+inline int shared_fn_209(int x) { return x + 209; }
+inline int shared_fn_210(int x) { return x + 210; }
+inline int shared_fn_211(int x) { return x + 211; }
+inline int shared_fn_212(int x) { return x + 212; }
+inline int shared_fn_213(int x) { return x + 213; }
+inline int shared_fn_214(int x) { return x + 214; }
+inline int shared_fn_215(int x) { return x + 215; }
+inline int shared_fn_216(int x) { return x + 216; }
+inline int shared_fn_217(int x) { return x + 217; }
+inline int shared_fn_218(int x) { return x + 218; }
+inline int shared_fn_219(int x) { return x + 219; }
+inline int shared_fn_220(int x) { return x + 220; }
+inline int shared_fn_221(int x) { return x + 221; }
+inline int shared_fn_222(int x) { return x + 222; }
+inline int shared_fn_223(int x) { return x + 223; }
+inline int shared_fn_224(int x) { return x + 224; }
+inline int shared_fn_225(int x) { return x + 225; }
+inline int shared_fn_226(int x) { return x + 226; }
+inline int shared_fn_227(int x) { return x + 227; }
+inline int shared_fn_228(int x) { return x + 228; }
+inline int shared_fn_229(int x) { return x + 229; }
+inline int shared_fn_230(int x) { return x + 230; }
+inline int shared_fn_231(int x) { return x + 231; }
+inline int shared_fn_232(int x) { return x + 232; }
+inline int shared_fn_233(int x) { return x + 233; }
+inline int shared_fn_234(int x) { return x + 234; }
+inline int shared_fn_235(int x) { return x + 235; }
+inline int shared_fn_236(int x) { return x + 236; }
+inline int shared_fn_237(int x) { return x + 237; }
+inline int shared_fn_238(int x) { return x + 238; }
+inline int shared_fn_239(int x) { return x + 239; }
+inline int shared_fn_240(int x) { return x + 240; }
+inline int shared_fn_241(int x) { return x + 241; }
+inline int shared_fn_242(int x) { return x + 242; }
+inline int shared_fn_243(int x) { return x + 243; }
+inline int shared_fn_244(int x) { return x + 244; }
+inline int shared_fn_245(int x) { return x + 245; }
+inline int shared_fn_246(int x) { return x + 246; }
+inline int shared_fn_247(int x) { return x + 247; }
+inline int shared_fn_248(int x) { return x + 248; }
+inline int shared_fn_249(int x) { return x + 249; }
+inline int shared_fn_250(int x) { return x + 250; }
+inline int shared_fn_251(int x) { return x + 251; }
+inline int shared_fn_252(int x) { return x + 252; }
+inline int shared_fn_253(int x) { return x + 253; }
+inline int shared_fn_254(int x) { return x + 254; }
+inline int shared_fn_255(int x) { return x + 255; }
+inline int shared_fn_256(int x) { return x + 256; }
+inline int shared_fn_257(int x) { return x + 257; }
+inline int shared_fn_258(int x) { return x + 258; }
+inline int shared_fn_259(int x) { return x + 259; }
+inline int shared_fn_260(int x) { return x + 260; }
+inline int shared_fn_261(int x) { return x + 261; }
+inline int shared_fn_262(int x) { return x + 262; }
+inline int shared_fn_263(int x) { return x + 263; }
+inline int shared_fn_264(int x) { return x + 264; }
+inline int shared_fn_265(int x) { return x + 265; }
+inline int shared_fn_266(int x) { return x + 266; }
+inline int shared_fn_267(int x) { return x + 267; }
+inline int shared_fn_268(int x) { return x + 268; }
+inline int shared_fn_269(int x) { return x + 269; }
+inline int shared_fn_270(int x) { return x + 270; }
+inline int shared_fn_271(int x) { return x + 271; }
+inline int shared_fn_272(int x) { return x + 272; }
+inline int shared_fn_273(int x) { return x + 273; }
+inline int shared_fn_274(int x) { return x + 274; }
+inline int shared_fn_275(int x) { return x + 275; }
+inline int shared_fn_276(int x) { return x + 276; }
+inline int shared_fn_277(int x) { return x + 277; }
+inline int shared_fn_278(int x) { return x + 278; }
+inline int shared_fn_279(int x) { return x + 279; }
+inline int shared_fn_280(int x) { return x + 280; }
+inline int shared_fn_281(int x) { return x + 281; }
+inline int shared_fn_282(int x) { return x + 282; }
+inline int shared_fn_283(int x) { return x + 283; }
+inline int shared_fn_284(int x) { return x + 284; }
+inline int shared_fn_285(int x) { return x + 285; }
+inline int shared_fn_286(int x) { return x + 286; }
+inline int shared_fn_287(int x) { return x + 287; }
+inline int shared_fn_288(int x) { return x + 288; }
+inline int shared_fn_289(int x) { return x + 289; }
+inline int shared_fn_290(int x) { return x + 290; }
+inline int shared_fn_291(int x) { return x + 291; }
+inline int shared_fn_292(int x) { return x + 292; }
+inline int shared_fn_293(int x) { return x + 293; }
+inline int shared_fn_294(int x) { return x + 294; }
+inline int shared_fn_295(int x) { return x + 295; }
+inline int shared_fn_296(int x) { return x + 296; }
+inline int shared_fn_297(int x) { return x + 297; }
+inline int shared_fn_298(int x) { return x + 298; }
+inline int shared_fn_299(int x) { return x + 299; }
+inline int shared_fn_300(int x) { return x + 300; }
+inline int shared_fn_301(int x) { return x + 301; }
+inline int shared_fn_302(int x) { return x + 302; }
+inline int shared_fn_303(int x) { return x + 303; }
+inline int shared_fn_304(int x) { return x + 304; }
+inline int shared_fn_305(int x) { return x + 305; }
+inline int shared_fn_306(int x) { return x + 306; }
+inline int shared_fn_307(int x) { return x + 307; }
+inline int shared_fn_308(int x) { return x + 308; }
+inline int shared_fn_309(int x) { return x + 309; }
+inline int shared_fn_310(int x) { return x + 310; }
+inline int shared_fn_311(int x) { return x + 311; }
+inline int shared_fn_312(int x) { return x + 312; }
+inline int shared_fn_313(int x) { return x + 313; }
+inline int shared_fn_314(int x) { return x + 314; }
+inline int shared_fn_315(int x) { return x + 315; }
+inline int shared_fn_316(int x) { return x + 316; }
+inline int shared_fn_317(int x) { return x + 317; }
+inline int shared_fn_318(int x) { return x + 318; }
+inline int shared_fn_319(int x) { return x + 319; }
+inline int shared_fn_320(int x) { return x + 320; }
+inline int shared_fn_321(int x) { return x + 321; }
+inline int shared_fn_322(int x) { return x + 322; }
+inline int shared_fn_323(int x) { return x + 323; }
+inline int shared_fn_324(int x) { return x + 324; }
+inline int shared_fn_325(int x) { return x + 325; }
+inline int shared_fn_326(int x) { return x + 326; }
+inline int shared_fn_327(int x) { return x + 327; }
+inline int shared_fn_328(int x) { return x + 328; }
+inline int shared_fn_329(int x) { return x + 329; }
+inline int shared_fn_330(int x) { return x + 330; }
+inline int shared_fn_331(int x) { return x + 331; }
+inline int shared_fn_332(int x) { return x + 332; }
+inline int shared_fn_333(int x) { return x + 333; }
+inline int shared_fn_334(int x) { return x + 334; }
+inline int shared_fn_335(int x) { return x + 335; }
+inline int shared_fn_336(int x) { return x + 336; }
+inline int shared_fn_337(int x) { return x + 337; }
+inline int shared_fn_338(int x) { return x + 338; }
+inline int shared_fn_339(int x) { return x + 339; }
+inline int shared_fn_340(int x) { return x + 340; }
+inline int shared_fn_341(int x) { return x + 341; }
+inline int shared_fn_342(int x) { return x + 342; }
+inline int shared_fn_343(int x) { return x + 343; }
+inline int shared_fn_344(int x) { return x + 344; }
+inline int shared_fn_345(int x) { return x + 345; }
+inline int shared_fn_346(int x) { return x + 346; }
+inline int shared_fn_347(int x) { return x + 347; }
+inline int shared_fn_348(int x) { return x + 348; }
+inline int shared_fn_349(int x) { return x + 349; }
+inline int shared_fn_350(int x) { return x + 350; }
+inline int shared_fn_351(int x) { return x + 351; }
+inline int shared_fn_352(int x) { return x + 352; }
+inline int shared_fn_353(int x) { return x + 353; }
+inline int shared_fn_354(int x) { return x + 354; }
+inline int shared_fn_355(int x) { return x + 355; }
+inline int shared_fn_356(int x) { return x + 356; }
+inline int shared_fn_357(int x) { return x + 357; }
+inline int shared_fn_358(int x) { return x + 358; }
+inline int shared_fn_359(int x) { return x + 359; }
+inline int shared_fn_360(int x) { return x + 360; }
+inline int shared_fn_361(int x) { return x + 361; }
+inline int shared_fn_362(int x) { return x + 362; }
+inline int shared_fn_363(int x) { return x + 363; }
+inline int shared_fn_364(int x) { return x + 364; }
+inline int shared_fn_365(int x) { return x + 365; }
+inline int shared_fn_366(int x) { return x + 366; }
+inline int shared_fn_367(int x) { return x + 367; }
+inline int shared_fn_368(int x) { return x + 368; }
+inline int shared_fn_369(int x) { return x + 369; }
+inline int shared_fn_370(int x) { return x + 370; }
+inline int shared_fn_371(int x) { return x + 371; }
+inline int shared_fn_372(int x) { return x + 372; }
+inline int shared_fn_373(int x) { return x + 373; }
+inline int shared_fn_374(int x) { return x + 374; }
+inline int shared_fn_375(int x) { return x + 375; }
+inline int shared_fn_376(int x) { return x + 376; }
+inline int shared_fn_377(int x) { return x + 377; }
+inline int shared_fn_378(int x) { return x + 378; }
+inline int shared_fn_379(int x) { return x + 379; }
+inline int shared_fn_380(int x) { return x + 380; }
+inline int shared_fn_381(int x) { return x + 381; }
+inline int shared_fn_382(int x) { return x + 382; }
+inline int shared_fn_383(int x) { return x + 383; }
+inline int shared_fn_384(int x) { return x + 384; }
+inline int shared_fn_385(int x) { return x + 385; }
+inline int shared_fn_386(int x) { return x + 386; }
+inline int shared_fn_387(int x) { return x + 387; }
+inline int shared_fn_388(int x) { return x + 388; }
+inline int shared_fn_389(int x) { return x + 389; }
+inline int shared_fn_390(int x) { return x + 390; }
+inline int shared_fn_391(int x) { return x + 391; }
+inline int shared_fn_392(int x) { return x + 392; }
+inline int shared_fn_393(int x) { return x + 393; }
+inline int shared_fn_394(int x) { return x + 394; }
+inline int shared_fn_395(int x) { return x + 395; }
+inline int shared_fn_396(int x) { return x + 396; }
+inline int shared_fn_397(int x) { return x + 397; }
+inline int shared_fn_398(int x) { return x + 398; }
+inline int shared_fn_399(int x) { return x + 399; }
+#endif
diff --git a/dedup-test/two_modules_stats.txt b/dedup-test/two_modules_stats.txt
new file mode 100644
index 0000000000000..dd3a1f0c2d3ac
--- /dev/null
+++ b/dedup-test/two_modules_stats.txt
@@ -0,0 +1,535 @@
+
+STATISTICS:
+
+*** Semantic Analysis Stats:
+
+Number of memory regions: 0
+Bytes used: 0
+Bytes allocated: 0
+Bytes wasted: 0 (includes alignment, etc)
+
+*** Analysis Based Warnings Stats:
+401 functions analyzed (0 w/o CFGs).
+ 1203 CFG blocks built.
+ 3 average CFG blocks per function.
+ 3 max CFG blocks per function.
+0 functions analyzed for uninitialiazed variables
+ 0 variables analyzed.
+ 0 average variables per function.
+ 0 max variables per function.
+ 0 block visits.
+ 0 average block visits per function.
+ 0 max block visits per function.
+
+*** LifetimeSafety Missing Origin per QualType: (QualType : count) :
+
+
+
+*** LifetimeSafety Missing Origin per StmtClassName: (StmtClassName : count) :
+
+
+Total missing origins: 0
+
+****************************************
+
+*** AST Context Stats:
+ 156 types total.
+ 120 Builtin types, 32 each (3840 bytes)
+ 1 FunctionProto types, 48 each (48 bytes)
+ 5 Pointer types, 48 each (240 bytes)
+ 1 Record types, 32 each (32 bytes)
+ 1 Typedef types, 32 each (32 bytes)
+ 28 Vector types, 48 each (1344 bytes)
+Total bytes = 5536
+0/0 implicit default constructors created
+0/0 implicit copy constructors created
+0/0 implicit move constructors created
+0/0 implicit copy assignment operators created
+0/0 implicit move assignment operators created
+0/0 implicit destructors created
+
+*** AST File Statistics:
+
+*** PCH/ModuleFile Remappings:
+
+*** PCH/Modules Loaded:
+
+Number of memory regions: 62
+Bytes used: 248400
+Bytes allocated: 253952
+Bytes wasted: 5552 (includes alignment, etc)
+
+*** Decl Stats:
+ 995 decls total.
+ 1 TranslationUnit decls, 104 each (104 bytes)
+ 1 ExternCContext decls, 72 each (72 bytes)
+ 401 Function decls, 168 each (67368 bytes)
+ 401 ParmVar decls, 104 each (41704 bytes)
+ 8 Field decls, 80 each (640 bytes)
+ 2 CXXRecord decls, 144 each (288 bytes)
+ 180 Typedef decls, 88 each (15840 bytes)
+ 1 Import decls, 56 each (56 bytes)
+Total bytes = 126072
+
+*** Stmt/Expr Stats:
+ 2408 stmts/exprs total.
+ 1 UnresolvedLookupExpr, 64 each (64 bytes)
+ 400 IntegerLiteral, 32 each (12800 bytes)
+ 402 DeclRefExpr, 32 each (12864 bytes)
+ 402 ImplicitCastExpr, 24 each (9648 bytes)
+ 1 CallExpr, 24 each (24 bytes)
+ 400 BinaryOperator, 32 each (12800 bytes)
+ 401 ReturnStmt, 16 each (6416 bytes)
+ 401 CompoundStmt, 16 each (6416 bytes)
+Total bytes = 61032
+
+STATISTICS FOR './module.modulemap':
+
+*** Preprocessor Stats:
+564 directives found:
+ 553 #define.
+ 0 #undef.
+ #include/#include_next/#import:
+ 4 source files entered.
+ 1 max include stack depth
+ 2 #if/#ifndef/#ifdef.
+ 0 #else/#elif/#elifdef/#elifndef.
+ 2 #endif.
+ 2 #pragma.
+0 #if/#ifndef#ifdef regions skipped
+0/0/0 obj/fn/builtin macros expanded, 0 on the fast path.
+0 token paste (##) operations performed, 0 on the fast path.
+
+Preprocessor Memory: 110103B total
+ BumpPtr: 57344
+ Macro Expanded Tokens: 384
+ Predefines Buffer: 32767
+ Macros: 16512
+ #pragma push_macro Info: 2056
+ Poison Reasons: 1032
+ Comment Handlers: 8
+
+*** Identifier Table Stats:
+# Identifiers: 13432
+# Empty Buckets: 19336
+Hash density (#identifiers per bucket): 0.409912
+Ave identifier length: 26.735631
+Max identifier length: 49
+
+Number of memory regions: 182
+Bytes used: 909825
+Bytes allocated: 966656
+Bytes wasted: 56831 (includes alignment, etc)
+
+*** HeaderSearch Stats:
+3 files tracked.
+ 0 #import/#pragma once files.
+ 2 #include/#include_next/#import.
+ 0 #includes skipped due to the multi-include optimization.
+0 framework lookups.
+0 subframework lookups.
+
+*** Source Manager Stats:
+3 files mapped, 3 mem buffers mapped.
+7 local SLocEntries allocated (168 bytes of capacity), 43765B of SLoc address space used.
+0 loaded SLocEntries allocated (0 bytes of capacity), 0B of SLoc address space used.
+20795 bytes of files mapped, 2 files with line #'s computed, 0 files with macro args computed.
+FileID scans: 32 linear, 0 binary.
+
+
+*** File Manager Stats:
+5 real files found, 7 real dirs found.
+0 virtual files found, 0 virtual dirs found.
+28 dir lookups, 9 dir cache misses.
+19 file lookups, 8 file cache misses.
+
+*** Virtual File System Stats:
+14 status() calls
+5 openFileForRead() calls
+0 dir_begin() calls
+1 getRealPath() calls
+0 exists() calls
+0 isLocal() calls
+
+===-------------------------------------------------------------------------===
+ ... Statistics Collected ...
+===-------------------------------------------------------------------------===
+
+ 2 file-search - Number of attempted #includes.
+43765 source-manager - Maximum number of bytes used by source locations (both loaded and local).
+
+
+STATISTICS:
+
+*** Semantic Analysis Stats:
+
+Number of memory regions: 0
+Bytes used: 0
+Bytes allocated: 0
+Bytes wasted: 0 (includes alignment, etc)
+
+*** Analysis Based Warnings Stats:
+401 functions analyzed (0 w/o CFGs).
+ 1203 CFG blocks built.
+ 3 average CFG blocks per function.
+ 3 max CFG blocks per function.
+0 functions analyzed for uninitialiazed variables
+ 0 variables analyzed.
+ 0 average variables per function.
+ 0 max variables per function.
+ 0 block visits.
+ 0 average block visits per function.
+ 0 max block visits per function.
+
+*** LifetimeSafety Missing Origin per QualType: (QualType : count) :
+
+
+
+*** LifetimeSafety Missing Origin per StmtClassName: (StmtClassName : count) :
+
+
+Total missing origins: 0
+
+****************************************
+
+*** AST Context Stats:
+ 156 types total.
+ 120 Builtin types, 32 each (3840 bytes)
+ 1 FunctionProto types, 48 each (48 bytes)
+ 5 Pointer types, 48 each (240 bytes)
+ 1 Record types, 32 each (32 bytes)
+ 1 Typedef types, 32 each (32 bytes)
+ 28 Vector types, 48 each (1344 bytes)
+Total bytes = 5536
+0/0 implicit default constructors created
+0/0 implicit copy constructors created
+0/0 implicit move constructors created
+0/0 implicit copy assignment operators created
+0/0 implicit move assignment operators created
+0/0 implicit destructors created
+
+*** AST File Statistics:
+
+*** PCH/ModuleFile Remappings:
+
+*** PCH/Modules Loaded:
+
+Number of memory regions: 62
+Bytes used: 248400
+Bytes allocated: 253952
+Bytes wasted: 5552 (includes alignment, etc)
+
+*** Decl Stats:
+ 1896 decls total.
+ 2 TranslationUnit decls, 104 each (208 bytes)
+ 2 ExternCContext decls, 72 each (144 bytes)
+ 802 Function decls, 168 each (134736 bytes)
+ 802 ParmVar decls, 104 each (83408 bytes)
+ 12 Field decls, 80 each (960 bytes)
+ 3 CXXRecord decls, 144 each (432 bytes)
+ 270 Typedef decls, 88 each (23760 bytes)
+ 3 Import decls, 56 each (168 bytes)
+Total bytes = 243816
+
+*** Stmt/Expr Stats:
+ 4816 stmts/exprs total.
+ 2 UnresolvedLookupExpr, 64 each (128 bytes)
+ 800 IntegerLiteral, 32 each (25600 bytes)
+ 804 DeclRefExpr, 32 each (25728 bytes)
+ 804 ImplicitCastExpr, 24 each (19296 bytes)
+ 2 CallExpr, 24 each (48 bytes)
+ 800 BinaryOperator, 32 each (25600 bytes)
+ 802 ReturnStmt, 16 each (12832 bytes)
+ 802 CompoundStmt, 16 each (12832 bytes)
+Total bytes = 122064
+
+STATISTICS FOR './module.modulemap':
+
+*** Preprocessor Stats:
+564 directives found:
+ 553 #define.
+ 0 #undef.
+ #include/#include_next/#import:
+ 4 source files entered.
+ 1 max include stack depth
+ 2 #if/#ifndef/#ifdef.
+ 0 #else/#elif/#elifdef/#elifndef.
+ 2 #endif.
+ 2 #pragma.
+0 #if/#ifndef#ifdef regions skipped
+0/0/0 obj/fn/builtin macros expanded, 0 on the fast path.
+0 token paste (##) operations performed, 0 on the fast path.
+
+Preprocessor Memory: 110103B total
+ BumpPtr: 57344
+ Macro Expanded Tokens: 384
+ Predefines Buffer: 32767
+ Macros: 16512
+ #pragma push_macro Info: 2056
+ Poison Reasons: 1032
+ Comment Handlers: 8
+
+*** Identifier Table Stats:
+# Identifiers: 13432
+# Empty Buckets: 19336
+Hash density (#identifiers per bucket): 0.409912
+Ave identifier length: 26.735631
+Max identifier length: 49
+
+Number of memory regions: 182
+Bytes used: 909825
+Bytes allocated: 966656
+Bytes wasted: 56831 (includes alignment, etc)
+
+*** HeaderSearch Stats:
+3 files tracked.
+ 0 #import/#pragma once files.
+ 4 #include/#include_next/#import.
+ 0 #includes skipped due to the multi-include optimization.
+0 framework lookups.
+0 subframework lookups.
+
+*** Source Manager Stats:
+3 files mapped, 3 mem buffers mapped.
+7 local SLocEntries allocated (168 bytes of capacity), 43765B of SLoc address space used.
+0 loaded SLocEntries allocated (0 bytes of capacity), 0B of SLoc address space used.
+20795 bytes of files mapped, 2 files with line #'s computed, 0 files with macro args computed.
+FileID scans: 32 linear, 0 binary.
+
+
+*** File Manager Stats:
+5 real files found, 7 real dirs found.
+0 virtual files found, 0 virtual dirs found.
+42 dir lookups, 10 dir cache misses.
+38 file lookups, 8 file cache misses.
+
+*** Virtual File System Stats:
+15 status() calls
+8 openFileForRead() calls
+0 dir_begin() calls
+1 getRealPath() calls
+0 exists() calls
+0 isLocal() calls
+
+===-------------------------------------------------------------------------===
+ ... Statistics Collected ...
+===-------------------------------------------------------------------------===
+
+ 4 file-search - Number of attempted #includes.
+66900 source-manager - Maximum number of bytes used by source locations (both loaded and local).
+
+
+STATISTICS:
+
+*** Semantic Analysis Stats:
+
+Number of memory regions: 0
+Bytes used: 0
+Bytes allocated: 0
+Bytes wasted: 0 (includes alignment, etc)
+
+*** Analysis Based Warnings Stats:
+0 functions analyzed (0 w/o CFGs).
+ 0 CFG blocks built.
+ 0 average CFG blocks per function.
+ 0 max CFG blocks per function.
+0 functions analyzed for uninitialiazed variables
+ 0 variables analyzed.
+ 0 average variables per function.
+ 0 max variables per function.
+ 0 block visits.
+ 0 average block visits per function.
+ 0 max block visits per function.
+
+*** LifetimeSafety Missing Origin per QualType: (QualType : count) :
+
+
+
+*** LifetimeSafety Missing Origin per StmtClassName: (StmtClassName : count) :
+
+
+Total missing origins: 0
+
+****************************************
+
+*** AST Context Stats:
+ 157 types total.
+ 120 Builtin types, 32 each (3840 bytes)
+ 2 FunctionProto types, 48 each (96 bytes)
+ 6 Pointer types, 48 each (288 bytes)
+ 1 Record types, 32 each (32 bytes)
+ 28 Vector types, 48 each (1344 bytes)
+Total bytes = 5600
+0/0 implicit default constructors created
+0/0 implicit copy constructors created
+0/0 implicit move constructors created
+0/0 implicit copy assignment operators created
+0/0 implicit move assignment operators created
+0/0 implicit destructors created
+
+*** AST File Statistics:
+ 0/12 source location entries read (0.000000%)
+ 4/64 types read (6.250000%)
+ 1032/1776 declarations read (58.108109%)
+ 14/992 identifiers read (1.411290%)
+ 0/4 macros read (0.000000%)
+ 14/4814 statements read (0.290818%)
+ 0/4 macros read (0.000000%)
+ 0/802 lexical declcontexts read (0.000000%)
+
+*** PCH/ModuleFile Remappings:
+Global bit offset map:
+ 0 -> /Users/ayokunleamodu/Repos/llvm-project/dedup-test/cache/71GTEYCXW85I/A-CAAI8SHN1D31.pcm
+ 1144160 -> /Users/ayokunleamodu/Repos/llvm-project/dedup-test/cache/71GTEYCXW85I/B-CAAI8SHN1D31.pcm
+Global source location entry map:
+ 2 -> /Users/ayokunleamodu/Repos/llvm-project/dedup-test/cache/71GTEYCXW85I/A-CAAI8SHN1D31.pcm
+ 8 -> /Users/ayokunleamodu/Repos/llvm-project/dedup-test/cache/71GTEYCXW85I/B-CAAI8SHN1D31.pcm
+Global submodule map:
+ 1 -> /Users/ayokunleamodu/Repos/llvm-project/dedup-test/cache/71GTEYCXW85I/A-CAAI8SHN1D31.pcm
+ 2 -> /Users/ayokunleamodu/Repos/llvm-project/dedup-test/cache/71GTEYCXW85I/B-CAAI8SHN1D31.pcm
+
+*** PCH/Modules Loaded:
+Module: /Users/ayokunleamodu/Repos/llvm-project/dedup-test/cache/71GTEYCXW85I/A-CAAI8SHN1D31.pcm
+ Base source location offset: 2147439884
+ Base identifier ID: 0
+ Number of identifiers: 496
+ Base macro ID: 0
+ Number of macros: 2
+ Base submodule ID: 0
+ Number of submodules: 1
+ Submodule ID local -> global map:
+ 0 -> 0
+ Base selector ID: 0
+ Number of selectors: 0
+ Base preprocessed entity ID: 0
+ Number of preprocessed entities: 0
+ Base type index: 0
+ Number of types: 32
+ Base decl index: 0
+ Number of decls: 888
+
+Module: /Users/ayokunleamodu/Repos/llvm-project/dedup-test/cache/71GTEYCXW85I/B-CAAI8SHN1D31.pcm
+ Base source location offset: 2147396120
+ Base identifier ID: 496
+ Number of identifiers: 496
+ Base macro ID: 2
+ Number of macros: 2
+ Base submodule ID: 1
+ Number of submodules: 1
+ Submodule ID local -> global map:
+ 0 -> 1
+ Base selector ID: 0
+ Number of selectors: 0
+ Base preprocessed entity ID: 0
+ Number of preprocessed entities: 0
+ Base type index: 32
+ Number of types: 32
+ Base decl index: 888
+ Number of decls: 888
+
+
+Number of memory regions: 5
+Bytes used: 19784
+Bytes allocated: 20480
+Bytes wasted: 696 (includes alignment, etc)
+
+*** Decl Stats:
+ 1907 decls total.
+ 2 TranslationUnit decls, 104 each (208 bytes)
+ 3 ExternCContext decls, 72 each (216 bytes)
+ 807 Function decls, 168 each (135576 bytes)
+ 806 ParmVar decls, 104 each (83824 bytes)
+ 12 Field decls, 80 each (960 bytes)
+ 3 CXXRecord decls, 144 each (432 bytes)
+ 270 Typedef decls, 88 each (23760 bytes)
+ 4 Import decls, 56 each (224 bytes)
+Total bytes = 245200
+
+*** Stmt/Expr Stats:
+ 4843 stmts/exprs total.
+ 4 UnresolvedLookupExpr, 64 each (256 bytes)
+ 802 IntegerLiteral, 32 each (25664 bytes)
+ 810 DeclRefExpr, 32 each (25920 bytes)
+ 810 ImplicitCastExpr, 24 each (19440 bytes)
+ 6 CallExpr, 24 each (144 bytes)
+ 801 BinaryOperator, 32 each (25632 bytes)
+ 805 ReturnStmt, 16 each (12880 bytes)
+ 805 CompoundStmt, 16 each (12880 bytes)
+Total bytes = 122816
+
+STATISTICS FOR 'use.cpp':
+
+*** Preprocessor Stats:
+559 directives found:
+ 552 #define.
+ 0 #undef.
+ #include/#include_next/#import:
+ 2 source files entered.
+ 0 max include stack depth
+ 0 #if/#ifndef/#ifdef.
+ 0 #else/#elif/#elifdef/#elifndef.
+ 0 #endif.
+ 2 #pragma.
+0 #if/#ifndef#ifdef regions skipped
+0/0/0 obj/fn/builtin macros expanded, 0 on the fast path.
+0 token paste (##) operations performed, 0 on the fast path.
+
+Preprocessor Memory: 106007B total
+ BumpPtr: 53248
+ Macro Expanded Tokens: 384
+ Predefines Buffer: 32767
+ Macros: 16512
+ #pragma push_macro Info: 2056
+ Poison Reasons: 1032
+ Comment Handlers: 8
+
+*** Identifier Table Stats:
+# Identifiers: 13037
+# Empty Buckets: 19731
+Hash density (#identifiers per bucket): 0.397858
+Ave identifier length: 27.158472
+Max identifier length: 49
+
+Number of memory regions: 180
+Bytes used: 888582
+Bytes allocated: 950272
+Bytes wasted: 61690 (includes alignment, etc)
+
+*** HeaderSearch Stats:
+3 files tracked.
+ 0 #import/#pragma once files.
+ 4 #include/#include_next/#import.
+ 0 #includes skipped due to the multi-include optimization.
+0 framework lookups.
+0 subframework lookups.
+
+*** Source Manager Stats:
+2 files mapped, 2 mem buffers mapped.
+5 local SLocEntries allocated (168 bytes of capacity), 23136B of SLoc address space used.
+12 loaded SLocEntries allocated (768 bytes of capacity), 87528B of SLoc address space used.
+2 duplicate loaded file SLocEntries detected (20694B of SLoc address space reusable).
+147 bytes of files mapped, 0 files with line #'s computed, 0 files with macro args computed.
+FileID scans: 15 linear, 0 binary.
+
+
+*** File Manager Stats:
+7 real files found, 8 real dirs found.
+0 virtual files found, 0 virtual dirs found.
+46 dir lookups, 11 dir cache misses.
+47 file lookups, 10 file cache misses.
+
+*** Virtual File System Stats:
+18 status() calls
+10 openFileForRead() calls
+0 dir_begin() calls
+1 getRealPath() calls
+0 exists() calls
+0 isLocal() calls
+
+===-------------------------------------------------------------------------===
+ ... Statistics Collected ...
+===-------------------------------------------------------------------------===
+
+ 4 file-search - Number of attempted #includes.
+110664 source-manager - Maximum number of bytes used by source locations (both loaded and local).
+
diff --git a/dedup-test/use.cpp b/dedup-test/use.cpp
new file mode 100644
index 0000000000000..cc00041ff4cc4
--- /dev/null
+++ b/dedup-test/use.cpp
@@ -0,0 +1,3 @@
+#include "a.h"
+#include "b.h"
+int main() { return a_entry(1) + b_entry(2); }
diff --git a/dedup-test/use1.cpp b/dedup-test/use1.cpp
new file mode 100644
index 0000000000000..1d4c4250df0c7
--- /dev/null
+++ b/dedup-test/use1.cpp
@@ -0,0 +1,2 @@
+#include "a.h"
+int main() { return a_entry(1); }
>From b2f0c7269aeb4b33a7a7e16404976275062f8e36 Mon Sep 17 00:00:00 2001
From: Ayokunle Amodu <ayokunle321 at gmail.com>
Date: Mon, 29 Jun 2026 20:13:59 -0400
Subject: [PATCH 02/15] add no-op piecewise translation
---
clang/include/clang/Serialization/ASTReader.h | 15 +++++++++++++++
clang/include/clang/Serialization/ModuleFile.h | 16 ++++++++++++++++
clang/lib/Serialization/ASTReader.cpp | 9 +++++++++
two_modules_stats.txt | 1 +
4 files changed, 41 insertions(+)
create mode 100644 two_modules_stats.txt
diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h
index 2afc4c199afda..62bc2b185d9d6 100644
--- a/clang/include/clang/Serialization/ASTReader.h
+++ b/clang/include/clang/Serialization/ASTReader.h
@@ -2501,6 +2501,21 @@ class ASTReader : public ExternalPreprocessorSource,
// translated or refactor the code to make it clear that
// TranslateSourceLocation won't be called with translated source location.
+ // De-duplication (Stage 2): a module's local->global offset map may be
+ // piecewise rather than a single flat shift, so look up the segment that
+ // covers this location. The seeded identity segment makes this identical to
+ // the flat shift below; redirect segments (Stage 2b) send a duplicated
+ // file's locations into the module that first loaded it.
+ if (!ModuleFile.SLocRemap.empty()) {
+ SourceLocation::UIntTy Raw = Loc.getRawEncoding();
+ for (const auto &Seg : ModuleFile.SLocRemap)
+ if (Raw >= Seg.LocalBegin && Raw < Seg.LocalEnd)
+ return SourceLocation::getFromRawEncoding(
+ static_cast<SourceLocation::UIntTy>(
+ static_cast<int64_t>(Raw) + Seg.Delta));
+ // No segment matched (shouldn't happen): fall through to the flat shift.
+ }
+
return Loc.getLocWithOffset(ModuleFile.SLocEntryBaseOffset - 2);
}
diff --git a/clang/include/clang/Serialization/ModuleFile.h b/clang/include/clang/Serialization/ModuleFile.h
index 6c47040fde093..6d3d46003f058 100644
--- a/clang/include/clang/Serialization/ModuleFile.h
+++ b/clang/include/clang/Serialization/ModuleFile.h
@@ -346,6 +346,22 @@ class ModuleFile {
/// AST file.
const uint32_t *SLocEntryOffsets = nullptr;
+ // === Source-location de-duplication: offset remap (prototype, Stage 2) ===
+
+ /// One offset-remap segment in this module's raw SourceLocation space:
+ /// a raw local location L in [LocalBegin, LocalEnd) maps to global L + Delta.
+ struct SLocRemapSegment {
+ SourceLocation::UIntTy LocalBegin;
+ SourceLocation::UIntTy LocalEnd;
+ int64_t Delta;
+ };
+
+ /// Piecewise local->global offset map for this module, sorted by LocalBegin.
+ /// Empty => fall back to the flat shift by (SLocEntryBaseOffset - 2).
+ /// Stage 2a seeds a single identity segment equivalent to the flat shift;
+ /// Stage 2b adds redirect/shift segments for de-duplicated files.
+ llvm::SmallVector<SLocRemapSegment, 4> SLocRemap;
+
// === Identifiers ===
/// The number of identifiers in this AST file.
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 2283a9ee90b65..d7c5468392ddf 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -4282,6 +4282,15 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
return llvm::createStringError(std::errc::invalid_argument,
"ran out of source locations");
}
+
+ // De-duplication (Stage 2a): seed the piecewise offset map with a single
+ // identity segment spanning the whole value range, equivalent to the flat
+ // shift by (BaseOffset - 2). This routes translation through the segment
+ // list with no behavior change; Stage 2b adds redirect/shift segments for
+ // duplicated files.
+ F.SLocRemap.push_back(
+ {/*LocalBegin=*/0, /*LocalEnd=*/~SourceLocation::UIntTy(0),
+ /*Delta=*/static_cast<int64_t>(F.SLocEntryBaseOffset) - 2});
// Make our entry in the range map. BaseID is negative and growing, so
// we invert it. Because we invert it, though, we need the other end of
// the range.
diff --git a/two_modules_stats.txt b/two_modules_stats.txt
new file mode 100644
index 0000000000000..d0df4d9e70b35
--- /dev/null
+++ b/two_modules_stats.txt
@@ -0,0 +1 @@
+zsh: command not found: -std=c++20
>From b2653b000796d7881768a01a96d0782c45fb4c78 Mon Sep 17 00:00:00 2001
From: Ayokunle Amodu <ayokunle321 at gmail.com>
Date: Wed, 1 Jul 2026 08:56:07 -0400
Subject: [PATCH 03/15] redirect duplicated files to previous allocation
---
clang/include/clang/Basic/SourceManager.h | 56 ++++--
clang/include/clang/Serialization/ASTReader.h | 28 ++-
.../include/clang/Serialization/ModuleFile.h | 11 ++
clang/lib/Basic/SourceManager.cpp | 4 +-
clang/lib/Serialization/ASTReader.cpp | 181 +++++++++++++-----
dedup-test/use_err.cpp | 14 ++
dedup-test/use_err_rev.cpp | 10 +
7 files changed, 235 insertions(+), 69 deletions(-)
create mode 100644 dedup-test/use_err.cpp
create mode 100644 dedup-test/use_err_rev.cpp
diff --git a/clang/include/clang/Basic/SourceManager.h b/clang/include/clang/Basic/SourceManager.h
index fe9dd42989e50..75b346018bb67 100644
--- a/clang/include/clang/Basic/SourceManager.h
+++ b/clang/include/clang/Basic/SourceManager.h
@@ -755,30 +755,48 @@ class SourceManager : public RefCountedBase<SourceManager> {
static const SourceLocation::UIntTy MaxLoadedOffset =
1ULL << (8 * sizeof(SourceLocation::UIntTy) - 1);
- /// --- Source-location de-duplication: detection (prototype, Stage 1) ---
- /// The first global offset at which each file's SLoc entry was loaded.
- /// Keyed by FileEntry identity (the same identity Clang uses to dedup file
- /// content), so we recognize when a later module re-loads the *same file*
- /// already present in the loaded address space (e.g. a shared header).
- llvm::DenseMap<const FileEntry *, SourceLocation::UIntTy>
- LoadedFileFirstOffset;
+ /// --- Source-location de-duplication (prototype, Stage 2) ---
+ /// The canonical loaded location of a file: where its SLoc entry first landed
+ /// in the global address space. Lets a later module reuse it instead of
+ /// re-allocating. Keyed by FileEntry identity (the same identity Clang uses
+ /// to dedup file content).
+public:
+ struct LoadedFileLoc {
+ SourceLocation::UIntTy Offset = 0; ///< global raw start offset
+ int ID = 0; ///< global SLoc entry ID
+ };
+
+private:
+ llvm::DenseMap<const FileEntry *, LoadedFileLoc> CanonicalLoadedFiles;
/// Number of loaded file SLoc entries that duplicated an already-loaded file.
unsigned NumDuplicateLoadedFiles = 0;
- /// SLoc address-space bytes occupied by those duplicates (the reuse prize).
+ /// SLoc address-space bytes those duplicates reused instead of allocating.
uint64_t DuplicateLoadedBytes = 0;
public:
- /// Record a loaded file SLoc entry. If the *same file* was already loaded,
- /// count it as a duplicate and add its size to the reusable total. Detection
- /// only -- no behavior change.
- void noteLoadedFileSLocEntry(const FileEntry *FE,
- SourceLocation::UIntTy Offset, uint64_t Size) {
- if (!FE)
- return;
- if (!LoadedFileFirstOffset.try_emplace(FE, Offset).second) {
- ++NumDuplicateLoadedFiles;
- DuplicateLoadedBytes += Size;
- }
+ /// Whether a file with this identity was already loaded into the address
+ /// space by an earlier module (i.e. its SLoc entry would be a duplicate).
+ bool isLoadedFileDuplicate(const FileEntry *FE) const {
+ return FE && CanonicalLoadedFiles.contains(FE);
+ }
+
+ /// The canonical loaded location of a previously-loaded file, or null.
+ const LoadedFileLoc *getCanonicalLoadedFile(const FileEntry *FE) const {
+ auto It = CanonicalLoadedFiles.find(FE);
+ return It == CanonicalLoadedFiles.end() ? nullptr : &It->second;
+ }
+
+ /// Record the canonical loaded location of a file the first time it loads.
+ void registerCanonicalLoadedFile(const FileEntry *FE,
+ SourceLocation::UIntTy Offset, int ID) {
+ if (FE)
+ CanonicalLoadedFiles.try_emplace(FE, LoadedFileLoc{Offset, ID});
+ }
+
+ /// Account for a de-duplicated file entry (for -print-stats reporting).
+ void noteDuplicateLoadedFile(uint64_t Size) {
+ ++NumDuplicateLoadedFiles;
+ DuplicateLoadedBytes += Size;
}
private:
diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h
index 62bc2b185d9d6..a063904e4567e 100644
--- a/clang/include/clang/Serialization/ASTReader.h
+++ b/clang/include/clang/Serialization/ASTReader.h
@@ -2407,6 +2407,13 @@ class ASTReader : public ExternalPreprocessorSource,
SmallVectorImpl<uint32_t> &Offsets,
SmallVectorImpl<const FileEntry *> &Files);
+ /// Map a module-local SLoc entry offset (the value stored in an entry record,
+ /// i.e. Record[0]) to its global raw start offset, applying the
+ /// de-duplication remap. Equals (SLocEntryBaseOffset + LocalOffset) when the
+ /// module is not de-duplicated.
+ SourceLocation::UIntTy remapSLocEntryOffset(ModuleFile &F,
+ uint32_t LocalOffset) const;
+
/// Retrieve the module import location and module name for the
/// given source manager entry ID.
std::pair<SourceLocation, StringRef> getModuleImportLoc(int ID) override;
@@ -2506,13 +2513,20 @@ class ASTReader : public ExternalPreprocessorSource,
// covers this location. The seeded identity segment makes this identical to
// the flat shift below; redirect segments (Stage 2b) send a duplicated
// file's locations into the module that first loaded it.
+ //
+ // Segments are keyed by the *file-offset* part of the location, so strip
+ // the macro bit before matching and re-apply it to the result (a macro
+ // location encodes its position in the low bits with the high bit set).
if (!ModuleFile.SLocRemap.empty()) {
SourceLocation::UIntTy Raw = Loc.getRawEncoding();
+ SourceLocation::UIntTy MacroBit = Raw & SourceLocation::MacroIDBit;
+ SourceLocation::UIntTy Low = Raw & ~SourceLocation::MacroIDBit;
for (const auto &Seg : ModuleFile.SLocRemap)
- if (Raw >= Seg.LocalBegin && Raw < Seg.LocalEnd)
+ if (Low >= Seg.LocalBegin && Low < Seg.LocalEnd)
return SourceLocation::getFromRawEncoding(
- static_cast<SourceLocation::UIntTy>(
- static_cast<int64_t>(Raw) + Seg.Delta));
+ (static_cast<SourceLocation::UIntTy>(static_cast<int64_t>(Low) +
+ Seg.Delta)) |
+ MacroBit);
// No segment matched (shouldn't happen): fall through to the flat shift.
}
@@ -2537,6 +2551,14 @@ class ASTReader : public ExternalPreprocessorSource,
assert(FID.ID >= 0 && "Reading non-local FileID.");
if (FID.isInvalid())
return FID;
+ // De-duplication (Stage 2b): a local FileID may map to the canonical copy
+ // in an earlier module, so consult the explicit map when present. Local
+ // FileID N corresponds to local entry index N-1.
+ if (!F.LocalToGlobalID.empty()) {
+ assert((unsigned)(FID.ID - 1) < F.LocalToGlobalID.size() &&
+ "local FileID out of range");
+ return FileID::get(F.LocalToGlobalID[FID.ID - 1]);
+ }
return FileID::get(F.SLocEntryBaseID + FID.ID - 1);
}
diff --git a/clang/include/clang/Serialization/ModuleFile.h b/clang/include/clang/Serialization/ModuleFile.h
index 6d3d46003f058..6b65089cc7e6b 100644
--- a/clang/include/clang/Serialization/ModuleFile.h
+++ b/clang/include/clang/Serialization/ModuleFile.h
@@ -362,6 +362,17 @@ class ModuleFile {
/// Stage 2b adds redirect/shift segments for de-duplicated files.
llvm::SmallVector<SLocRemapSegment, 4> SLocRemap;
+ /// Maps a local SLoc entry index -> its resulting global SLoc entry ID.
+ /// Kept entries map to their own newly-allocated ID; de-duplicated entries
+ /// map to the ID of the canonical copy in an earlier module. Empty => no
+ /// de-duplication for this module (global ID is SLocEntryBaseID + index).
+ std::vector<int> LocalToGlobalID;
+
+ /// For each kept global slot j (0-based, relative to SLocEntryBaseID), the
+ /// original local entry index in this module (index into SLocEntryOffsets).
+ /// Empty => no de-duplication (kept slot j == local index j).
+ std::vector<unsigned> KeptSLocLocalIndex;
+
// === Identifiers ===
/// The number of identifiers in this AST file.
diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp
index 194426ae2f145..fc1d0094a84d8 100644
--- a/clang/lib/Basic/SourceManager.cpp
+++ b/clang/lib/Basic/SourceManager.cpp
@@ -2154,9 +2154,9 @@ void SourceManager::PrintStats() const {
<< "B of SLoc address space used.\n";
if (NumDuplicateLoadedFiles)
llvm::errs() << NumDuplicateLoadedFiles
- << " duplicate loaded file SLocEntries detected ("
+ << " duplicate loaded file SLocEntries de-duplicated ("
<< DuplicateLoadedBytes
- << "B of SLoc address space reusable).\n";
+ << "B of SLoc address space reused).\n";
unsigned NumLineNumsComputed = 0;
unsigned NumFileBytesMapped = 0;
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index d7c5468392ddf..d8041c06a4674 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -1853,6 +1853,21 @@ bool ASTReader::scanLoadedSLocEntries(
return true;
}
+SourceLocation::UIntTy
+ASTReader::remapSLocEntryOffset(ModuleFile &F, uint32_t LocalOffset) const {
+ // The entry's local raw start location is LocalOffset + 2 (offsets 0 and 1
+ // are reserved). Find the segment covering it and apply that segment's delta.
+ if (!F.SLocRemap.empty()) {
+ SourceLocation::UIntTy Low = LocalOffset + 2;
+ for (const auto &Seg : F.SLocRemap)
+ if (Low >= Seg.LocalBegin && Low < Seg.LocalEnd)
+ return static_cast<SourceLocation::UIntTy>(static_cast<int64_t>(Low) +
+ Seg.Delta);
+ }
+ // No remap (or no segment matched): original flat shift.
+ return F.SLocEntryBaseOffset + LocalOffset;
+}
+
llvm::Expected<SourceLocation::UIntTy>
ASTReader::readSLocOffset(ModuleFile *F, unsigned Index) {
BitstreamCursor &Cursor = F->SLocEntryCursor;
@@ -1885,7 +1900,7 @@ ASTReader::readSLocOffset(ModuleFile *F, unsigned Index) {
case SM_SLOC_FILE_ENTRY:
case SM_SLOC_BUFFER_ENTRY:
case SM_SLOC_EXPANSION_ENTRY:
- return F->SLocEntryBaseOffset + Record[0];
+ return remapSLocEntryOffset(*F, Record[0]);
}
}
@@ -1898,13 +1913,21 @@ int ASTReader::getSLocEntryID(SourceLocation::UIntTy SLocOffset) {
bool Invalid = false;
+ // De-duplication (Stage 2b): the global table holds only this module's kept
+ // entries, so search over kept slots and translate each slot to its on-disk
+ // local entry index when reading the offset.
+ bool Dedup = !F->KeptSLocLocalIndex.empty();
+ unsigned NumSlots =
+ Dedup ? F->KeptSLocLocalIndex.size() : F->LocalNumSLocEntries;
+
auto It = llvm::upper_bound(
- llvm::index_range(0, F->LocalNumSLocEntries), SLocOffset,
- [&](SourceLocation::UIntTy Offset, std::size_t LocalIndex) {
- int ID = F->SLocEntryBaseID + LocalIndex;
+ llvm::index_range(0, NumSlots), SLocOffset,
+ [&](SourceLocation::UIntTy Offset, std::size_t Slot) {
+ int ID = F->SLocEntryBaseID + Slot;
std::size_t Index = -ID - 2;
if (!SourceMgr.SLocEntryOffsetLoaded[Index]) {
assert(!SourceMgr.SLocEntryLoaded[Index]);
+ unsigned LocalIndex = Dedup ? F->KeptSLocLocalIndex[Slot] : Slot;
auto MaybeEntryOffset = readSLocOffset(F, LocalIndex);
if (!MaybeEntryOffset) {
Error(MaybeEntryOffset.takeError());
@@ -1986,15 +2009,23 @@ bool ASTReader::ReadSLocEntry(int ID) {
};
ModuleFile *F = GlobalSLocEntryMap.find(-ID)->second;
+ // De-duplication (Stage 2b): with entries skipped, the global slot
+ // (ID - SLocEntryBaseID) is no longer the on-disk local index, so translate
+ // it through the kept-index table when present.
+ unsigned LocalIndex = ID - F->SLocEntryBaseID;
+ if (!F->KeptSLocLocalIndex.empty()) {
+ assert(LocalIndex < F->KeptSLocLocalIndex.size() && "kept slot out of range");
+ LocalIndex = F->KeptSLocLocalIndex[LocalIndex];
+ }
if (llvm::Error Err = F->SLocEntryCursor.JumpToBit(
- F->SLocEntryOffsetsBase +
- F->SLocEntryOffsets[ID - F->SLocEntryBaseID])) {
+ F->SLocEntryOffsetsBase + F->SLocEntryOffsets[LocalIndex])) {
Error(std::move(Err));
return true;
}
BitstreamCursor &SLocEntryCursor = F->SLocEntryCursor;
SourceLocation::UIntTy BaseOffset = F->SLocEntryBaseOffset;
+ (void)BaseOffset;
++NumSLocEntriesRead;
Expected<llvm::BitstreamEntry> MaybeEntry = SLocEntryCursor.advance();
@@ -2044,7 +2075,7 @@ bool ASTReader::ReadSLocEntry(int ID) {
SrcMgr::CharacteristicKind
FileCharacter = (SrcMgr::CharacteristicKind)Record[2];
FileID FID = SourceMgr.createFileID(*File, IncludeLoc, FileCharacter, ID,
- BaseOffset + Record[0]);
+ remapSLocEntryOffset(*F, Record[0]));
SrcMgr::FileInfo &FileInfo = SourceMgr.getSLocEntry(FID).getFile();
FileInfo.NumCreatedFIDs = Record[5];
if (Record[3])
@@ -2086,7 +2117,8 @@ bool ASTReader::ReadSLocEntry(int ID) {
if (!Buffer)
return true;
FileID FID = SourceMgr.createFileID(std::move(Buffer), FileCharacter, ID,
- BaseOffset + Offset, IncludeLoc);
+ remapSLocEntryOffset(*F, Offset),
+ IncludeLoc);
if (Record[3]) {
auto &FileInfo = SourceMgr.getSLocEntry(FID).getFile();
FileInfo.setHasLineDirectives();
@@ -2100,7 +2132,7 @@ bool ASTReader::ReadSLocEntry(int ID) {
SourceLocation ExpansionEnd = ReadSourceLocation(*F, Record[3]);
SourceMgr.createExpansionLoc(SpellingLoc, ExpansionBegin, ExpansionEnd,
Record[5], Record[4], ID,
- BaseOffset + Record[0]);
+ remapSLocEntryOffset(*F, Record[0]));
break;
}
}
@@ -4273,9 +4305,36 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
F.LocalNumSLocEntries = Record[0];
SourceLocation::UIntTy SLocSpaceSize = Record[1];
F.SLocEntryOffsetsBase = Record[2] + F.SourceManagerBlockStartOffset;
+ unsigned N = F.LocalNumSLocEntries;
+
+ // De-duplication (Stage 2b): scan this module's SLoc entries *before*
+ // allocating, so we can recognize files already loaded by an earlier
+ // module and reserve less address space for them.
+ SmallVector<uint32_t, 64> Offsets;
+ SmallVector<const FileEntry *, 64> Files;
+ bool Scanned = scanLoadedSLocEntries(F, Offsets, Files);
+
+ // Classify duplicates and compute the reduced allocation request.
+ auto entrySize = [&](unsigned I) -> uint64_t {
+ return (I + 1 < N ? Offsets[I + 1] : SLocSpaceSize) - Offsets[I];
+ };
+ unsigned NumDupEntries = 0;
+ uint64_t DupBytes = 0;
+ if (Scanned)
+ for (unsigned I = 0; I != N; ++I)
+ if (SourceMgr.isLoadedFileDuplicate(Files[I])) {
+ uint64_t Size = entrySize(I);
+ SourceMgr.noteDuplicateLoadedFile(Size);
+ DupBytes += Size;
+ ++NumDupEntries;
+ }
+ unsigned ReducedNumEntries = N - NumDupEntries;
+ SourceLocation::UIntTy ReducedSize = SLocSpaceSize - DupBytes;
+
+ // Reserve the reduced amount (equals the full amount when nothing is
+ // de-duplicated).
std::tie(F.SLocEntryBaseID, F.SLocEntryBaseOffset) =
- SourceMgr.AllocateLoadedSLocEntries(F.LocalNumSLocEntries,
- SLocSpaceSize);
+ SourceMgr.AllocateLoadedSLocEntries(ReducedNumEntries, ReducedSize);
if (!F.SLocEntryBaseID) {
Diags.Report(SourceLocation(), diag::remark_sloc_usage);
SourceMgr.noteSLocAddressSpaceUsage(Diags);
@@ -4283,49 +4342,81 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
"ran out of source locations");
}
- // De-duplication (Stage 2a): seed the piecewise offset map with a single
- // identity segment spanning the whole value range, equivalent to the flat
- // shift by (BaseOffset - 2). This routes translation through the segment
- // list with no behavior change; Stage 2b adds redirect/shift segments for
- // duplicated files.
- F.SLocRemap.push_back(
- {/*LocalBegin=*/0, /*LocalEnd=*/~SourceLocation::UIntTy(0),
- /*Delta=*/static_cast<int64_t>(F.SLocEntryBaseOffset) - 2});
+ if (NumDupEntries == 0) {
+ // No de-duplication: one identity segment (== flat shift) and a linear
+ // local->global ID mapping. Register each file as the canonical copy so
+ // later modules can reuse it.
+ F.SLocRemap.push_back(
+ {/*LocalBegin=*/0, /*LocalEnd=*/~SourceLocation::UIntTy(0),
+ /*Delta=*/static_cast<int64_t>(F.SLocEntryBaseOffset) - 2});
+ if (Scanned)
+ for (unsigned I = 0; I != N; ++I)
+ if (Files[I])
+ SourceMgr.registerCanonicalLoadedFile(
+ Files[I], F.SLocEntryBaseOffset + Offsets[I],
+ F.SLocEntryBaseID + (int)I);
+ } else {
+ // De-duplication: build keep/redirect offset segments and the
+ // local->global ID map. Skipped (duplicate) entries get no slot and no
+ // address space; their references are redirected to the canonical copy.
+ F.LocalToGlobalID.assign(N, 0);
+ F.KeptSLocLocalIndex.reserve(ReducedNumEntries);
+ uint64_t DupBefore = 0;
+ unsigned KeptCount = 0;
+ for (unsigned I = 0; I != N; ++I) {
+ SourceLocation::UIntTy LowStart = Offsets[I] + 2;
+ SourceLocation::UIntTy LowEnd =
+ (I + 1 < N ? Offsets[I + 1] : SLocSpaceSize) + 2;
+ const FileEntry *FE = Files[I];
+ if (FE && SourceMgr.isLoadedFileDuplicate(FE)) {
+ // Redirect this file's locations into the module that first loaded
+ // it; reserve nothing here.
+ const SourceManager::LoadedFileLoc *Canon =
+ SourceMgr.getCanonicalLoadedFile(FE);
+ F.SLocRemap.push_back({LowStart, LowEnd,
+ static_cast<int64_t>(Canon->Offset) -
+ static_cast<int64_t>(LowStart)});
+ F.LocalToGlobalID[I] = Canon->ID;
+ DupBefore += LowEnd - LowStart;
+ } else {
+ // Keep: lands in this module's block, shifted down to close gaps
+ // left by skipped duplicates before it.
+ int GlobalID = F.SLocEntryBaseID + (int)KeptCount;
+ SourceLocation::UIntTy GlobalStart =
+ static_cast<SourceLocation::UIntTy>(F.SLocEntryBaseOffset +
+ Offsets[I] - DupBefore);
+ F.SLocRemap.push_back({LowStart, LowEnd,
+ static_cast<int64_t>(GlobalStart) -
+ static_cast<int64_t>(LowStart)});
+ F.LocalToGlobalID[I] = GlobalID;
+ F.KeptSLocLocalIndex.push_back(I);
+ if (FE)
+ SourceMgr.registerCanonicalLoadedFile(FE, GlobalStart, GlobalID);
+ ++KeptCount;
+ }
+ }
+ // Extend the first/last segments to cover the whole value range so
+ // every translated location matches a segment.
+ F.SLocRemap.front().LocalBegin = 0;
+ F.SLocRemap.back().LocalEnd = ~SourceLocation::UIntTy(0);
+ assert(KeptCount == ReducedNumEntries && "kept count mismatch");
+ }
+
// Make our entry in the range map. BaseID is negative and growing, so
// we invert it. Because we invert it, though, we need the other end of
// the range.
unsigned RangeStart =
- unsigned(-F.SLocEntryBaseID) - F.LocalNumSLocEntries + 1;
+ unsigned(-F.SLocEntryBaseID) - ReducedNumEntries + 1;
GlobalSLocEntryMap.insert(std::make_pair(RangeStart, &F));
F.FirstLoc = SourceLocation::getFromRawEncoding(F.SLocEntryBaseOffset);
// SLocEntryBaseOffset is lower than MaxLoadedOffset and decreasing.
assert((F.SLocEntryBaseOffset & SourceLocation::MacroIDBit) == 0);
- GlobalSLocOffsetMap.insert(
- std::make_pair(SourceManager::MaxLoadedOffset - F.SLocEntryBaseOffset
- - SLocSpaceSize,&F));
-
- TotalNumSLocEntries += F.LocalNumSLocEntries;
-
- // De-duplication detection (prototype, Stage 1). Walk this module's SLoc
- // file entries and recognize when the same file was already loaded by an
- // earlier module, measuring the address space a future reuse (Stage 2)
- // could reclaim. Detection only: no allocation/translation change here.
- {
- SmallVector<uint32_t, 64> Offsets;
- SmallVector<const FileEntry *, 64> Files;
- if (scanLoadedSLocEntries(F, Offsets, Files)) {
- unsigned N = Offsets.size();
- for (unsigned I = 0; I != N; ++I) {
- if (!Files[I])
- continue;
- uint64_t Size =
- (I + 1 < N ? Offsets[I + 1] : SLocSpaceSize) - Offsets[I];
- SourceMgr.noteLoadedFileSLocEntry(
- Files[I], F.SLocEntryBaseOffset + Offsets[I], Size);
- }
- }
- }
+ GlobalSLocOffsetMap.insert(std::make_pair(
+ SourceManager::MaxLoadedOffset - F.SLocEntryBaseOffset - ReducedSize,
+ &F));
+
+ TotalNumSLocEntries += ReducedNumEntries;
break;
}
diff --git a/dedup-test/use_err.cpp b/dedup-test/use_err.cpp
new file mode 100644
index 0000000000000..e3cf22fe27df4
--- /dev/null
+++ b/dedup-test/use_err.cpp
@@ -0,0 +1,14 @@
+// Stage 2c: prove the redirect resolves correctly.
+// Include BOTH modules so A loads first (registers shared.h as the canonical
+// copy) and B loads second (its shared.h is de-duplicated / redirected into
+// A's copy). Then trigger a diagnostic whose location lives in shared.h.
+// The error must still point at shared.h:<line> with the right function/line,
+// which only holds if the redirected offsets resolve correctly.
+#include "a.h"
+#include "b.h"
+
+int main() {
+ // shared_fn_1 is defined in shared.h (present in both A and B); pass a bad
+ // argument so overload resolution reports the candidate in shared.h.
+ return a_entry(1) + shared_fn_1("oops");
+}
diff --git a/dedup-test/use_err_rev.cpp b/dedup-test/use_err_rev.cpp
new file mode 100644
index 0000000000000..817bfb4bc2b1e
--- /dev/null
+++ b/dedup-test/use_err_rev.cpp
@@ -0,0 +1,10 @@
+// Stage 2c: load-order independence. Same as use_err.cpp but with the include
+// order flipped so B is seen first. Whichever module loads first becomes the
+// canonical copy; the other redirects into it. Result should be identical:
+// dedup active + the diagnostic still resolves to shared.h:<line>.
+#include "b.h"
+#include "a.h"
+
+int main() {
+ return a_entry(1) + shared_fn_1("oops");
+}
>From 29b5f5f76393a6aef250af3a43f7a69de8c0167c Mon Sep 17 00:00:00 2001
From: Ayokunle Amodu <ayokunle321 at gmail.com>
Date: Wed, 1 Jul 2026 09:53:16 -0400
Subject: [PATCH 04/15] clean up stats files
---
clang/include/clang/Serialization/ASTReader.h | 3 +--
two_modules_stats.txt | 1 -
2 files changed, 1 insertion(+), 3 deletions(-)
delete mode 100644 two_modules_stats.txt
diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h
index a063904e4567e..ec4312cf1972c 100644
--- a/clang/include/clang/Serialization/ASTReader.h
+++ b/clang/include/clang/Serialization/ASTReader.h
@@ -2399,10 +2399,9 @@ class ASTReader : public ExternalPreprocessorSource,
llvm::Expected<SourceLocation::UIntTy> readSLocOffset(ModuleFile *F,
unsigned Index);
- /// Walk module \p F's SLoc entry records (read-only). Fills \p Offsets[i]
+ /// Walk module F's SLoc entry records (read-only). Fills Offsets[i]
/// with each entry's local offset and \p Files[i] with its FileEntry (null
/// for non-file entries). Returns false if the records couldn't be read.
- /// Shared scaffolding for source-location de-duplication.
bool scanLoadedSLocEntries(ModuleFile &F,
SmallVectorImpl<uint32_t> &Offsets,
SmallVectorImpl<const FileEntry *> &Files);
diff --git a/two_modules_stats.txt b/two_modules_stats.txt
deleted file mode 100644
index d0df4d9e70b35..0000000000000
--- a/two_modules_stats.txt
+++ /dev/null
@@ -1 +0,0 @@
-zsh: command not found: -std=c++20
>From eb4ad5a33e934afa5e2f190df4d9ccdf1b7f884e Mon Sep 17 00:00:00 2001
From: Ayokunle Amodu <ayokunle321 at gmail.com>
Date: Wed, 1 Jul 2026 09:56:21 -0400
Subject: [PATCH 05/15] clean up stats files
---
dedup-test/one_module_stats.txt | 352 --------------------
dedup-test/two_modules_stats.txt | 535 -------------------------------
2 files changed, 887 deletions(-)
delete mode 100644 dedup-test/one_module_stats.txt
delete mode 100644 dedup-test/two_modules_stats.txt
diff --git a/dedup-test/one_module_stats.txt b/dedup-test/one_module_stats.txt
deleted file mode 100644
index 373fe97b5e1d8..0000000000000
--- a/dedup-test/one_module_stats.txt
+++ /dev/null
@@ -1,352 +0,0 @@
-
-STATISTICS:
-
-*** Semantic Analysis Stats:
-
-Number of memory regions: 0
-Bytes used: 0
-Bytes allocated: 0
-Bytes wasted: 0 (includes alignment, etc)
-
-*** Analysis Based Warnings Stats:
-401 functions analyzed (0 w/o CFGs).
- 1203 CFG blocks built.
- 3 average CFG blocks per function.
- 3 max CFG blocks per function.
-0 functions analyzed for uninitialiazed variables
- 0 variables analyzed.
- 0 average variables per function.
- 0 max variables per function.
- 0 block visits.
- 0 average block visits per function.
- 0 max block visits per function.
-
-*** LifetimeSafety Missing Origin per QualType: (QualType : count) :
-
-
-
-*** LifetimeSafety Missing Origin per StmtClassName: (StmtClassName : count) :
-
-
-Total missing origins: 0
-
-****************************************
-
-*** AST Context Stats:
- 156 types total.
- 120 Builtin types, 32 each (3840 bytes)
- 1 FunctionProto types, 48 each (48 bytes)
- 5 Pointer types, 48 each (240 bytes)
- 1 Record types, 32 each (32 bytes)
- 1 Typedef types, 32 each (32 bytes)
- 28 Vector types, 48 each (1344 bytes)
-Total bytes = 5536
-0/0 implicit default constructors created
-0/0 implicit copy constructors created
-0/0 implicit move constructors created
-0/0 implicit copy assignment operators created
-0/0 implicit move assignment operators created
-0/0 implicit destructors created
-
-*** AST File Statistics:
-
-*** PCH/ModuleFile Remappings:
-
-*** PCH/Modules Loaded:
-
-Number of memory regions: 62
-Bytes used: 248400
-Bytes allocated: 253952
-Bytes wasted: 5552 (includes alignment, etc)
-
-*** Decl Stats:
- 995 decls total.
- 1 TranslationUnit decls, 104 each (104 bytes)
- 1 ExternCContext decls, 72 each (72 bytes)
- 401 Function decls, 168 each (67368 bytes)
- 401 ParmVar decls, 104 each (41704 bytes)
- 8 Field decls, 80 each (640 bytes)
- 2 CXXRecord decls, 144 each (288 bytes)
- 180 Typedef decls, 88 each (15840 bytes)
- 1 Import decls, 56 each (56 bytes)
-Total bytes = 126072
-
-*** Stmt/Expr Stats:
- 2408 stmts/exprs total.
- 1 UnresolvedLookupExpr, 64 each (64 bytes)
- 400 IntegerLiteral, 32 each (12800 bytes)
- 402 DeclRefExpr, 32 each (12864 bytes)
- 402 ImplicitCastExpr, 24 each (9648 bytes)
- 1 CallExpr, 24 each (24 bytes)
- 400 BinaryOperator, 32 each (12800 bytes)
- 401 ReturnStmt, 16 each (6416 bytes)
- 401 CompoundStmt, 16 each (6416 bytes)
-Total bytes = 61032
-
-STATISTICS FOR './module.modulemap':
-
-*** Preprocessor Stats:
-564 directives found:
- 553 #define.
- 0 #undef.
- #include/#include_next/#import:
- 4 source files entered.
- 1 max include stack depth
- 2 #if/#ifndef/#ifdef.
- 0 #else/#elif/#elifdef/#elifndef.
- 2 #endif.
- 2 #pragma.
-0 #if/#ifndef#ifdef regions skipped
-0/0/0 obj/fn/builtin macros expanded, 0 on the fast path.
-0 token paste (##) operations performed, 0 on the fast path.
-
-Preprocessor Memory: 110103B total
- BumpPtr: 57344
- Macro Expanded Tokens: 384
- Predefines Buffer: 32767
- Macros: 16512
- #pragma push_macro Info: 2056
- Poison Reasons: 1032
- Comment Handlers: 8
-
-*** Identifier Table Stats:
-# Identifiers: 13432
-# Empty Buckets: 19336
-Hash density (#identifiers per bucket): 0.409912
-Ave identifier length: 26.735631
-Max identifier length: 49
-
-Number of memory regions: 182
-Bytes used: 909825
-Bytes allocated: 966656
-Bytes wasted: 56831 (includes alignment, etc)
-
-*** HeaderSearch Stats:
-3 files tracked.
- 0 #import/#pragma once files.
- 2 #include/#include_next/#import.
- 0 #includes skipped due to the multi-include optimization.
-0 framework lookups.
-0 subframework lookups.
-
-*** Source Manager Stats:
-3 files mapped, 3 mem buffers mapped.
-7 local SLocEntries allocated (168 bytes of capacity), 43765B of SLoc address space used.
-0 loaded SLocEntries allocated (0 bytes of capacity), 0B of SLoc address space used.
-20795 bytes of files mapped, 2 files with line #'s computed, 0 files with macro args computed.
-FileID scans: 32 linear, 0 binary.
-
-
-*** File Manager Stats:
-5 real files found, 7 real dirs found.
-0 virtual files found, 0 virtual dirs found.
-28 dir lookups, 9 dir cache misses.
-19 file lookups, 8 file cache misses.
-
-*** Virtual File System Stats:
-14 status() calls
-5 openFileForRead() calls
-0 dir_begin() calls
-1 getRealPath() calls
-0 exists() calls
-0 isLocal() calls
-
-===-------------------------------------------------------------------------===
- ... Statistics Collected ...
-===-------------------------------------------------------------------------===
-
- 2 file-search - Number of attempted #includes.
-43765 source-manager - Maximum number of bytes used by source locations (both loaded and local).
-
-
-STATISTICS:
-
-*** Semantic Analysis Stats:
-
-Number of memory regions: 0
-Bytes used: 0
-Bytes allocated: 0
-Bytes wasted: 0 (includes alignment, etc)
-
-*** Analysis Based Warnings Stats:
-0 functions analyzed (0 w/o CFGs).
- 0 CFG blocks built.
- 0 average CFG blocks per function.
- 0 max CFG blocks per function.
-0 functions analyzed for uninitialiazed variables
- 0 variables analyzed.
- 0 average variables per function.
- 0 max variables per function.
- 0 block visits.
- 0 average block visits per function.
- 0 max block visits per function.
-
-*** LifetimeSafety Missing Origin per QualType: (QualType : count) :
-
-
-
-*** LifetimeSafety Missing Origin per StmtClassName: (StmtClassName : count) :
-
-
-Total missing origins: 0
-
-****************************************
-
-*** AST Context Stats:
- 157 types total.
- 120 Builtin types, 32 each (3840 bytes)
- 2 FunctionProto types, 48 each (96 bytes)
- 6 Pointer types, 48 each (288 bytes)
- 1 Record types, 32 each (32 bytes)
- 28 Vector types, 48 each (1344 bytes)
-Total bytes = 5600
-0/0 implicit default constructors created
-0/0 implicit copy constructors created
-0/0 implicit move constructors created
-0/0 implicit copy assignment operators created
-0/0 implicit move assignment operators created
-0/0 implicit destructors created
-
-*** AST File Statistics:
- 0/6 source location entries read (0.000000%)
- 2/32 types read (6.250000%)
- 516/888 declarations read (58.108109%)
- 7/496 identifiers read (1.411290%)
- 0/2 macros read (0.000000%)
- 7/2407 statements read (0.290818%)
- 0/2 macros read (0.000000%)
- 0/401 lexical declcontexts read (0.000000%)
-
-*** PCH/ModuleFile Remappings:
-Global bit offset map:
- 0 -> /Users/ayokunleamodu/Repos/llvm-project/dedup-test/cache1/71GTEYCXW85I/A-CAAI8SHN1D31.pcm
-Global source location entry map:
- 2 -> /Users/ayokunleamodu/Repos/llvm-project/dedup-test/cache1/71GTEYCXW85I/A-CAAI8SHN1D31.pcm
-Global submodule map:
- 1 -> /Users/ayokunleamodu/Repos/llvm-project/dedup-test/cache1/71GTEYCXW85I/A-CAAI8SHN1D31.pcm
-
-*** PCH/Modules Loaded:
-Module: /Users/ayokunleamodu/Repos/llvm-project/dedup-test/cache1/71GTEYCXW85I/A-CAAI8SHN1D31.pcm
- Base source location offset: 2147439884
- Base identifier ID: 0
- Number of identifiers: 496
- Base macro ID: 0
- Number of macros: 2
- Base submodule ID: 0
- Number of submodules: 1
- Submodule ID local -> global map:
- 0 -> 0
- Base selector ID: 0
- Number of selectors: 0
- Base preprocessed entity ID: 0
- Number of preprocessed entities: 0
- Base type index: 0
- Number of types: 32
- Base decl index: 0
- Number of decls: 888
-
-
-Number of memory regions: 5
-Bytes used: 18452
-Bytes allocated: 20480
-Bytes wasted: 2028 (includes alignment, etc)
-
-*** Decl Stats:
- 1002 decls total.
- 1 TranslationUnit decls, 104 each (104 bytes)
- 2 ExternCContext decls, 72 each (144 bytes)
- 404 Function decls, 168 each (67872 bytes)
- 403 ParmVar decls, 104 each (41912 bytes)
- 8 Field decls, 80 each (640 bytes)
- 2 CXXRecord decls, 144 each (288 bytes)
- 180 Typedef decls, 88 each (15840 bytes)
- 2 Import decls, 56 each (112 bytes)
-Total bytes = 126912
-
-*** Stmt/Expr Stats:
- 2422 stmts/exprs total.
- 2 UnresolvedLookupExpr, 64 each (128 bytes)
- 401 IntegerLiteral, 32 each (12832 bytes)
- 405 DeclRefExpr, 32 each (12960 bytes)
- 405 ImplicitCastExpr, 24 each (9720 bytes)
- 3 CallExpr, 24 each (72 bytes)
- 400 BinaryOperator, 32 each (12800 bytes)
- 403 ReturnStmt, 16 each (6448 bytes)
- 403 CompoundStmt, 16 each (6448 bytes)
-Total bytes = 61408
-
-STATISTICS FOR 'use1.cpp':
-
-*** Preprocessor Stats:
-558 directives found:
- 552 #define.
- 0 #undef.
- #include/#include_next/#import:
- 2 source files entered.
- 0 max include stack depth
- 0 #if/#ifndef/#ifdef.
- 0 #else/#elif/#elifdef/#elifndef.
- 0 #endif.
- 2 #pragma.
-0 #if/#ifndef#ifdef regions skipped
-0/0/0 obj/fn/builtin macros expanded, 0 on the fast path.
-0 token paste (##) operations performed, 0 on the fast path.
-
-Preprocessor Memory: 106007B total
- BumpPtr: 53248
- Macro Expanded Tokens: 384
- Predefines Buffer: 32767
- Macros: 16512
- #pragma push_macro Info: 2056
- Poison Reasons: 1032
- Comment Handlers: 8
-
-*** Identifier Table Stats:
-# Identifiers: 13033
-# Empty Buckets: 19735
-Hash density (#identifiers per bucket): 0.397736
-Ave identifier length: 27.165119
-Max identifier length: 49
-
-Number of memory regions: 180
-Bytes used: 888396
-Bytes allocated: 950272
-Bytes wasted: 61876 (includes alignment, etc)
-
-*** HeaderSearch Stats:
-3 files tracked.
- 0 #import/#pragma once files.
- 2 #include/#include_next/#import.
- 0 #includes skipped due to the multi-include optimization.
-0 framework lookups.
-0 subframework lookups.
-
-*** Source Manager Stats:
-2 files mapped, 2 mem buffers mapped.
-5 local SLocEntries allocated (168 bytes of capacity), 23108B of SLoc address space used.
-6 loaded SLocEntries allocated (768 bytes of capacity), 43764B of SLoc address space used.
-119 bytes of files mapped, 0 files with line #'s computed, 0 files with macro args computed.
-FileID scans: 11 linear, 0 binary.
-
-
-*** File Manager Stats:
-6 real files found, 8 real dirs found.
-0 virtual files found, 0 virtual dirs found.
-31 dir lookups, 11 dir cache misses.
-27 file lookups, 9 file cache misses.
-
-*** Virtual File System Stats:
-17 status() calls
-6 openFileForRead() calls
-0 dir_begin() calls
-1 getRealPath() calls
-0 exists() calls
-0 isLocal() calls
-
-===-------------------------------------------------------------------------===
- ... Statistics Collected ...
-===-------------------------------------------------------------------------===
-
- 2 file-search - Number of attempted #includes.
-66872 source-manager - Maximum number of bytes used by source locations (both loaded and local).
-
diff --git a/dedup-test/two_modules_stats.txt b/dedup-test/two_modules_stats.txt
deleted file mode 100644
index dd3a1f0c2d3ac..0000000000000
--- a/dedup-test/two_modules_stats.txt
+++ /dev/null
@@ -1,535 +0,0 @@
-
-STATISTICS:
-
-*** Semantic Analysis Stats:
-
-Number of memory regions: 0
-Bytes used: 0
-Bytes allocated: 0
-Bytes wasted: 0 (includes alignment, etc)
-
-*** Analysis Based Warnings Stats:
-401 functions analyzed (0 w/o CFGs).
- 1203 CFG blocks built.
- 3 average CFG blocks per function.
- 3 max CFG blocks per function.
-0 functions analyzed for uninitialiazed variables
- 0 variables analyzed.
- 0 average variables per function.
- 0 max variables per function.
- 0 block visits.
- 0 average block visits per function.
- 0 max block visits per function.
-
-*** LifetimeSafety Missing Origin per QualType: (QualType : count) :
-
-
-
-*** LifetimeSafety Missing Origin per StmtClassName: (StmtClassName : count) :
-
-
-Total missing origins: 0
-
-****************************************
-
-*** AST Context Stats:
- 156 types total.
- 120 Builtin types, 32 each (3840 bytes)
- 1 FunctionProto types, 48 each (48 bytes)
- 5 Pointer types, 48 each (240 bytes)
- 1 Record types, 32 each (32 bytes)
- 1 Typedef types, 32 each (32 bytes)
- 28 Vector types, 48 each (1344 bytes)
-Total bytes = 5536
-0/0 implicit default constructors created
-0/0 implicit copy constructors created
-0/0 implicit move constructors created
-0/0 implicit copy assignment operators created
-0/0 implicit move assignment operators created
-0/0 implicit destructors created
-
-*** AST File Statistics:
-
-*** PCH/ModuleFile Remappings:
-
-*** PCH/Modules Loaded:
-
-Number of memory regions: 62
-Bytes used: 248400
-Bytes allocated: 253952
-Bytes wasted: 5552 (includes alignment, etc)
-
-*** Decl Stats:
- 995 decls total.
- 1 TranslationUnit decls, 104 each (104 bytes)
- 1 ExternCContext decls, 72 each (72 bytes)
- 401 Function decls, 168 each (67368 bytes)
- 401 ParmVar decls, 104 each (41704 bytes)
- 8 Field decls, 80 each (640 bytes)
- 2 CXXRecord decls, 144 each (288 bytes)
- 180 Typedef decls, 88 each (15840 bytes)
- 1 Import decls, 56 each (56 bytes)
-Total bytes = 126072
-
-*** Stmt/Expr Stats:
- 2408 stmts/exprs total.
- 1 UnresolvedLookupExpr, 64 each (64 bytes)
- 400 IntegerLiteral, 32 each (12800 bytes)
- 402 DeclRefExpr, 32 each (12864 bytes)
- 402 ImplicitCastExpr, 24 each (9648 bytes)
- 1 CallExpr, 24 each (24 bytes)
- 400 BinaryOperator, 32 each (12800 bytes)
- 401 ReturnStmt, 16 each (6416 bytes)
- 401 CompoundStmt, 16 each (6416 bytes)
-Total bytes = 61032
-
-STATISTICS FOR './module.modulemap':
-
-*** Preprocessor Stats:
-564 directives found:
- 553 #define.
- 0 #undef.
- #include/#include_next/#import:
- 4 source files entered.
- 1 max include stack depth
- 2 #if/#ifndef/#ifdef.
- 0 #else/#elif/#elifdef/#elifndef.
- 2 #endif.
- 2 #pragma.
-0 #if/#ifndef#ifdef regions skipped
-0/0/0 obj/fn/builtin macros expanded, 0 on the fast path.
-0 token paste (##) operations performed, 0 on the fast path.
-
-Preprocessor Memory: 110103B total
- BumpPtr: 57344
- Macro Expanded Tokens: 384
- Predefines Buffer: 32767
- Macros: 16512
- #pragma push_macro Info: 2056
- Poison Reasons: 1032
- Comment Handlers: 8
-
-*** Identifier Table Stats:
-# Identifiers: 13432
-# Empty Buckets: 19336
-Hash density (#identifiers per bucket): 0.409912
-Ave identifier length: 26.735631
-Max identifier length: 49
-
-Number of memory regions: 182
-Bytes used: 909825
-Bytes allocated: 966656
-Bytes wasted: 56831 (includes alignment, etc)
-
-*** HeaderSearch Stats:
-3 files tracked.
- 0 #import/#pragma once files.
- 2 #include/#include_next/#import.
- 0 #includes skipped due to the multi-include optimization.
-0 framework lookups.
-0 subframework lookups.
-
-*** Source Manager Stats:
-3 files mapped, 3 mem buffers mapped.
-7 local SLocEntries allocated (168 bytes of capacity), 43765B of SLoc address space used.
-0 loaded SLocEntries allocated (0 bytes of capacity), 0B of SLoc address space used.
-20795 bytes of files mapped, 2 files with line #'s computed, 0 files with macro args computed.
-FileID scans: 32 linear, 0 binary.
-
-
-*** File Manager Stats:
-5 real files found, 7 real dirs found.
-0 virtual files found, 0 virtual dirs found.
-28 dir lookups, 9 dir cache misses.
-19 file lookups, 8 file cache misses.
-
-*** Virtual File System Stats:
-14 status() calls
-5 openFileForRead() calls
-0 dir_begin() calls
-1 getRealPath() calls
-0 exists() calls
-0 isLocal() calls
-
-===-------------------------------------------------------------------------===
- ... Statistics Collected ...
-===-------------------------------------------------------------------------===
-
- 2 file-search - Number of attempted #includes.
-43765 source-manager - Maximum number of bytes used by source locations (both loaded and local).
-
-
-STATISTICS:
-
-*** Semantic Analysis Stats:
-
-Number of memory regions: 0
-Bytes used: 0
-Bytes allocated: 0
-Bytes wasted: 0 (includes alignment, etc)
-
-*** Analysis Based Warnings Stats:
-401 functions analyzed (0 w/o CFGs).
- 1203 CFG blocks built.
- 3 average CFG blocks per function.
- 3 max CFG blocks per function.
-0 functions analyzed for uninitialiazed variables
- 0 variables analyzed.
- 0 average variables per function.
- 0 max variables per function.
- 0 block visits.
- 0 average block visits per function.
- 0 max block visits per function.
-
-*** LifetimeSafety Missing Origin per QualType: (QualType : count) :
-
-
-
-*** LifetimeSafety Missing Origin per StmtClassName: (StmtClassName : count) :
-
-
-Total missing origins: 0
-
-****************************************
-
-*** AST Context Stats:
- 156 types total.
- 120 Builtin types, 32 each (3840 bytes)
- 1 FunctionProto types, 48 each (48 bytes)
- 5 Pointer types, 48 each (240 bytes)
- 1 Record types, 32 each (32 bytes)
- 1 Typedef types, 32 each (32 bytes)
- 28 Vector types, 48 each (1344 bytes)
-Total bytes = 5536
-0/0 implicit default constructors created
-0/0 implicit copy constructors created
-0/0 implicit move constructors created
-0/0 implicit copy assignment operators created
-0/0 implicit move assignment operators created
-0/0 implicit destructors created
-
-*** AST File Statistics:
-
-*** PCH/ModuleFile Remappings:
-
-*** PCH/Modules Loaded:
-
-Number of memory regions: 62
-Bytes used: 248400
-Bytes allocated: 253952
-Bytes wasted: 5552 (includes alignment, etc)
-
-*** Decl Stats:
- 1896 decls total.
- 2 TranslationUnit decls, 104 each (208 bytes)
- 2 ExternCContext decls, 72 each (144 bytes)
- 802 Function decls, 168 each (134736 bytes)
- 802 ParmVar decls, 104 each (83408 bytes)
- 12 Field decls, 80 each (960 bytes)
- 3 CXXRecord decls, 144 each (432 bytes)
- 270 Typedef decls, 88 each (23760 bytes)
- 3 Import decls, 56 each (168 bytes)
-Total bytes = 243816
-
-*** Stmt/Expr Stats:
- 4816 stmts/exprs total.
- 2 UnresolvedLookupExpr, 64 each (128 bytes)
- 800 IntegerLiteral, 32 each (25600 bytes)
- 804 DeclRefExpr, 32 each (25728 bytes)
- 804 ImplicitCastExpr, 24 each (19296 bytes)
- 2 CallExpr, 24 each (48 bytes)
- 800 BinaryOperator, 32 each (25600 bytes)
- 802 ReturnStmt, 16 each (12832 bytes)
- 802 CompoundStmt, 16 each (12832 bytes)
-Total bytes = 122064
-
-STATISTICS FOR './module.modulemap':
-
-*** Preprocessor Stats:
-564 directives found:
- 553 #define.
- 0 #undef.
- #include/#include_next/#import:
- 4 source files entered.
- 1 max include stack depth
- 2 #if/#ifndef/#ifdef.
- 0 #else/#elif/#elifdef/#elifndef.
- 2 #endif.
- 2 #pragma.
-0 #if/#ifndef#ifdef regions skipped
-0/0/0 obj/fn/builtin macros expanded, 0 on the fast path.
-0 token paste (##) operations performed, 0 on the fast path.
-
-Preprocessor Memory: 110103B total
- BumpPtr: 57344
- Macro Expanded Tokens: 384
- Predefines Buffer: 32767
- Macros: 16512
- #pragma push_macro Info: 2056
- Poison Reasons: 1032
- Comment Handlers: 8
-
-*** Identifier Table Stats:
-# Identifiers: 13432
-# Empty Buckets: 19336
-Hash density (#identifiers per bucket): 0.409912
-Ave identifier length: 26.735631
-Max identifier length: 49
-
-Number of memory regions: 182
-Bytes used: 909825
-Bytes allocated: 966656
-Bytes wasted: 56831 (includes alignment, etc)
-
-*** HeaderSearch Stats:
-3 files tracked.
- 0 #import/#pragma once files.
- 4 #include/#include_next/#import.
- 0 #includes skipped due to the multi-include optimization.
-0 framework lookups.
-0 subframework lookups.
-
-*** Source Manager Stats:
-3 files mapped, 3 mem buffers mapped.
-7 local SLocEntries allocated (168 bytes of capacity), 43765B of SLoc address space used.
-0 loaded SLocEntries allocated (0 bytes of capacity), 0B of SLoc address space used.
-20795 bytes of files mapped, 2 files with line #'s computed, 0 files with macro args computed.
-FileID scans: 32 linear, 0 binary.
-
-
-*** File Manager Stats:
-5 real files found, 7 real dirs found.
-0 virtual files found, 0 virtual dirs found.
-42 dir lookups, 10 dir cache misses.
-38 file lookups, 8 file cache misses.
-
-*** Virtual File System Stats:
-15 status() calls
-8 openFileForRead() calls
-0 dir_begin() calls
-1 getRealPath() calls
-0 exists() calls
-0 isLocal() calls
-
-===-------------------------------------------------------------------------===
- ... Statistics Collected ...
-===-------------------------------------------------------------------------===
-
- 4 file-search - Number of attempted #includes.
-66900 source-manager - Maximum number of bytes used by source locations (both loaded and local).
-
-
-STATISTICS:
-
-*** Semantic Analysis Stats:
-
-Number of memory regions: 0
-Bytes used: 0
-Bytes allocated: 0
-Bytes wasted: 0 (includes alignment, etc)
-
-*** Analysis Based Warnings Stats:
-0 functions analyzed (0 w/o CFGs).
- 0 CFG blocks built.
- 0 average CFG blocks per function.
- 0 max CFG blocks per function.
-0 functions analyzed for uninitialiazed variables
- 0 variables analyzed.
- 0 average variables per function.
- 0 max variables per function.
- 0 block visits.
- 0 average block visits per function.
- 0 max block visits per function.
-
-*** LifetimeSafety Missing Origin per QualType: (QualType : count) :
-
-
-
-*** LifetimeSafety Missing Origin per StmtClassName: (StmtClassName : count) :
-
-
-Total missing origins: 0
-
-****************************************
-
-*** AST Context Stats:
- 157 types total.
- 120 Builtin types, 32 each (3840 bytes)
- 2 FunctionProto types, 48 each (96 bytes)
- 6 Pointer types, 48 each (288 bytes)
- 1 Record types, 32 each (32 bytes)
- 28 Vector types, 48 each (1344 bytes)
-Total bytes = 5600
-0/0 implicit default constructors created
-0/0 implicit copy constructors created
-0/0 implicit move constructors created
-0/0 implicit copy assignment operators created
-0/0 implicit move assignment operators created
-0/0 implicit destructors created
-
-*** AST File Statistics:
- 0/12 source location entries read (0.000000%)
- 4/64 types read (6.250000%)
- 1032/1776 declarations read (58.108109%)
- 14/992 identifiers read (1.411290%)
- 0/4 macros read (0.000000%)
- 14/4814 statements read (0.290818%)
- 0/4 macros read (0.000000%)
- 0/802 lexical declcontexts read (0.000000%)
-
-*** PCH/ModuleFile Remappings:
-Global bit offset map:
- 0 -> /Users/ayokunleamodu/Repos/llvm-project/dedup-test/cache/71GTEYCXW85I/A-CAAI8SHN1D31.pcm
- 1144160 -> /Users/ayokunleamodu/Repos/llvm-project/dedup-test/cache/71GTEYCXW85I/B-CAAI8SHN1D31.pcm
-Global source location entry map:
- 2 -> /Users/ayokunleamodu/Repos/llvm-project/dedup-test/cache/71GTEYCXW85I/A-CAAI8SHN1D31.pcm
- 8 -> /Users/ayokunleamodu/Repos/llvm-project/dedup-test/cache/71GTEYCXW85I/B-CAAI8SHN1D31.pcm
-Global submodule map:
- 1 -> /Users/ayokunleamodu/Repos/llvm-project/dedup-test/cache/71GTEYCXW85I/A-CAAI8SHN1D31.pcm
- 2 -> /Users/ayokunleamodu/Repos/llvm-project/dedup-test/cache/71GTEYCXW85I/B-CAAI8SHN1D31.pcm
-
-*** PCH/Modules Loaded:
-Module: /Users/ayokunleamodu/Repos/llvm-project/dedup-test/cache/71GTEYCXW85I/A-CAAI8SHN1D31.pcm
- Base source location offset: 2147439884
- Base identifier ID: 0
- Number of identifiers: 496
- Base macro ID: 0
- Number of macros: 2
- Base submodule ID: 0
- Number of submodules: 1
- Submodule ID local -> global map:
- 0 -> 0
- Base selector ID: 0
- Number of selectors: 0
- Base preprocessed entity ID: 0
- Number of preprocessed entities: 0
- Base type index: 0
- Number of types: 32
- Base decl index: 0
- Number of decls: 888
-
-Module: /Users/ayokunleamodu/Repos/llvm-project/dedup-test/cache/71GTEYCXW85I/B-CAAI8SHN1D31.pcm
- Base source location offset: 2147396120
- Base identifier ID: 496
- Number of identifiers: 496
- Base macro ID: 2
- Number of macros: 2
- Base submodule ID: 1
- Number of submodules: 1
- Submodule ID local -> global map:
- 0 -> 1
- Base selector ID: 0
- Number of selectors: 0
- Base preprocessed entity ID: 0
- Number of preprocessed entities: 0
- Base type index: 32
- Number of types: 32
- Base decl index: 888
- Number of decls: 888
-
-
-Number of memory regions: 5
-Bytes used: 19784
-Bytes allocated: 20480
-Bytes wasted: 696 (includes alignment, etc)
-
-*** Decl Stats:
- 1907 decls total.
- 2 TranslationUnit decls, 104 each (208 bytes)
- 3 ExternCContext decls, 72 each (216 bytes)
- 807 Function decls, 168 each (135576 bytes)
- 806 ParmVar decls, 104 each (83824 bytes)
- 12 Field decls, 80 each (960 bytes)
- 3 CXXRecord decls, 144 each (432 bytes)
- 270 Typedef decls, 88 each (23760 bytes)
- 4 Import decls, 56 each (224 bytes)
-Total bytes = 245200
-
-*** Stmt/Expr Stats:
- 4843 stmts/exprs total.
- 4 UnresolvedLookupExpr, 64 each (256 bytes)
- 802 IntegerLiteral, 32 each (25664 bytes)
- 810 DeclRefExpr, 32 each (25920 bytes)
- 810 ImplicitCastExpr, 24 each (19440 bytes)
- 6 CallExpr, 24 each (144 bytes)
- 801 BinaryOperator, 32 each (25632 bytes)
- 805 ReturnStmt, 16 each (12880 bytes)
- 805 CompoundStmt, 16 each (12880 bytes)
-Total bytes = 122816
-
-STATISTICS FOR 'use.cpp':
-
-*** Preprocessor Stats:
-559 directives found:
- 552 #define.
- 0 #undef.
- #include/#include_next/#import:
- 2 source files entered.
- 0 max include stack depth
- 0 #if/#ifndef/#ifdef.
- 0 #else/#elif/#elifdef/#elifndef.
- 0 #endif.
- 2 #pragma.
-0 #if/#ifndef#ifdef regions skipped
-0/0/0 obj/fn/builtin macros expanded, 0 on the fast path.
-0 token paste (##) operations performed, 0 on the fast path.
-
-Preprocessor Memory: 106007B total
- BumpPtr: 53248
- Macro Expanded Tokens: 384
- Predefines Buffer: 32767
- Macros: 16512
- #pragma push_macro Info: 2056
- Poison Reasons: 1032
- Comment Handlers: 8
-
-*** Identifier Table Stats:
-# Identifiers: 13037
-# Empty Buckets: 19731
-Hash density (#identifiers per bucket): 0.397858
-Ave identifier length: 27.158472
-Max identifier length: 49
-
-Number of memory regions: 180
-Bytes used: 888582
-Bytes allocated: 950272
-Bytes wasted: 61690 (includes alignment, etc)
-
-*** HeaderSearch Stats:
-3 files tracked.
- 0 #import/#pragma once files.
- 4 #include/#include_next/#import.
- 0 #includes skipped due to the multi-include optimization.
-0 framework lookups.
-0 subframework lookups.
-
-*** Source Manager Stats:
-2 files mapped, 2 mem buffers mapped.
-5 local SLocEntries allocated (168 bytes of capacity), 23136B of SLoc address space used.
-12 loaded SLocEntries allocated (768 bytes of capacity), 87528B of SLoc address space used.
-2 duplicate loaded file SLocEntries detected (20694B of SLoc address space reusable).
-147 bytes of files mapped, 0 files with line #'s computed, 0 files with macro args computed.
-FileID scans: 15 linear, 0 binary.
-
-
-*** File Manager Stats:
-7 real files found, 8 real dirs found.
-0 virtual files found, 0 virtual dirs found.
-46 dir lookups, 11 dir cache misses.
-47 file lookups, 10 file cache misses.
-
-*** Virtual File System Stats:
-18 status() calls
-10 openFileForRead() calls
-0 dir_begin() calls
-1 getRealPath() calls
-0 exists() calls
-0 isLocal() calls
-
-===-------------------------------------------------------------------------===
- ... Statistics Collected ...
-===-------------------------------------------------------------------------===
-
- 4 file-search - Number of attempted #includes.
-110664 source-manager - Maximum number of bytes used by source locations (both loaded and local).
-
>From 26201a329de8246171027cd1ec676b5905a49d23 Mon Sep 17 00:00:00 2001
From: Ayokunle Amodu <ayokunle321 at gmail.com>
Date: Mon, 6 Jul 2026 14:37:08 -0400
Subject: [PATCH 06/15] fix SLoc de-dup miscount for files repeated within a
module
---
clang/lib/Serialization/ASTReader.cpp | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index d8041c06a4674..872c5bd458fac 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -4314,15 +4314,20 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
SmallVector<const FileEntry *, 64> Files;
bool Scanned = scanLoadedSLocEntries(F, Offsets, Files);
- // Classify duplicates and compute the reduced allocation request.
+ // Classify each entry against the canonical map as it stands now, before
+ // this module registers any of its own files, and store the decision per
+ // entry. The build pass reads these flags, so a file that appears
+ // multiple times in this module is classified consistently.
auto entrySize = [&](unsigned I) -> uint64_t {
return (I + 1 < N ? Offsets[I + 1] : SLocSpaceSize) - Offsets[I];
};
+ SmallVector<bool, 64> IsDup(N, false);
unsigned NumDupEntries = 0;
uint64_t DupBytes = 0;
if (Scanned)
for (unsigned I = 0; I != N; ++I)
if (SourceMgr.isLoadedFileDuplicate(Files[I])) {
+ IsDup[I] = true;
uint64_t Size = entrySize(I);
SourceMgr.noteDuplicateLoadedFile(Size);
DupBytes += Size;
@@ -4368,7 +4373,7 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
SourceLocation::UIntTy LowEnd =
(I + 1 < N ? Offsets[I + 1] : SLocSpaceSize) + 2;
const FileEntry *FE = Files[I];
- if (FE && SourceMgr.isLoadedFileDuplicate(FE)) {
+ if (IsDup[I]) {
// Redirect this file's locations into the module that first loaded
// it; reserve nothing here.
const SourceManager::LoadedFileLoc *Canon =
>From 027f60306055f085b91655bc590f7dc592f60a2c Mon Sep 17 00:00:00 2001
From: Ayokunle Amodu <ayokunle321 at gmail.com>
Date: Mon, 6 Jul 2026 14:54:07 -0400
Subject: [PATCH 07/15] clean up comments
---
clang/include/clang/Basic/SourceManager.h | 19 ++++-----
clang/include/clang/Serialization/ASTReader.h | 32 ++++++---------
.../include/clang/Serialization/ModuleFile.h | 30 +++++++-------
clang/lib/Serialization/ASTReader.cpp | 40 ++++++++-----------
4 files changed, 56 insertions(+), 65 deletions(-)
diff --git a/clang/include/clang/Basic/SourceManager.h b/clang/include/clang/Basic/SourceManager.h
index 75b346018bb67..4809a9dcbbd46 100644
--- a/clang/include/clang/Basic/SourceManager.h
+++ b/clang/include/clang/Basic/SourceManager.h
@@ -755,22 +755,23 @@ class SourceManager : public RefCountedBase<SourceManager> {
static const SourceLocation::UIntTy MaxLoadedOffset =
1ULL << (8 * sizeof(SourceLocation::UIntTy) - 1);
- /// --- Source-location de-duplication (prototype, Stage 2) ---
- /// The canonical loaded location of a file: where its SLoc entry first landed
- /// in the global address space. Lets a later module reuse it instead of
- /// re-allocating. Keyed by FileEntry identity (the same identity Clang uses
- /// to dedup file content).
+ // === Source location de-duplication ===
public:
+ /// Where a file's SLoc entry first landed in the loaded address space. A file
+ /// shared by several modules is loaded once; later modules reuse this rather
+ /// than allocating their own.
struct LoadedFileLoc {
- SourceLocation::UIntTy Offset = 0; ///< global raw start offset
+ SourceLocation::UIntTy Offset = 0; ///< global start offset
int ID = 0; ///< global SLoc entry ID
};
private:
+ /// The first loaded location of each file, keyed by the FileEntry identity
+ /// Clang already uses to share file contents.
llvm::DenseMap<const FileEntry *, LoadedFileLoc> CanonicalLoadedFiles;
- /// Number of loaded file SLoc entries that duplicated an already-loaded file.
+ /// Number of loaded file entries reused from an earlier module.
unsigned NumDuplicateLoadedFiles = 0;
- /// SLoc address-space bytes those duplicates reused instead of allocating.
+ /// Address-space bytes reused instead of allocated, for -print-stats.
uint64_t DuplicateLoadedBytes = 0;
public:
@@ -793,7 +794,7 @@ class SourceManager : public RefCountedBase<SourceManager> {
CanonicalLoadedFiles.try_emplace(FE, LoadedFileLoc{Offset, ID});
}
- /// Account for a de-duplicated file entry (for -print-stats reporting).
+ /// Record that a loaded file entry was reused from an earlier module.
void noteDuplicateLoadedFile(uint64_t Size) {
++NumDuplicateLoadedFiles;
DuplicateLoadedBytes += Size;
diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h
index ec4312cf1972c..a9991091fc659 100644
--- a/clang/include/clang/Serialization/ASTReader.h
+++ b/clang/include/clang/Serialization/ASTReader.h
@@ -2399,17 +2399,16 @@ class ASTReader : public ExternalPreprocessorSource,
llvm::Expected<SourceLocation::UIntTy> readSLocOffset(ModuleFile *F,
unsigned Index);
- /// Walk module F's SLoc entry records (read-only). Fills Offsets[i]
- /// with each entry's local offset and \p Files[i] with its FileEntry (null
- /// for non-file entries). Returns false if the records couldn't be read.
+ /// Read \p F's SLoc entry records without materializing them, filling
+ /// \p Offsets[i] with each entry's local offset and \p Files[i] with its
+ /// FileEntry (null for non-file entries). Returns false on a malformed record.
bool scanLoadedSLocEntries(ModuleFile &F,
SmallVectorImpl<uint32_t> &Offsets,
SmallVectorImpl<const FileEntry *> &Files);
- /// Map a module-local SLoc entry offset (the value stored in an entry record,
- /// i.e. Record[0]) to its global raw start offset, applying the
- /// de-duplication remap. Equals (SLocEntryBaseOffset + LocalOffset) when the
- /// module is not de-duplicated.
+ /// Map a local SLoc entry offset (as stored in the entry record) to its
+ /// global start offset. This is (SLocEntryBaseOffset + LocalOffset) unless a
+ /// file in this module was reused from an earlier one.
SourceLocation::UIntTy remapSLocEntryOffset(ModuleFile &F,
uint32_t LocalOffset) const;
@@ -2507,15 +2506,10 @@ class ASTReader : public ExternalPreprocessorSource,
// translated or refactor the code to make it clear that
// TranslateSourceLocation won't be called with translated source location.
- // De-duplication (Stage 2): a module's local->global offset map may be
- // piecewise rather than a single flat shift, so look up the segment that
- // covers this location. The seeded identity segment makes this identical to
- // the flat shift below; redirect segments (Stage 2b) send a duplicated
- // file's locations into the module that first loaded it.
- //
- // Segments are keyed by the *file-offset* part of the location, so strip
- // the macro bit before matching and re-apply it to the result (a macro
- // location encodes its position in the low bits with the high bit set).
+ // When a file in this module was reused from an earlier one, the map is
+ // piecewise rather than a single shift, so find the segment covering this
+ // location. A macro location keeps its offset in the low bits with the high
+ // bit set, so match on the offset part and re-apply the bit to the result.
if (!ModuleFile.SLocRemap.empty()) {
SourceLocation::UIntTy Raw = Loc.getRawEncoding();
SourceLocation::UIntTy MacroBit = Raw & SourceLocation::MacroIDBit;
@@ -2550,9 +2544,9 @@ class ASTReader : public ExternalPreprocessorSource,
assert(FID.ID >= 0 && "Reading non-local FileID.");
if (FID.isInvalid())
return FID;
- // De-duplication (Stage 2b): a local FileID may map to the canonical copy
- // in an earlier module, so consult the explicit map when present. Local
- // FileID N corresponds to local entry index N-1.
+ // When a file was reused from an earlier module, its local FileID maps to
+ // that module's copy, so use the explicit map. Local FileID N is local
+ // entry index N-1.
if (!F.LocalToGlobalID.empty()) {
assert((unsigned)(FID.ID - 1) < F.LocalToGlobalID.size() &&
"local FileID out of range");
diff --git a/clang/include/clang/Serialization/ModuleFile.h b/clang/include/clang/Serialization/ModuleFile.h
index 6b65089cc7e6b..a985c17904aa6 100644
--- a/clang/include/clang/Serialization/ModuleFile.h
+++ b/clang/include/clang/Serialization/ModuleFile.h
@@ -346,31 +346,33 @@ class ModuleFile {
/// AST file.
const uint32_t *SLocEntryOffsets = nullptr;
- // === Source-location de-duplication: offset remap (prototype, Stage 2) ===
+ // === Source location de-duplication ===
- /// One offset-remap segment in this module's raw SourceLocation space:
- /// a raw local location L in [LocalBegin, LocalEnd) maps to global L + Delta.
+ /// One segment of the local-to-global source location map: a local raw
+ /// location L in [LocalBegin, LocalEnd) maps to the global location L + Delta.
struct SLocRemapSegment {
SourceLocation::UIntTy LocalBegin;
SourceLocation::UIntTy LocalEnd;
int64_t Delta;
};
- /// Piecewise local->global offset map for this module, sorted by LocalBegin.
- /// Empty => fall back to the flat shift by (SLocEntryBaseOffset - 2).
- /// Stage 2a seeds a single identity segment equivalent to the flat shift;
- /// Stage 2b adds redirect/shift segments for de-duplicated files.
+ /// The local-to-global source location map for this module, sorted by
+ /// LocalBegin. A module whose files are all distinct has a single segment
+ /// equivalent to the flat shift by (SLocEntryBaseOffset - 2); when a file is
+ /// reused from an earlier module, extra segments redirect that file's
+ /// locations into the earlier module. Empty for a module that is not loaded
+ /// through this path, in which case the flat shift is used directly.
llvm::SmallVector<SLocRemapSegment, 4> SLocRemap;
- /// Maps a local SLoc entry index -> its resulting global SLoc entry ID.
- /// Kept entries map to their own newly-allocated ID; de-duplicated entries
- /// map to the ID of the canonical copy in an earlier module. Empty => no
- /// de-duplication for this module (global ID is SLocEntryBaseID + index).
+ /// Maps a local SLoc entry index to its global SLoc entry ID. A kept entry
+ /// maps to its own ID; a file reused from an earlier module maps to that
+ /// module's copy. Empty when no file was reused (the global ID is then
+ /// SLocEntryBaseID + index).
std::vector<int> LocalToGlobalID;
- /// For each kept global slot j (0-based, relative to SLocEntryBaseID), the
- /// original local entry index in this module (index into SLocEntryOffsets).
- /// Empty => no de-duplication (kept slot j == local index j).
+ /// For each kept entry, in order, its original local index (into
+ /// SLocEntryOffsets). Reused entries have no slot, so this skips them. Empty
+ /// when no file was reused (kept slot j is then local index j).
std::vector<unsigned> KeptSLocLocalIndex;
// === Identifiers ===
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 872c5bd458fac..f2e69bd42d1cb 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -1913,9 +1913,8 @@ int ASTReader::getSLocEntryID(SourceLocation::UIntTy SLocOffset) {
bool Invalid = false;
- // De-duplication (Stage 2b): the global table holds only this module's kept
- // entries, so search over kept slots and translate each slot to its on-disk
- // local entry index when reading the offset.
+ // The table holds only this module's kept entries, so search over kept slots
+ // and map each back to its on-disk local index when reading the offset.
bool Dedup = !F->KeptSLocLocalIndex.empty();
unsigned NumSlots =
Dedup ? F->KeptSLocLocalIndex.size() : F->LocalNumSLocEntries;
@@ -2009,9 +2008,9 @@ bool ASTReader::ReadSLocEntry(int ID) {
};
ModuleFile *F = GlobalSLocEntryMap.find(-ID)->second;
- // De-duplication (Stage 2b): with entries skipped, the global slot
- // (ID - SLocEntryBaseID) is no longer the on-disk local index, so translate
- // it through the kept-index table when present.
+ // When entries have been skipped, the global slot (ID - SLocEntryBaseID) is
+ // no longer the on-disk local index, so map it back through the kept-index
+ // table.
unsigned LocalIndex = ID - F->SLocEntryBaseID;
if (!F->KeptSLocLocalIndex.empty()) {
assert(LocalIndex < F->KeptSLocLocalIndex.size() && "kept slot out of range");
@@ -2024,8 +2023,6 @@ bool ASTReader::ReadSLocEntry(int ID) {
}
BitstreamCursor &SLocEntryCursor = F->SLocEntryCursor;
- SourceLocation::UIntTy BaseOffset = F->SLocEntryBaseOffset;
- (void)BaseOffset;
++NumSLocEntriesRead;
Expected<llvm::BitstreamEntry> MaybeEntry = SLocEntryCursor.advance();
@@ -4307,17 +4304,16 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
F.SLocEntryOffsetsBase = Record[2] + F.SourceManagerBlockStartOffset;
unsigned N = F.LocalNumSLocEntries;
- // De-duplication (Stage 2b): scan this module's SLoc entries *before*
- // allocating, so we can recognize files already loaded by an earlier
- // module and reserve less address space for them.
+ // Scan this module's SLoc entries before allocating, so files already
+ // loaded by an earlier module can be recognized and reserve no space here.
SmallVector<uint32_t, 64> Offsets;
SmallVector<const FileEntry *, 64> Files;
bool Scanned = scanLoadedSLocEntries(F, Offsets, Files);
- // Classify each entry against the canonical map as it stands now, before
- // this module registers any of its own files, and store the decision per
- // entry. The build pass reads these flags, so a file that appears
- // multiple times in this module is classified consistently.
+ // Decide duplicates here, up front. The loop below registers each kept
+ // file as it goes, so checking against the map there would treat a file
+ // that appears more than once in this module as a duplicate of its own
+ // first occurrence.
auto entrySize = [&](unsigned I) -> uint64_t {
return (I + 1 < N ? Offsets[I + 1] : SLocSpaceSize) - Offsets[I];
};
@@ -4336,8 +4332,8 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
unsigned ReducedNumEntries = N - NumDupEntries;
SourceLocation::UIntTy ReducedSize = SLocSpaceSize - DupBytes;
- // Reserve the reduced amount (equals the full amount when nothing is
- // de-duplicated).
+ // Reserve the reduced amount (equal to the full amount when no file is
+ // reused).
std::tie(F.SLocEntryBaseID, F.SLocEntryBaseOffset) =
SourceMgr.AllocateLoadedSLocEntries(ReducedNumEntries, ReducedSize);
if (!F.SLocEntryBaseID) {
@@ -4348,9 +4344,8 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
}
if (NumDupEntries == 0) {
- // No de-duplication: one identity segment (== flat shift) and a linear
- // local->global ID mapping. Register each file as the canonical copy so
- // later modules can reuse it.
+ // Nothing reused: a single segment equal to the flat shift, and a
+ // linear ID mapping. Record each file so later modules can reuse it.
F.SLocRemap.push_back(
{/*LocalBegin=*/0, /*LocalEnd=*/~SourceLocation::UIntTy(0),
/*Delta=*/static_cast<int64_t>(F.SLocEntryBaseOffset) - 2});
@@ -4361,9 +4356,8 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
Files[I], F.SLocEntryBaseOffset + Offsets[I],
F.SLocEntryBaseID + (int)I);
} else {
- // De-duplication: build keep/redirect offset segments and the
- // local->global ID map. Skipped (duplicate) entries get no slot and no
- // address space; their references are redirected to the canonical copy.
+ // Build the offset segments and the ID map. A reused file gets no slot
+ // and no address space; its references point at the earlier copy.
F.LocalToGlobalID.assign(N, 0);
F.KeptSLocLocalIndex.reserve(ReducedNumEntries);
uint64_t DupBefore = 0;
>From 7951a03cf35447e377a2971054fa5f692de05741 Mon Sep 17 00:00:00 2001
From: Ayokunle Amodu <ayokunle321 at gmail.com>
Date: Mon, 6 Jul 2026 19:31:03 -0400
Subject: [PATCH 08/15] add bench scripts
---
dedup-test/bench/bench.sh | 124 +++++++++++++++++++++++++++++++++++
dedup-test/bench/timewrap.sh | 24 +++++++
2 files changed, 148 insertions(+)
create mode 100755 dedup-test/bench/bench.sh
create mode 100755 dedup-test/bench/timewrap.sh
diff --git a/dedup-test/bench/bench.sh b/dedup-test/bench/bench.sh
new file mode 100755
index 0000000000000..68a9667545866
--- /dev/null
+++ b/dedup-test/bench/bench.sh
@@ -0,0 +1,124 @@
+#!/usr/bin/env bash
+# Compare baseline (pre-patch) and patched clang on a modules-enabled build,
+# reporting peak RSS, CPU time, and loaded SourceLocation usage.
+#
+# The current checkout is the patched tree; the baseline comes from a detached
+# worktree at $BASELINE_REF, so the branch and index are left untouched. Both
+# clangs are built Release/no-asserts with the same flags.
+#
+# macOS (/usr/bin/time -l via timewrap.sh).
+set -euo pipefail
+
+REPO="$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)"
+BASELINE_REF="${BASELINE_REF:-main}"
+BASELINE_TREE="${BASELINE_TREE:-$REPO/../llvm-bench-baseline}"
+JOBS="${JOBS:-$(sysctl -n hw.ncpu 2>/dev/null || echo 4)}"
+RUNS="${RUNS:-5}"
+WORKLOAD_TARGET="${WORKLOAD_TARGET:-clangBasic}"
+OUT="${OUT:-$REPO/dedup-test/bench/out}"
+WRAP="$REPO/dedup-test/bench/timewrap.sh"
+chmod +x "$WRAP"
+mkdir -p "$OUT"
+
+echo "baseline=$BASELINE_REF jobs=$JOBS runs=$RUNS workload=$WORKLOAD_TARGET"
+
+# Baseline tree.
+if [ ! -d "$BASELINE_TREE" ]; then
+ git -C "$REPO" worktree add --detach "$BASELINE_TREE" "$BASELINE_REF"
+fi
+
+# Build a Release clang from a source tree.
+build_clang() { # <src> <tag>
+ local src="$1" tag="$2" bdir="$1/build-bench"
+ echo "building $tag clang"
+ cmake -G Ninja -S "$src/llvm" -B "$bdir" \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DLLVM_ENABLE_PROJECTS=clang \
+ -DLLVM_ENABLE_ASSERTIONS=OFF \
+ -DLLVM_TARGETS_TO_BUILD=Native >/dev/null
+ # Building 'clang' also produces the clang++/clang-cl symlinks.
+ ninja -C "$bdir" clang
+}
+build_clang "$REPO" patched
+build_clang "$BASELINE_TREE" baseline
+
+# Compile the workload with one clang, timing every invocation. The first build
+# populates the module cache; only subsequent clean rebuilds are recorded, so
+# the numbers reflect module loading rather than first-time module building.
+run_workload() { # <clang-tree> <tag>
+ local ctree="$1" tag="$2"
+ local cxx="$ctree/build-bench/bin/clang++" cc="$ctree/build-bench/bin/clang"
+ local wdir="$OUT/work-$tag" logdir="$OUT/log-$tag"
+ rm -rf "$wdir" "$logdir"; mkdir -p "$logdir"; : > "$logdir/all.txt"
+
+ cmake -G Ninja -S "$REPO/llvm" -B "$wdir" \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DLLVM_ENABLE_PROJECTS=clang \
+ -DLLVM_ENABLE_MODULES=ON \
+ -DLLVM_TARGETS_TO_BUILD=Native \
+ -DCMAKE_C_COMPILER="$cc" -DCMAKE_CXX_COMPILER="$cxx" \
+ -DCMAKE_C_COMPILER_LAUNCHER="$WRAP" \
+ -DCMAKE_CXX_COMPILER_LAUNCHER="$WRAP" >/dev/null
+
+ # Warm the module cache. Output streams to the terminal (and to warm.log);
+ # pipefail makes a compile failure here abort the run.
+ echo "[$tag] warming module cache"
+ ninja -C "$wdir" "$WORKLOAD_TARGET" 2>&1 | tee "$logdir/warm.log"
+
+ for r in $(seq 1 "$RUNS"); do
+ echo "[$tag] measured run $r/$RUNS"
+ ninja -C "$wdir" -t clean >/dev/null 2>&1
+ rm -f "$logdir"/*.m
+ BENCH_LOG_DIR="$logdir" \
+ ninja -C "$wdir" -j "$JOBS" "$WORKLOAD_TARGET" 2>&1 | tee "$logdir/run$r.log"
+ cat "$logdir"/*.m >> "$logdir/all.txt"
+ done
+}
+run_workload "$REPO" patched
+run_workload "$BASELINE_TREE" baseline
+PATCHED_LOG="$OUT/log-patched/all.txt"
+BASELINE_LOG="$OUT/log-baseline/all.txt"
+
+# Loaded SourceLocation usage on one representative TU, for each clang.
+sloc_stats() { # <tag>
+ local wdir="$OUT/work-$1" cmd
+ cmd=$(ninja -C "$wdir" -t commands "$WORKLOAD_TARGET" 2>/dev/null \
+ | grep -m1 -E 'clang\+\+.*\.cpp\.o') || return 0
+ eval "$cmd -Xclang -print-stats" 2>&1 \
+ | awk -v t="$1" '/loaded SLocEntries|de-duplicated/{print " ["t"] "$0}'
+}
+
+python3 - "$BASELINE_LOG" "$PATCHED_LOG" <<'PY'
+import sys, math, statistics as st
+def load(p):
+ rss=[]; cpu=[]
+ for ln in open(p):
+ a=ln.split()
+ if len(a)==3:
+ rss.append(float(a[0])/1048576.0) # bytes -> MB
+ cpu.append(float(a[1])+float(a[2])) # user+sys
+ return rss,cpu
+gm=lambda xs: math.exp(sum(map(math.log,xs))/len(xs)) if xs else 0.0
+br,bc=load(sys.argv[1]); pr,pc=load(sys.argv[2])
+def row(n,b,p,f):
+ d=(p-b)/b*100 if b else 0.0
+ print(f"{n:<32}{f(b):>12}{f(p):>12}{d:>+9.1f}%")
+mb=lambda x:f"{x:,.0f}"; s=lambda x:f"{x:.3f}"
+print(f"\n{'':<32}{'baseline':>12}{'patched':>12}{'delta':>10}")
+print("-"*66)
+print(f"compiles: {len(bc)} baseline / {len(pc)} patched")
+row("peak RSS, max cc1 (MB)", max(br), max(pr), mb)
+row("peak RSS, geomean/TU (MB)", gm(br), gm(pr), mb)
+row("CPU time, total (s)", sum(bc), sum(pc), s)
+row("CPU time, geomean/TU (s)", gm(bc), gm(pc), s)
+row("CPU time, median/TU (s)", st.median(bc), st.median(pc), s)
+PY
+
+echo
+echo "loaded SourceLocation usage (one TU):"
+sloc_stats baseline || true
+sloc_stats patched || true
+
+echo
+echo "logs: $OUT/log-{baseline,patched}/all.txt"
+echo "drop the baseline tree with: git worktree remove $BASELINE_TREE"
diff --git a/dedup-test/bench/timewrap.sh b/dedup-test/bench/timewrap.sh
new file mode 100755
index 0000000000000..02fa917f6d3b4
--- /dev/null
+++ b/dedup-test/bench/timewrap.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+# Compiler launcher. Runs the compile under `time -l` and, when BENCH_LOG_DIR
+# is set, records peak RSS (bytes) and user+sys time (seconds) for it there.
+# With BENCH_LOG_DIR unset (e.g. the warm build) it just runs the compile.
+set -u
+
+t=$(mktemp)
+/usr/bin/time -l "$@" 2>"$t"
+rc=$?
+
+rss=$(awk '/maximum resident set size/{print $1}' "$t")
+read -r usr sys < <(awk '/real/&&/user/&&/sys/{print $3, $5}' "$t")
+
+# Record only measured builds, and only for real compiles (link/archive steps
+# have no RSS line).
+if [ -n "${BENCH_LOG_DIR:-}" ] && [ -n "${rss:-}" ]; then
+ printf '%s %s %s\n' "$rss" "${usr:-0}" "${sys:-0}" \
+ > "$BENCH_LOG_DIR/$(date +%s)-$$-$RANDOM.m"
+fi
+
+# Forward the compiler's own stderr; drop the trailing resource block.
+awk '/real/&&/user/&&/sys/{stop=1} !stop{print}' "$t" >&2
+rm -f "$t"
+exit $rc
>From 10bce021112b205b14e0f97b794d0b6636d9f33a Mon Sep 17 00:00:00 2001
From: Ayokunle Amodu <ayokunle321 at gmail.com>
Date: Wed, 15 Jul 2026 13:14:02 +0000
Subject: [PATCH 09/15] cleaned up comments and variable names
---
.gitignore | 3 +
clang/include/clang/Basic/SourceManager.h | 37 +-----
clang/include/clang/Serialization/ASTReader.h | 62 ++++++++--
.../include/clang/Serialization/ModuleFile.h | 16 +--
clang/lib/Serialization/ASTReader.cpp | 109 ++++++++++++------
5 files changed, 145 insertions(+), 82 deletions(-)
diff --git a/.gitignore b/.gitignore
index a4382c9ea7390..1bceeef94e7e4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,6 +31,9 @@
# Nested build directory
/build*
+/ Test directory
+/dedup-test
+
#==============================================================================#
# Explicit files to ignore (only matches one).
#==============================================================================#
diff --git a/clang/include/clang/Basic/SourceManager.h b/clang/include/clang/Basic/SourceManager.h
index 4809a9dcbbd46..424de78725492 100644
--- a/clang/include/clang/Basic/SourceManager.h
+++ b/clang/include/clang/Basic/SourceManager.h
@@ -755,45 +755,18 @@ class SourceManager : public RefCountedBase<SourceManager> {
static const SourceLocation::UIntTy MaxLoadedOffset =
1ULL << (8 * sizeof(SourceLocation::UIntTy) - 1);
- // === Source location de-duplication ===
-public:
- /// Where a file's SLoc entry first landed in the loaded address space. A file
- /// shared by several modules is loaded once; later modules reuse this rather
- /// than allocating their own.
- struct LoadedFileLoc {
- SourceLocation::UIntTy Offset = 0; ///< global start offset
- int ID = 0; ///< global SLoc entry ID
- };
-
+ // Source location de-duplication. A file included into many modules is
+ // serialized into each of their PCMs. ASTReader keeps the first loaded copy
+ // and redirects later modules' references to it instead of allocating a
+ // duplicate SLoc range. These counters record the address space that reuse
+ // saved, for -print-stats.
private:
- /// The first loaded location of each file, keyed by the FileEntry identity
- /// Clang already uses to share file contents.
- llvm::DenseMap<const FileEntry *, LoadedFileLoc> CanonicalLoadedFiles;
/// Number of loaded file entries reused from an earlier module.
unsigned NumDuplicateLoadedFiles = 0;
/// Address-space bytes reused instead of allocated, for -print-stats.
uint64_t DuplicateLoadedBytes = 0;
public:
- /// Whether a file with this identity was already loaded into the address
- /// space by an earlier module (i.e. its SLoc entry would be a duplicate).
- bool isLoadedFileDuplicate(const FileEntry *FE) const {
- return FE && CanonicalLoadedFiles.contains(FE);
- }
-
- /// The canonical loaded location of a previously-loaded file, or null.
- const LoadedFileLoc *getCanonicalLoadedFile(const FileEntry *FE) const {
- auto It = CanonicalLoadedFiles.find(FE);
- return It == CanonicalLoadedFiles.end() ? nullptr : &It->second;
- }
-
- /// Record the canonical loaded location of a file the first time it loads.
- void registerCanonicalLoadedFile(const FileEntry *FE,
- SourceLocation::UIntTy Offset, int ID) {
- if (FE)
- CanonicalLoadedFiles.try_emplace(FE, LoadedFileLoc{Offset, ID});
- }
-
/// Record that a loaded file entry was reused from an earlier module.
void noteDuplicateLoadedFile(uint64_t Size) {
++NumDuplicateLoadedFiles;
diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h
index a9991091fc659..e1020e64fcca8 100644
--- a/clang/include/clang/Serialization/ASTReader.h
+++ b/clang/include/clang/Serialization/ASTReader.h
@@ -2399,12 +2399,49 @@ class ASTReader : public ExternalPreprocessorSource,
llvm::Expected<SourceLocation::UIntTy> readSLocOffset(ModuleFile *F,
unsigned Index);
+ /// Identity of an input file, taken from serialized metadata without touching
+ /// the filesystem. It uses the stored name, size, and modification time that
+ /// Clang's own input-file staleness check relies on. An empty Name marks a
+ /// non-file entry (a buffer or expansion), which never deduplicates.
+ struct SLocFileIdentity {
+ StringRef Name;
+ off_t Size = 0;
+ time_t Time = 0;
+ };
+
+ /// Where a file's SLoc entry first landed in the loaded address space, kept
+ /// with the identity fields used to confirm a later module's same-named entry
+ /// really is the same file.
+ struct PrimaryLoadedFileLoc {
+ SourceLocation::UIntTy Offset = 0; ///< global start offset
+ int ID = 0; ///< global SLoc entry ID
+ off_t Size = 0;
+ time_t Time = 0;
+ };
+
+ /// Files already loaded into the loaded SLoc address space, keyed by stored
+ /// name. Lets a later module reuse an earlier module's copy instead of
+ /// allocating a duplicate range. The key is serialized metadata, so no input
+ /// file is resolved or stat'd at load time.
+ llvm::StringMap<PrimaryLoadedFileLoc> PrimaryLoadedFiles;
+
+ /// The location of a previously-loaded file matching \p Id (same name, size,
+ /// and time), or null if none has been loaded.
+ const PrimaryLoadedFileLoc *
+ getPrimaryLoadedFile(const SLocFileIdentity &Id) const;
+
+ /// Record the location of a file the first time it loads. \p Id must name a
+ /// file entry (non-empty Name). Later duplicates are ignored.
+ void registerPrimaryLoadedFile(const SLocFileIdentity &Id,
+ SourceLocation::UIntTy Offset, int ID);
+
/// Read \p F's SLoc entry records without materializing them, filling
/// \p Offsets[i] with each entry's local offset and \p Files[i] with its
- /// FileEntry (null for non-file entries). Returns false on a malformed record.
- bool scanLoadedSLocEntries(ModuleFile &F,
- SmallVectorImpl<uint32_t> &Offsets,
- SmallVectorImpl<const FileEntry *> &Files);
+ /// file identity (empty Name for non-file entries). File identity comes from
+ /// serialized metadata only, with no input file resolved on disk. Returns
+ /// false on a malformed record.
+ bool scanLoadedSLocEntries(ModuleFile &F, SmallVectorImpl<uint32_t> &Offsets,
+ SmallVectorImpl<SLocFileIdentity> &Files);
/// Map a local SLoc entry offset (as stored in the entry record) to its
/// global start offset. This is (SLocEntryBaseOffset + LocalOffset) unless a
@@ -2514,13 +2551,24 @@ class ASTReader : public ExternalPreprocessorSource,
SourceLocation::UIntTy Raw = Loc.getRawEncoding();
SourceLocation::UIntTy MacroBit = Raw & SourceLocation::MacroIDBit;
SourceLocation::UIntTy Low = Raw & ~SourceLocation::MacroIDBit;
- for (const auto &Seg : ModuleFile.SLocRemap)
- if (Low >= Seg.LocalBegin && Low < Seg.LocalEnd)
+ // The list is sorted by LocalBegin and its segments are contiguous, so
+ // the covering segment is the last one whose LocalBegin is <= Low.
+ auto It = llvm::upper_bound(
+ ModuleFile.SLocRemap, Low,
+ [](SourceLocation::UIntTy V,
+ const serialization::ModuleFile::SLocRemapSegment &S) {
+ return V < S.LocalBegin;
+ });
+ if (It != ModuleFile.SLocRemap.begin()) {
+ const auto &Seg = *std::prev(It);
+ if (Low < Seg.LocalEnd)
return SourceLocation::getFromRawEncoding(
(static_cast<SourceLocation::UIntTy>(static_cast<int64_t>(Low) +
Seg.Delta)) |
MacroBit);
- // No segment matched (shouldn't happen): fall through to the flat shift.
+ }
+ // No segment matched. This shouldn't happen, so fall through to the
+ // flat shift below.
}
return Loc.getLocWithOffset(ModuleFile.SLocEntryBaseOffset - 2);
diff --git a/clang/include/clang/Serialization/ModuleFile.h b/clang/include/clang/Serialization/ModuleFile.h
index a985c17904aa6..76cefc2280936 100644
--- a/clang/include/clang/Serialization/ModuleFile.h
+++ b/clang/include/clang/Serialization/ModuleFile.h
@@ -348,8 +348,8 @@ class ModuleFile {
// === Source location de-duplication ===
- /// One segment of the local-to-global source location map: a local raw
- /// location L in [LocalBegin, LocalEnd) maps to the global location L + Delta.
+ /// One segment of the local-to-global source location map. A local raw
+ /// location L in [LocalBegin, LocalEnd) maps to global location L + Delta.
struct SLocRemapSegment {
SourceLocation::UIntTy LocalBegin;
SourceLocation::UIntTy LocalEnd;
@@ -357,15 +357,15 @@ class ModuleFile {
};
/// The local-to-global source location map for this module, sorted by
- /// LocalBegin. A module whose files are all distinct has a single segment
- /// equivalent to the flat shift by (SLocEntryBaseOffset - 2); when a file is
- /// reused from an earlier module, extra segments redirect that file's
- /// locations into the earlier module. Empty for a module that is not loaded
- /// through this path, in which case the flat shift is used directly.
+ /// LocalBegin. When a module's files are all distinct it holds a single
+ /// segment equivalent to the flat shift by (SLocEntryBaseOffset - 2). When a
+ /// file is reused from an earlier module, extra segments redirect that file's
+ /// locations into the earlier module. Empty when this path did not run, in
+ /// which case the flat shift is used directly.
llvm::SmallVector<SLocRemapSegment, 4> SLocRemap;
/// Maps a local SLoc entry index to its global SLoc entry ID. A kept entry
- /// maps to its own ID; a file reused from an earlier module maps to that
+ /// maps to its own ID. A file reused from an earlier module maps to that
/// module's copy. Empty when no file was reused (the global ID is then
/// SLocEntryBaseID + index).
std::vector<int> LocalToGlobalID;
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index f2e69bd42d1cb..5df770034e7db 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -1815,18 +1815,40 @@ llvm::Error ASTReader::ReadSourceManagerBlock(ModuleFile &F) {
}
}
+const ASTReader::PrimaryLoadedFileLoc *
+ASTReader::getPrimaryLoadedFile(const SLocFileIdentity &Id) const {
+ assert(!Id.Name.empty() && "querying a non-file entry");
+ auto It = PrimaryLoadedFiles.find(Id.Name);
+ if (It == PrimaryLoadedFiles.end())
+ return nullptr;
+ const PrimaryLoadedFileLoc &Primary = It->second;
+ // A matching name but different size or time is a different file, e.g. two
+ // modules built against different versions of the same path. Don't merge.
+ if (Primary.Size != Id.Size || Primary.Time != Id.Time)
+ return nullptr;
+ return &Primary;
+}
+
+void ASTReader::registerPrimaryLoadedFile(const SLocFileIdentity &Id,
+ SourceLocation::UIntTy Offset,
+ int ID) {
+ assert(!Id.Name.empty() && "registering a non-file entry");
+ PrimaryLoadedFiles.try_emplace(
+ Id.Name, PrimaryLoadedFileLoc{Offset, ID, Id.Size, Id.Time});
+}
+
bool ASTReader::scanLoadedSLocEntries(
ModuleFile &F, SmallVectorImpl<uint32_t> &Offsets,
- SmallVectorImpl<const FileEntry *> &Files) {
+ SmallVectorImpl<SLocFileIdentity> &Files) {
unsigned N = F.LocalNumSLocEntries;
Offsets.assign(N, 0);
- Files.assign(N, nullptr);
+ Files.assign(N, SLocFileIdentity{});
BitstreamCursor &Cursor = F.SLocEntryCursor;
SavedStreamPosition SavedPosition(Cursor);
for (unsigned I = 0; I != N; ++I) {
- if (llvm::Error Err = Cursor.JumpToBit(F.SLocEntryOffsetsBase +
- F.SLocEntryOffsets[I])) {
+ if (llvm::Error Err =
+ Cursor.JumpToBit(F.SLocEntryOffsetsBase + F.SLocEntryOffsets[I])) {
consumeError(std::move(Err));
return false;
}
@@ -1839,16 +1861,22 @@ bool ASTReader::scanLoadedSLocEntries(
return false;
RecordData Record;
- StringRef Blob;
- Expected<unsigned> Code = Cursor.readRecord(Entry->ID, Record, &Blob);
+ Expected<unsigned> Code = Cursor.readRecord(Entry->ID, Record);
if (!Code) {
consumeError(Code.takeError());
return false;
}
Offsets[I] = (uint32_t)Record[0];
- if (Code.get() == SM_SLOC_FILE_ENTRY)
- if (OptionalFileEntryRef File = getInputFile(F, Record[4]).getFile())
- Files[I] = &File->getFileEntry();
+ if (Code.get() == SM_SLOC_FILE_ENTRY) {
+ // Identify the file from serialized metadata only. Resolving it on disk
+ // here (getInputFile) would stat and open every input file of every
+ // module at load, which is prohibitive. The stored name, size, and time
+ // are the identity Clang's own staleness check already uses.
+ InputFileInfo IFI = getInputFileInfo(F, Record[4]);
+ if (IFI.isValid())
+ Files[I] = SLocFileIdentity{IFI.UnresolvedImportedFilename,
+ IFI.StoredSize, IFI.StoredTime};
+ }
}
return true;
}
@@ -1859,12 +1887,22 @@ ASTReader::remapSLocEntryOffset(ModuleFile &F, uint32_t LocalOffset) const {
// are reserved). Find the segment covering it and apply that segment's delta.
if (!F.SLocRemap.empty()) {
SourceLocation::UIntTy Low = LocalOffset + 2;
- for (const auto &Seg : F.SLocRemap)
- if (Low >= Seg.LocalBegin && Low < Seg.LocalEnd)
+ // The list is sorted by LocalBegin and its segments are contiguous, so the
+ // covering segment is the last one whose LocalBegin is <= Low.
+ auto It = llvm::upper_bound(
+ F.SLocRemap, Low,
+ [](SourceLocation::UIntTy V,
+ const serialization::ModuleFile::SLocRemapSegment &S) {
+ return V < S.LocalBegin;
+ });
+ if (It != F.SLocRemap.begin()) {
+ const auto &Seg = *std::prev(It);
+ if (Low < Seg.LocalEnd)
return static_cast<SourceLocation::UIntTy>(static_cast<int64_t>(Low) +
Seg.Delta);
+ }
}
- // No remap (or no segment matched): original flat shift.
+ // No remap, or no segment matched. Use the original flat shift.
return F.SLocEntryBaseOffset + LocalOffset;
}
@@ -2013,7 +2051,8 @@ bool ASTReader::ReadSLocEntry(int ID) {
// table.
unsigned LocalIndex = ID - F->SLocEntryBaseID;
if (!F->KeptSLocLocalIndex.empty()) {
- assert(LocalIndex < F->KeptSLocLocalIndex.size() && "kept slot out of range");
+ assert(LocalIndex < F->KeptSLocLocalIndex.size() &&
+ "kept slot out of range");
LocalIndex = F->KeptSLocLocalIndex[LocalIndex];
}
if (llvm::Error Err = F->SLocEntryCursor.JumpToBit(
@@ -2113,9 +2152,9 @@ bool ASTReader::ReadSLocEntry(int ID) {
auto Buffer = ReadBuffer(SLocEntryCursor, Name);
if (!Buffer)
return true;
- FileID FID = SourceMgr.createFileID(std::move(Buffer), FileCharacter, ID,
- remapSLocEntryOffset(*F, Offset),
- IncludeLoc);
+ FileID FID =
+ SourceMgr.createFileID(std::move(Buffer), FileCharacter, ID,
+ remapSLocEntryOffset(*F, Offset), IncludeLoc);
if (Record[3]) {
auto &FileInfo = SourceMgr.getSLocEntry(FID).getFile();
FileInfo.setHasLineDirectives();
@@ -4305,9 +4344,10 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
unsigned N = F.LocalNumSLocEntries;
// Scan this module's SLoc entries before allocating, so files already
- // loaded by an earlier module can be recognized and reserve no space here.
+ // loaded by an earlier module can be recognized and reserve no space
+ // here.
SmallVector<uint32_t, 64> Offsets;
- SmallVector<const FileEntry *, 64> Files;
+ SmallVector<SLocFileIdentity, 64> Files;
bool Scanned = scanLoadedSLocEntries(F, Offsets, Files);
// Decide duplicates here, up front. The loop below registers each kept
@@ -4322,7 +4362,7 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
uint64_t DupBytes = 0;
if (Scanned)
for (unsigned I = 0; I != N; ++I)
- if (SourceMgr.isLoadedFileDuplicate(Files[I])) {
+ if (!Files[I].Name.empty() && getPrimaryLoadedFile(Files[I])) {
IsDup[I] = true;
uint64_t Size = entrySize(I);
SourceMgr.noteDuplicateLoadedFile(Size);
@@ -4344,20 +4384,20 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
}
if (NumDupEntries == 0) {
- // Nothing reused: a single segment equal to the flat shift, and a
+ // Nothing reused. A single segment equal to the flat shift, plus a
// linear ID mapping. Record each file so later modules can reuse it.
F.SLocRemap.push_back(
{/*LocalBegin=*/0, /*LocalEnd=*/~SourceLocation::UIntTy(0),
/*Delta=*/static_cast<int64_t>(F.SLocEntryBaseOffset) - 2});
if (Scanned)
for (unsigned I = 0; I != N; ++I)
- if (Files[I])
- SourceMgr.registerCanonicalLoadedFile(
- Files[I], F.SLocEntryBaseOffset + Offsets[I],
- F.SLocEntryBaseID + (int)I);
+ if (!Files[I].Name.empty())
+ registerPrimaryLoadedFile(Files[I],
+ F.SLocEntryBaseOffset + Offsets[I],
+ F.SLocEntryBaseID + (int)I);
} else {
// Build the offset segments and the ID map. A reused file gets no slot
- // and no address space; its references point at the earlier copy.
+ // and no address space, and its references point at the earlier copy.
F.LocalToGlobalID.assign(N, 0);
F.KeptSLocLocalIndex.reserve(ReducedNumEntries);
uint64_t DupBefore = 0;
@@ -4366,20 +4406,19 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
SourceLocation::UIntTy LowStart = Offsets[I] + 2;
SourceLocation::UIntTy LowEnd =
(I + 1 < N ? Offsets[I + 1] : SLocSpaceSize) + 2;
- const FileEntry *FE = Files[I];
+ const SLocFileIdentity &Id = Files[I];
if (IsDup[I]) {
// Redirect this file's locations into the module that first loaded
- // it; reserve nothing here.
- const SourceManager::LoadedFileLoc *Canon =
- SourceMgr.getCanonicalLoadedFile(FE);
+ // it and reserve nothing here.
+ const PrimaryLoadedFileLoc *Primary = getPrimaryLoadedFile(Id);
F.SLocRemap.push_back({LowStart, LowEnd,
- static_cast<int64_t>(Canon->Offset) -
+ static_cast<int64_t>(Primary->Offset) -
static_cast<int64_t>(LowStart)});
- F.LocalToGlobalID[I] = Canon->ID;
+ F.LocalToGlobalID[I] = Primary->ID;
DupBefore += LowEnd - LowStart;
} else {
- // Keep: lands in this module's block, shifted down to close gaps
- // left by skipped duplicates before it.
+ // Kept entry. It lands in this module's block, shifted down to
+ // close gaps left by skipped duplicates before it.
int GlobalID = F.SLocEntryBaseID + (int)KeptCount;
SourceLocation::UIntTy GlobalStart =
static_cast<SourceLocation::UIntTy>(F.SLocEntryBaseOffset +
@@ -4389,8 +4428,8 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
static_cast<int64_t>(LowStart)});
F.LocalToGlobalID[I] = GlobalID;
F.KeptSLocLocalIndex.push_back(I);
- if (FE)
- SourceMgr.registerCanonicalLoadedFile(FE, GlobalStart, GlobalID);
+ if (!Id.Name.empty())
+ registerPrimaryLoadedFile(Id, GlobalStart, GlobalID);
++KeptCount;
}
}
>From cea3ba0e75e4c7fd3034cd2a32773537c6efd71f Mon Sep 17 00:00:00 2001
From: Ayokunle Amodu <ayokunle321 at gmail.com>
Date: Wed, 15 Jul 2026 13:16:09 +0000
Subject: [PATCH 10/15] Stop tracking dedup-test/
---
dedup-test/a.h | 5 -
dedup-test/b.h | 5 -
dedup-test/bench/bench.sh | 124 -----------
dedup-test/bench/timewrap.sh | 24 ---
dedup-test/module.modulemap | 2 -
dedup-test/shared.h | 403 -----------------------------------
dedup-test/use.cpp | 3 -
dedup-test/use1.cpp | 2 -
dedup-test/use_err.cpp | 14 --
dedup-test/use_err_rev.cpp | 10 -
10 files changed, 592 deletions(-)
delete mode 100644 dedup-test/a.h
delete mode 100644 dedup-test/b.h
delete mode 100755 dedup-test/bench/bench.sh
delete mode 100755 dedup-test/bench/timewrap.sh
delete mode 100644 dedup-test/module.modulemap
delete mode 100644 dedup-test/shared.h
delete mode 100644 dedup-test/use.cpp
delete mode 100644 dedup-test/use1.cpp
delete mode 100644 dedup-test/use_err.cpp
delete mode 100644 dedup-test/use_err_rev.cpp
diff --git a/dedup-test/a.h b/dedup-test/a.h
deleted file mode 100644
index 1fe7fc27db549..0000000000000
--- a/dedup-test/a.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifndef A_H
-#define A_H
-#include "shared.h"
-inline int a_entry(int x) { return shared_fn_0(x); }
-#endif
diff --git a/dedup-test/b.h b/dedup-test/b.h
deleted file mode 100644
index 85839261fc602..0000000000000
--- a/dedup-test/b.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifndef B_H
-#define B_H
-#include "shared.h"
-inline int b_entry(int x) { return shared_fn_1(x); }
-#endif
diff --git a/dedup-test/bench/bench.sh b/dedup-test/bench/bench.sh
deleted file mode 100755
index 68a9667545866..0000000000000
--- a/dedup-test/bench/bench.sh
+++ /dev/null
@@ -1,124 +0,0 @@
-#!/usr/bin/env bash
-# Compare baseline (pre-patch) and patched clang on a modules-enabled build,
-# reporting peak RSS, CPU time, and loaded SourceLocation usage.
-#
-# The current checkout is the patched tree; the baseline comes from a detached
-# worktree at $BASELINE_REF, so the branch and index are left untouched. Both
-# clangs are built Release/no-asserts with the same flags.
-#
-# macOS (/usr/bin/time -l via timewrap.sh).
-set -euo pipefail
-
-REPO="$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)"
-BASELINE_REF="${BASELINE_REF:-main}"
-BASELINE_TREE="${BASELINE_TREE:-$REPO/../llvm-bench-baseline}"
-JOBS="${JOBS:-$(sysctl -n hw.ncpu 2>/dev/null || echo 4)}"
-RUNS="${RUNS:-5}"
-WORKLOAD_TARGET="${WORKLOAD_TARGET:-clangBasic}"
-OUT="${OUT:-$REPO/dedup-test/bench/out}"
-WRAP="$REPO/dedup-test/bench/timewrap.sh"
-chmod +x "$WRAP"
-mkdir -p "$OUT"
-
-echo "baseline=$BASELINE_REF jobs=$JOBS runs=$RUNS workload=$WORKLOAD_TARGET"
-
-# Baseline tree.
-if [ ! -d "$BASELINE_TREE" ]; then
- git -C "$REPO" worktree add --detach "$BASELINE_TREE" "$BASELINE_REF"
-fi
-
-# Build a Release clang from a source tree.
-build_clang() { # <src> <tag>
- local src="$1" tag="$2" bdir="$1/build-bench"
- echo "building $tag clang"
- cmake -G Ninja -S "$src/llvm" -B "$bdir" \
- -DCMAKE_BUILD_TYPE=Release \
- -DLLVM_ENABLE_PROJECTS=clang \
- -DLLVM_ENABLE_ASSERTIONS=OFF \
- -DLLVM_TARGETS_TO_BUILD=Native >/dev/null
- # Building 'clang' also produces the clang++/clang-cl symlinks.
- ninja -C "$bdir" clang
-}
-build_clang "$REPO" patched
-build_clang "$BASELINE_TREE" baseline
-
-# Compile the workload with one clang, timing every invocation. The first build
-# populates the module cache; only subsequent clean rebuilds are recorded, so
-# the numbers reflect module loading rather than first-time module building.
-run_workload() { # <clang-tree> <tag>
- local ctree="$1" tag="$2"
- local cxx="$ctree/build-bench/bin/clang++" cc="$ctree/build-bench/bin/clang"
- local wdir="$OUT/work-$tag" logdir="$OUT/log-$tag"
- rm -rf "$wdir" "$logdir"; mkdir -p "$logdir"; : > "$logdir/all.txt"
-
- cmake -G Ninja -S "$REPO/llvm" -B "$wdir" \
- -DCMAKE_BUILD_TYPE=Release \
- -DLLVM_ENABLE_PROJECTS=clang \
- -DLLVM_ENABLE_MODULES=ON \
- -DLLVM_TARGETS_TO_BUILD=Native \
- -DCMAKE_C_COMPILER="$cc" -DCMAKE_CXX_COMPILER="$cxx" \
- -DCMAKE_C_COMPILER_LAUNCHER="$WRAP" \
- -DCMAKE_CXX_COMPILER_LAUNCHER="$WRAP" >/dev/null
-
- # Warm the module cache. Output streams to the terminal (and to warm.log);
- # pipefail makes a compile failure here abort the run.
- echo "[$tag] warming module cache"
- ninja -C "$wdir" "$WORKLOAD_TARGET" 2>&1 | tee "$logdir/warm.log"
-
- for r in $(seq 1 "$RUNS"); do
- echo "[$tag] measured run $r/$RUNS"
- ninja -C "$wdir" -t clean >/dev/null 2>&1
- rm -f "$logdir"/*.m
- BENCH_LOG_DIR="$logdir" \
- ninja -C "$wdir" -j "$JOBS" "$WORKLOAD_TARGET" 2>&1 | tee "$logdir/run$r.log"
- cat "$logdir"/*.m >> "$logdir/all.txt"
- done
-}
-run_workload "$REPO" patched
-run_workload "$BASELINE_TREE" baseline
-PATCHED_LOG="$OUT/log-patched/all.txt"
-BASELINE_LOG="$OUT/log-baseline/all.txt"
-
-# Loaded SourceLocation usage on one representative TU, for each clang.
-sloc_stats() { # <tag>
- local wdir="$OUT/work-$1" cmd
- cmd=$(ninja -C "$wdir" -t commands "$WORKLOAD_TARGET" 2>/dev/null \
- | grep -m1 -E 'clang\+\+.*\.cpp\.o') || return 0
- eval "$cmd -Xclang -print-stats" 2>&1 \
- | awk -v t="$1" '/loaded SLocEntries|de-duplicated/{print " ["t"] "$0}'
-}
-
-python3 - "$BASELINE_LOG" "$PATCHED_LOG" <<'PY'
-import sys, math, statistics as st
-def load(p):
- rss=[]; cpu=[]
- for ln in open(p):
- a=ln.split()
- if len(a)==3:
- rss.append(float(a[0])/1048576.0) # bytes -> MB
- cpu.append(float(a[1])+float(a[2])) # user+sys
- return rss,cpu
-gm=lambda xs: math.exp(sum(map(math.log,xs))/len(xs)) if xs else 0.0
-br,bc=load(sys.argv[1]); pr,pc=load(sys.argv[2])
-def row(n,b,p,f):
- d=(p-b)/b*100 if b else 0.0
- print(f"{n:<32}{f(b):>12}{f(p):>12}{d:>+9.1f}%")
-mb=lambda x:f"{x:,.0f}"; s=lambda x:f"{x:.3f}"
-print(f"\n{'':<32}{'baseline':>12}{'patched':>12}{'delta':>10}")
-print("-"*66)
-print(f"compiles: {len(bc)} baseline / {len(pc)} patched")
-row("peak RSS, max cc1 (MB)", max(br), max(pr), mb)
-row("peak RSS, geomean/TU (MB)", gm(br), gm(pr), mb)
-row("CPU time, total (s)", sum(bc), sum(pc), s)
-row("CPU time, geomean/TU (s)", gm(bc), gm(pc), s)
-row("CPU time, median/TU (s)", st.median(bc), st.median(pc), s)
-PY
-
-echo
-echo "loaded SourceLocation usage (one TU):"
-sloc_stats baseline || true
-sloc_stats patched || true
-
-echo
-echo "logs: $OUT/log-{baseline,patched}/all.txt"
-echo "drop the baseline tree with: git worktree remove $BASELINE_TREE"
diff --git a/dedup-test/bench/timewrap.sh b/dedup-test/bench/timewrap.sh
deleted file mode 100755
index 02fa917f6d3b4..0000000000000
--- a/dedup-test/bench/timewrap.sh
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/usr/bin/env bash
-# Compiler launcher. Runs the compile under `time -l` and, when BENCH_LOG_DIR
-# is set, records peak RSS (bytes) and user+sys time (seconds) for it there.
-# With BENCH_LOG_DIR unset (e.g. the warm build) it just runs the compile.
-set -u
-
-t=$(mktemp)
-/usr/bin/time -l "$@" 2>"$t"
-rc=$?
-
-rss=$(awk '/maximum resident set size/{print $1}' "$t")
-read -r usr sys < <(awk '/real/&&/user/&&/sys/{print $3, $5}' "$t")
-
-# Record only measured builds, and only for real compiles (link/archive steps
-# have no RSS line).
-if [ -n "${BENCH_LOG_DIR:-}" ] && [ -n "${rss:-}" ]; then
- printf '%s %s %s\n' "$rss" "${usr:-0}" "${sys:-0}" \
- > "$BENCH_LOG_DIR/$(date +%s)-$$-$RANDOM.m"
-fi
-
-# Forward the compiler's own stderr; drop the trailing resource block.
-awk '/real/&&/user/&&/sys/{stop=1} !stop{print}' "$t" >&2
-rm -f "$t"
-exit $rc
diff --git a/dedup-test/module.modulemap b/dedup-test/module.modulemap
deleted file mode 100644
index 2da1c03a22211..0000000000000
--- a/dedup-test/module.modulemap
+++ /dev/null
@@ -1,2 +0,0 @@
-module A { header "a.h" export * }
-module B { header "b.h" export * }
diff --git a/dedup-test/shared.h b/dedup-test/shared.h
deleted file mode 100644
index 3ac57a45355f9..0000000000000
--- a/dedup-test/shared.h
+++ /dev/null
@@ -1,403 +0,0 @@
-#ifndef SHARED_H
-#define SHARED_H
-inline int shared_fn_0(int x) { return x + 0; }
-inline int shared_fn_1(int x) { return x + 1; }
-inline int shared_fn_2(int x) { return x + 2; }
-inline int shared_fn_3(int x) { return x + 3; }
-inline int shared_fn_4(int x) { return x + 4; }
-inline int shared_fn_5(int x) { return x + 5; }
-inline int shared_fn_6(int x) { return x + 6; }
-inline int shared_fn_7(int x) { return x + 7; }
-inline int shared_fn_8(int x) { return x + 8; }
-inline int shared_fn_9(int x) { return x + 9; }
-inline int shared_fn_10(int x) { return x + 10; }
-inline int shared_fn_11(int x) { return x + 11; }
-inline int shared_fn_12(int x) { return x + 12; }
-inline int shared_fn_13(int x) { return x + 13; }
-inline int shared_fn_14(int x) { return x + 14; }
-inline int shared_fn_15(int x) { return x + 15; }
-inline int shared_fn_16(int x) { return x + 16; }
-inline int shared_fn_17(int x) { return x + 17; }
-inline int shared_fn_18(int x) { return x + 18; }
-inline int shared_fn_19(int x) { return x + 19; }
-inline int shared_fn_20(int x) { return x + 20; }
-inline int shared_fn_21(int x) { return x + 21; }
-inline int shared_fn_22(int x) { return x + 22; }
-inline int shared_fn_23(int x) { return x + 23; }
-inline int shared_fn_24(int x) { return x + 24; }
-inline int shared_fn_25(int x) { return x + 25; }
-inline int shared_fn_26(int x) { return x + 26; }
-inline int shared_fn_27(int x) { return x + 27; }
-inline int shared_fn_28(int x) { return x + 28; }
-inline int shared_fn_29(int x) { return x + 29; }
-inline int shared_fn_30(int x) { return x + 30; }
-inline int shared_fn_31(int x) { return x + 31; }
-inline int shared_fn_32(int x) { return x + 32; }
-inline int shared_fn_33(int x) { return x + 33; }
-inline int shared_fn_34(int x) { return x + 34; }
-inline int shared_fn_35(int x) { return x + 35; }
-inline int shared_fn_36(int x) { return x + 36; }
-inline int shared_fn_37(int x) { return x + 37; }
-inline int shared_fn_38(int x) { return x + 38; }
-inline int shared_fn_39(int x) { return x + 39; }
-inline int shared_fn_40(int x) { return x + 40; }
-inline int shared_fn_41(int x) { return x + 41; }
-inline int shared_fn_42(int x) { return x + 42; }
-inline int shared_fn_43(int x) { return x + 43; }
-inline int shared_fn_44(int x) { return x + 44; }
-inline int shared_fn_45(int x) { return x + 45; }
-inline int shared_fn_46(int x) { return x + 46; }
-inline int shared_fn_47(int x) { return x + 47; }
-inline int shared_fn_48(int x) { return x + 48; }
-inline int shared_fn_49(int x) { return x + 49; }
-inline int shared_fn_50(int x) { return x + 50; }
-inline int shared_fn_51(int x) { return x + 51; }
-inline int shared_fn_52(int x) { return x + 52; }
-inline int shared_fn_53(int x) { return x + 53; }
-inline int shared_fn_54(int x) { return x + 54; }
-inline int shared_fn_55(int x) { return x + 55; }
-inline int shared_fn_56(int x) { return x + 56; }
-inline int shared_fn_57(int x) { return x + 57; }
-inline int shared_fn_58(int x) { return x + 58; }
-inline int shared_fn_59(int x) { return x + 59; }
-inline int shared_fn_60(int x) { return x + 60; }
-inline int shared_fn_61(int x) { return x + 61; }
-inline int shared_fn_62(int x) { return x + 62; }
-inline int shared_fn_63(int x) { return x + 63; }
-inline int shared_fn_64(int x) { return x + 64; }
-inline int shared_fn_65(int x) { return x + 65; }
-inline int shared_fn_66(int x) { return x + 66; }
-inline int shared_fn_67(int x) { return x + 67; }
-inline int shared_fn_68(int x) { return x + 68; }
-inline int shared_fn_69(int x) { return x + 69; }
-inline int shared_fn_70(int x) { return x + 70; }
-inline int shared_fn_71(int x) { return x + 71; }
-inline int shared_fn_72(int x) { return x + 72; }
-inline int shared_fn_73(int x) { return x + 73; }
-inline int shared_fn_74(int x) { return x + 74; }
-inline int shared_fn_75(int x) { return x + 75; }
-inline int shared_fn_76(int x) { return x + 76; }
-inline int shared_fn_77(int x) { return x + 77; }
-inline int shared_fn_78(int x) { return x + 78; }
-inline int shared_fn_79(int x) { return x + 79; }
-inline int shared_fn_80(int x) { return x + 80; }
-inline int shared_fn_81(int x) { return x + 81; }
-inline int shared_fn_82(int x) { return x + 82; }
-inline int shared_fn_83(int x) { return x + 83; }
-inline int shared_fn_84(int x) { return x + 84; }
-inline int shared_fn_85(int x) { return x + 85; }
-inline int shared_fn_86(int x) { return x + 86; }
-inline int shared_fn_87(int x) { return x + 87; }
-inline int shared_fn_88(int x) { return x + 88; }
-inline int shared_fn_89(int x) { return x + 89; }
-inline int shared_fn_90(int x) { return x + 90; }
-inline int shared_fn_91(int x) { return x + 91; }
-inline int shared_fn_92(int x) { return x + 92; }
-inline int shared_fn_93(int x) { return x + 93; }
-inline int shared_fn_94(int x) { return x + 94; }
-inline int shared_fn_95(int x) { return x + 95; }
-inline int shared_fn_96(int x) { return x + 96; }
-inline int shared_fn_97(int x) { return x + 97; }
-inline int shared_fn_98(int x) { return x + 98; }
-inline int shared_fn_99(int x) { return x + 99; }
-inline int shared_fn_100(int x) { return x + 100; }
-inline int shared_fn_101(int x) { return x + 101; }
-inline int shared_fn_102(int x) { return x + 102; }
-inline int shared_fn_103(int x) { return x + 103; }
-inline int shared_fn_104(int x) { return x + 104; }
-inline int shared_fn_105(int x) { return x + 105; }
-inline int shared_fn_106(int x) { return x + 106; }
-inline int shared_fn_107(int x) { return x + 107; }
-inline int shared_fn_108(int x) { return x + 108; }
-inline int shared_fn_109(int x) { return x + 109; }
-inline int shared_fn_110(int x) { return x + 110; }
-inline int shared_fn_111(int x) { return x + 111; }
-inline int shared_fn_112(int x) { return x + 112; }
-inline int shared_fn_113(int x) { return x + 113; }
-inline int shared_fn_114(int x) { return x + 114; }
-inline int shared_fn_115(int x) { return x + 115; }
-inline int shared_fn_116(int x) { return x + 116; }
-inline int shared_fn_117(int x) { return x + 117; }
-inline int shared_fn_118(int x) { return x + 118; }
-inline int shared_fn_119(int x) { return x + 119; }
-inline int shared_fn_120(int x) { return x + 120; }
-inline int shared_fn_121(int x) { return x + 121; }
-inline int shared_fn_122(int x) { return x + 122; }
-inline int shared_fn_123(int x) { return x + 123; }
-inline int shared_fn_124(int x) { return x + 124; }
-inline int shared_fn_125(int x) { return x + 125; }
-inline int shared_fn_126(int x) { return x + 126; }
-inline int shared_fn_127(int x) { return x + 127; }
-inline int shared_fn_128(int x) { return x + 128; }
-inline int shared_fn_129(int x) { return x + 129; }
-inline int shared_fn_130(int x) { return x + 130; }
-inline int shared_fn_131(int x) { return x + 131; }
-inline int shared_fn_132(int x) { return x + 132; }
-inline int shared_fn_133(int x) { return x + 133; }
-inline int shared_fn_134(int x) { return x + 134; }
-inline int shared_fn_135(int x) { return x + 135; }
-inline int shared_fn_136(int x) { return x + 136; }
-inline int shared_fn_137(int x) { return x + 137; }
-inline int shared_fn_138(int x) { return x + 138; }
-inline int shared_fn_139(int x) { return x + 139; }
-inline int shared_fn_140(int x) { return x + 140; }
-inline int shared_fn_141(int x) { return x + 141; }
-inline int shared_fn_142(int x) { return x + 142; }
-inline int shared_fn_143(int x) { return x + 143; }
-inline int shared_fn_144(int x) { return x + 144; }
-inline int shared_fn_145(int x) { return x + 145; }
-inline int shared_fn_146(int x) { return x + 146; }
-inline int shared_fn_147(int x) { return x + 147; }
-inline int shared_fn_148(int x) { return x + 148; }
-inline int shared_fn_149(int x) { return x + 149; }
-inline int shared_fn_150(int x) { return x + 150; }
-inline int shared_fn_151(int x) { return x + 151; }
-inline int shared_fn_152(int x) { return x + 152; }
-inline int shared_fn_153(int x) { return x + 153; }
-inline int shared_fn_154(int x) { return x + 154; }
-inline int shared_fn_155(int x) { return x + 155; }
-inline int shared_fn_156(int x) { return x + 156; }
-inline int shared_fn_157(int x) { return x + 157; }
-inline int shared_fn_158(int x) { return x + 158; }
-inline int shared_fn_159(int x) { return x + 159; }
-inline int shared_fn_160(int x) { return x + 160; }
-inline int shared_fn_161(int x) { return x + 161; }
-inline int shared_fn_162(int x) { return x + 162; }
-inline int shared_fn_163(int x) { return x + 163; }
-inline int shared_fn_164(int x) { return x + 164; }
-inline int shared_fn_165(int x) { return x + 165; }
-inline int shared_fn_166(int x) { return x + 166; }
-inline int shared_fn_167(int x) { return x + 167; }
-inline int shared_fn_168(int x) { return x + 168; }
-inline int shared_fn_169(int x) { return x + 169; }
-inline int shared_fn_170(int x) { return x + 170; }
-inline int shared_fn_171(int x) { return x + 171; }
-inline int shared_fn_172(int x) { return x + 172; }
-inline int shared_fn_173(int x) { return x + 173; }
-inline int shared_fn_174(int x) { return x + 174; }
-inline int shared_fn_175(int x) { return x + 175; }
-inline int shared_fn_176(int x) { return x + 176; }
-inline int shared_fn_177(int x) { return x + 177; }
-inline int shared_fn_178(int x) { return x + 178; }
-inline int shared_fn_179(int x) { return x + 179; }
-inline int shared_fn_180(int x) { return x + 180; }
-inline int shared_fn_181(int x) { return x + 181; }
-inline int shared_fn_182(int x) { return x + 182; }
-inline int shared_fn_183(int x) { return x + 183; }
-inline int shared_fn_184(int x) { return x + 184; }
-inline int shared_fn_185(int x) { return x + 185; }
-inline int shared_fn_186(int x) { return x + 186; }
-inline int shared_fn_187(int x) { return x + 187; }
-inline int shared_fn_188(int x) { return x + 188; }
-inline int shared_fn_189(int x) { return x + 189; }
-inline int shared_fn_190(int x) { return x + 190; }
-inline int shared_fn_191(int x) { return x + 191; }
-inline int shared_fn_192(int x) { return x + 192; }
-inline int shared_fn_193(int x) { return x + 193; }
-inline int shared_fn_194(int x) { return x + 194; }
-inline int shared_fn_195(int x) { return x + 195; }
-inline int shared_fn_196(int x) { return x + 196; }
-inline int shared_fn_197(int x) { return x + 197; }
-inline int shared_fn_198(int x) { return x + 198; }
-inline int shared_fn_199(int x) { return x + 199; }
-inline int shared_fn_200(int x) { return x + 200; }
-inline int shared_fn_201(int x) { return x + 201; }
-inline int shared_fn_202(int x) { return x + 202; }
-inline int shared_fn_203(int x) { return x + 203; }
-inline int shared_fn_204(int x) { return x + 204; }
-inline int shared_fn_205(int x) { return x + 205; }
-inline int shared_fn_206(int x) { return x + 206; }
-inline int shared_fn_207(int x) { return x + 207; }
-inline int shared_fn_208(int x) { return x + 208; }
-inline int shared_fn_209(int x) { return x + 209; }
-inline int shared_fn_210(int x) { return x + 210; }
-inline int shared_fn_211(int x) { return x + 211; }
-inline int shared_fn_212(int x) { return x + 212; }
-inline int shared_fn_213(int x) { return x + 213; }
-inline int shared_fn_214(int x) { return x + 214; }
-inline int shared_fn_215(int x) { return x + 215; }
-inline int shared_fn_216(int x) { return x + 216; }
-inline int shared_fn_217(int x) { return x + 217; }
-inline int shared_fn_218(int x) { return x + 218; }
-inline int shared_fn_219(int x) { return x + 219; }
-inline int shared_fn_220(int x) { return x + 220; }
-inline int shared_fn_221(int x) { return x + 221; }
-inline int shared_fn_222(int x) { return x + 222; }
-inline int shared_fn_223(int x) { return x + 223; }
-inline int shared_fn_224(int x) { return x + 224; }
-inline int shared_fn_225(int x) { return x + 225; }
-inline int shared_fn_226(int x) { return x + 226; }
-inline int shared_fn_227(int x) { return x + 227; }
-inline int shared_fn_228(int x) { return x + 228; }
-inline int shared_fn_229(int x) { return x + 229; }
-inline int shared_fn_230(int x) { return x + 230; }
-inline int shared_fn_231(int x) { return x + 231; }
-inline int shared_fn_232(int x) { return x + 232; }
-inline int shared_fn_233(int x) { return x + 233; }
-inline int shared_fn_234(int x) { return x + 234; }
-inline int shared_fn_235(int x) { return x + 235; }
-inline int shared_fn_236(int x) { return x + 236; }
-inline int shared_fn_237(int x) { return x + 237; }
-inline int shared_fn_238(int x) { return x + 238; }
-inline int shared_fn_239(int x) { return x + 239; }
-inline int shared_fn_240(int x) { return x + 240; }
-inline int shared_fn_241(int x) { return x + 241; }
-inline int shared_fn_242(int x) { return x + 242; }
-inline int shared_fn_243(int x) { return x + 243; }
-inline int shared_fn_244(int x) { return x + 244; }
-inline int shared_fn_245(int x) { return x + 245; }
-inline int shared_fn_246(int x) { return x + 246; }
-inline int shared_fn_247(int x) { return x + 247; }
-inline int shared_fn_248(int x) { return x + 248; }
-inline int shared_fn_249(int x) { return x + 249; }
-inline int shared_fn_250(int x) { return x + 250; }
-inline int shared_fn_251(int x) { return x + 251; }
-inline int shared_fn_252(int x) { return x + 252; }
-inline int shared_fn_253(int x) { return x + 253; }
-inline int shared_fn_254(int x) { return x + 254; }
-inline int shared_fn_255(int x) { return x + 255; }
-inline int shared_fn_256(int x) { return x + 256; }
-inline int shared_fn_257(int x) { return x + 257; }
-inline int shared_fn_258(int x) { return x + 258; }
-inline int shared_fn_259(int x) { return x + 259; }
-inline int shared_fn_260(int x) { return x + 260; }
-inline int shared_fn_261(int x) { return x + 261; }
-inline int shared_fn_262(int x) { return x + 262; }
-inline int shared_fn_263(int x) { return x + 263; }
-inline int shared_fn_264(int x) { return x + 264; }
-inline int shared_fn_265(int x) { return x + 265; }
-inline int shared_fn_266(int x) { return x + 266; }
-inline int shared_fn_267(int x) { return x + 267; }
-inline int shared_fn_268(int x) { return x + 268; }
-inline int shared_fn_269(int x) { return x + 269; }
-inline int shared_fn_270(int x) { return x + 270; }
-inline int shared_fn_271(int x) { return x + 271; }
-inline int shared_fn_272(int x) { return x + 272; }
-inline int shared_fn_273(int x) { return x + 273; }
-inline int shared_fn_274(int x) { return x + 274; }
-inline int shared_fn_275(int x) { return x + 275; }
-inline int shared_fn_276(int x) { return x + 276; }
-inline int shared_fn_277(int x) { return x + 277; }
-inline int shared_fn_278(int x) { return x + 278; }
-inline int shared_fn_279(int x) { return x + 279; }
-inline int shared_fn_280(int x) { return x + 280; }
-inline int shared_fn_281(int x) { return x + 281; }
-inline int shared_fn_282(int x) { return x + 282; }
-inline int shared_fn_283(int x) { return x + 283; }
-inline int shared_fn_284(int x) { return x + 284; }
-inline int shared_fn_285(int x) { return x + 285; }
-inline int shared_fn_286(int x) { return x + 286; }
-inline int shared_fn_287(int x) { return x + 287; }
-inline int shared_fn_288(int x) { return x + 288; }
-inline int shared_fn_289(int x) { return x + 289; }
-inline int shared_fn_290(int x) { return x + 290; }
-inline int shared_fn_291(int x) { return x + 291; }
-inline int shared_fn_292(int x) { return x + 292; }
-inline int shared_fn_293(int x) { return x + 293; }
-inline int shared_fn_294(int x) { return x + 294; }
-inline int shared_fn_295(int x) { return x + 295; }
-inline int shared_fn_296(int x) { return x + 296; }
-inline int shared_fn_297(int x) { return x + 297; }
-inline int shared_fn_298(int x) { return x + 298; }
-inline int shared_fn_299(int x) { return x + 299; }
-inline int shared_fn_300(int x) { return x + 300; }
-inline int shared_fn_301(int x) { return x + 301; }
-inline int shared_fn_302(int x) { return x + 302; }
-inline int shared_fn_303(int x) { return x + 303; }
-inline int shared_fn_304(int x) { return x + 304; }
-inline int shared_fn_305(int x) { return x + 305; }
-inline int shared_fn_306(int x) { return x + 306; }
-inline int shared_fn_307(int x) { return x + 307; }
-inline int shared_fn_308(int x) { return x + 308; }
-inline int shared_fn_309(int x) { return x + 309; }
-inline int shared_fn_310(int x) { return x + 310; }
-inline int shared_fn_311(int x) { return x + 311; }
-inline int shared_fn_312(int x) { return x + 312; }
-inline int shared_fn_313(int x) { return x + 313; }
-inline int shared_fn_314(int x) { return x + 314; }
-inline int shared_fn_315(int x) { return x + 315; }
-inline int shared_fn_316(int x) { return x + 316; }
-inline int shared_fn_317(int x) { return x + 317; }
-inline int shared_fn_318(int x) { return x + 318; }
-inline int shared_fn_319(int x) { return x + 319; }
-inline int shared_fn_320(int x) { return x + 320; }
-inline int shared_fn_321(int x) { return x + 321; }
-inline int shared_fn_322(int x) { return x + 322; }
-inline int shared_fn_323(int x) { return x + 323; }
-inline int shared_fn_324(int x) { return x + 324; }
-inline int shared_fn_325(int x) { return x + 325; }
-inline int shared_fn_326(int x) { return x + 326; }
-inline int shared_fn_327(int x) { return x + 327; }
-inline int shared_fn_328(int x) { return x + 328; }
-inline int shared_fn_329(int x) { return x + 329; }
-inline int shared_fn_330(int x) { return x + 330; }
-inline int shared_fn_331(int x) { return x + 331; }
-inline int shared_fn_332(int x) { return x + 332; }
-inline int shared_fn_333(int x) { return x + 333; }
-inline int shared_fn_334(int x) { return x + 334; }
-inline int shared_fn_335(int x) { return x + 335; }
-inline int shared_fn_336(int x) { return x + 336; }
-inline int shared_fn_337(int x) { return x + 337; }
-inline int shared_fn_338(int x) { return x + 338; }
-inline int shared_fn_339(int x) { return x + 339; }
-inline int shared_fn_340(int x) { return x + 340; }
-inline int shared_fn_341(int x) { return x + 341; }
-inline int shared_fn_342(int x) { return x + 342; }
-inline int shared_fn_343(int x) { return x + 343; }
-inline int shared_fn_344(int x) { return x + 344; }
-inline int shared_fn_345(int x) { return x + 345; }
-inline int shared_fn_346(int x) { return x + 346; }
-inline int shared_fn_347(int x) { return x + 347; }
-inline int shared_fn_348(int x) { return x + 348; }
-inline int shared_fn_349(int x) { return x + 349; }
-inline int shared_fn_350(int x) { return x + 350; }
-inline int shared_fn_351(int x) { return x + 351; }
-inline int shared_fn_352(int x) { return x + 352; }
-inline int shared_fn_353(int x) { return x + 353; }
-inline int shared_fn_354(int x) { return x + 354; }
-inline int shared_fn_355(int x) { return x + 355; }
-inline int shared_fn_356(int x) { return x + 356; }
-inline int shared_fn_357(int x) { return x + 357; }
-inline int shared_fn_358(int x) { return x + 358; }
-inline int shared_fn_359(int x) { return x + 359; }
-inline int shared_fn_360(int x) { return x + 360; }
-inline int shared_fn_361(int x) { return x + 361; }
-inline int shared_fn_362(int x) { return x + 362; }
-inline int shared_fn_363(int x) { return x + 363; }
-inline int shared_fn_364(int x) { return x + 364; }
-inline int shared_fn_365(int x) { return x + 365; }
-inline int shared_fn_366(int x) { return x + 366; }
-inline int shared_fn_367(int x) { return x + 367; }
-inline int shared_fn_368(int x) { return x + 368; }
-inline int shared_fn_369(int x) { return x + 369; }
-inline int shared_fn_370(int x) { return x + 370; }
-inline int shared_fn_371(int x) { return x + 371; }
-inline int shared_fn_372(int x) { return x + 372; }
-inline int shared_fn_373(int x) { return x + 373; }
-inline int shared_fn_374(int x) { return x + 374; }
-inline int shared_fn_375(int x) { return x + 375; }
-inline int shared_fn_376(int x) { return x + 376; }
-inline int shared_fn_377(int x) { return x + 377; }
-inline int shared_fn_378(int x) { return x + 378; }
-inline int shared_fn_379(int x) { return x + 379; }
-inline int shared_fn_380(int x) { return x + 380; }
-inline int shared_fn_381(int x) { return x + 381; }
-inline int shared_fn_382(int x) { return x + 382; }
-inline int shared_fn_383(int x) { return x + 383; }
-inline int shared_fn_384(int x) { return x + 384; }
-inline int shared_fn_385(int x) { return x + 385; }
-inline int shared_fn_386(int x) { return x + 386; }
-inline int shared_fn_387(int x) { return x + 387; }
-inline int shared_fn_388(int x) { return x + 388; }
-inline int shared_fn_389(int x) { return x + 389; }
-inline int shared_fn_390(int x) { return x + 390; }
-inline int shared_fn_391(int x) { return x + 391; }
-inline int shared_fn_392(int x) { return x + 392; }
-inline int shared_fn_393(int x) { return x + 393; }
-inline int shared_fn_394(int x) { return x + 394; }
-inline int shared_fn_395(int x) { return x + 395; }
-inline int shared_fn_396(int x) { return x + 396; }
-inline int shared_fn_397(int x) { return x + 397; }
-inline int shared_fn_398(int x) { return x + 398; }
-inline int shared_fn_399(int x) { return x + 399; }
-#endif
diff --git a/dedup-test/use.cpp b/dedup-test/use.cpp
deleted file mode 100644
index cc00041ff4cc4..0000000000000
--- a/dedup-test/use.cpp
+++ /dev/null
@@ -1,3 +0,0 @@
-#include "a.h"
-#include "b.h"
-int main() { return a_entry(1) + b_entry(2); }
diff --git a/dedup-test/use1.cpp b/dedup-test/use1.cpp
deleted file mode 100644
index 1d4c4250df0c7..0000000000000
--- a/dedup-test/use1.cpp
+++ /dev/null
@@ -1,2 +0,0 @@
-#include "a.h"
-int main() { return a_entry(1); }
diff --git a/dedup-test/use_err.cpp b/dedup-test/use_err.cpp
deleted file mode 100644
index e3cf22fe27df4..0000000000000
--- a/dedup-test/use_err.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-// Stage 2c: prove the redirect resolves correctly.
-// Include BOTH modules so A loads first (registers shared.h as the canonical
-// copy) and B loads second (its shared.h is de-duplicated / redirected into
-// A's copy). Then trigger a diagnostic whose location lives in shared.h.
-// The error must still point at shared.h:<line> with the right function/line,
-// which only holds if the redirected offsets resolve correctly.
-#include "a.h"
-#include "b.h"
-
-int main() {
- // shared_fn_1 is defined in shared.h (present in both A and B); pass a bad
- // argument so overload resolution reports the candidate in shared.h.
- return a_entry(1) + shared_fn_1("oops");
-}
diff --git a/dedup-test/use_err_rev.cpp b/dedup-test/use_err_rev.cpp
deleted file mode 100644
index 817bfb4bc2b1e..0000000000000
--- a/dedup-test/use_err_rev.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-// Stage 2c: load-order independence. Same as use_err.cpp but with the include
-// order flipped so B is seen first. Whichever module loads first becomes the
-// canonical copy; the other redirects into it. Result should be identical:
-// dedup active + the diagnostic still resolves to shared.h:<line>.
-#include "b.h"
-#include "a.h"
-
-int main() {
- return a_entry(1) + shared_fn_1("oops");
-}
>From 4dd7271b2c0f56af6b377e690900b4166ff3e058 Mon Sep 17 00:00:00 2001
From: Ayokunle Amodu <ayokunle321 at gmail.com>
Date: Wed, 15 Jul 2026 13:40:40 +0000
Subject: [PATCH 11/15] clean up comments
---
clang/include/clang/Basic/SourceManager.h | 2 +-
clang/include/clang/Serialization/ASTReader.h | 21 +++++++++----------
.../include/clang/Serialization/ModuleFile.h | 2 +-
clang/lib/Basic/SourceManager.cpp | 2 +-
clang/lib/Serialization/ASTReader.cpp | 5 ++++-
5 files changed, 17 insertions(+), 15 deletions(-)
diff --git a/clang/include/clang/Basic/SourceManager.h b/clang/include/clang/Basic/SourceManager.h
index 424de78725492..b776d37b6ba1a 100644
--- a/clang/include/clang/Basic/SourceManager.h
+++ b/clang/include/clang/Basic/SourceManager.h
@@ -755,7 +755,7 @@ class SourceManager : public RefCountedBase<SourceManager> {
static const SourceLocation::UIntTy MaxLoadedOffset =
1ULL << (8 * sizeof(SourceLocation::UIntTy) - 1);
- // Source location de-duplication. A file included into many modules is
+ // Source location deduplication. A file included into many modules is
// serialized into each of their PCMs. ASTReader keeps the first loaded copy
// and redirects later modules' references to it instead of allocating a
// duplicate SLoc range. These counters record the address space that reuse
diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h
index e1020e64fcca8..429d7fc3e653f 100644
--- a/clang/include/clang/Serialization/ASTReader.h
+++ b/clang/include/clang/Serialization/ASTReader.h
@@ -2399,10 +2399,11 @@ class ASTReader : public ExternalPreprocessorSource,
llvm::Expected<SourceLocation::UIntTy> readSLocOffset(ModuleFile *F,
unsigned Index);
- /// Identity of an input file, taken from serialized metadata without touching
- /// the filesystem. It uses the stored name, size, and modification time that
- /// Clang's own input-file staleness check relies on. An empty Name marks a
- /// non-file entry (a buffer or expansion), which never deduplicates.
+ /// Identity of an input file, from serialized metadata (no filesystem
+ /// access). Uses the stored name, size, and modification time that Clang's
+ /// own input-file staleness check relies on. ContentHash is not used because
+ /// it is zero unless -fvalidate-ast-input-files-content is set. An empty Name
+ /// marks a non-file entry (a buffer or expansion), which never deduplicates.
struct SLocFileIdentity {
StringRef Name;
off_t Size = 0;
@@ -2421,8 +2422,7 @@ class ASTReader : public ExternalPreprocessorSource,
/// Files already loaded into the loaded SLoc address space, keyed by stored
/// name. Lets a later module reuse an earlier module's copy instead of
- /// allocating a duplicate range. The key is serialized metadata, so no input
- /// file is resolved or stat'd at load time.
+ /// allocating a duplicate range.
llvm::StringMap<PrimaryLoadedFileLoc> PrimaryLoadedFiles;
/// The location of a previously-loaded file matching \p Id (same name, size,
@@ -2437,9 +2437,8 @@ class ASTReader : public ExternalPreprocessorSource,
/// Read \p F's SLoc entry records without materializing them, filling
/// \p Offsets[i] with each entry's local offset and \p Files[i] with its
- /// file identity (empty Name for non-file entries). File identity comes from
- /// serialized metadata only, with no input file resolved on disk. Returns
- /// false on a malformed record.
+ /// file identity (empty Name for non-file entries). Returns false on a
+ /// malformed record.
bool scanLoadedSLocEntries(ModuleFile &F, SmallVectorImpl<uint32_t> &Offsets,
SmallVectorImpl<SLocFileIdentity> &Files);
@@ -2567,8 +2566,8 @@ class ASTReader : public ExternalPreprocessorSource,
Seg.Delta)) |
MacroBit);
}
- // No segment matched. This shouldn't happen, so fall through to the
- // flat shift below.
+ // The segments cover the whole value range, so one always matches.
+ llvm_unreachable("SLocRemap segments must cover every source location");
}
return Loc.getLocWithOffset(ModuleFile.SLocEntryBaseOffset - 2);
diff --git a/clang/include/clang/Serialization/ModuleFile.h b/clang/include/clang/Serialization/ModuleFile.h
index 76cefc2280936..3d2ef6f2124ac 100644
--- a/clang/include/clang/Serialization/ModuleFile.h
+++ b/clang/include/clang/Serialization/ModuleFile.h
@@ -346,7 +346,7 @@ class ModuleFile {
/// AST file.
const uint32_t *SLocEntryOffsets = nullptr;
- // === Source location de-duplication ===
+ // === Source location deduplication ===
/// One segment of the local-to-global source location map. A local raw
/// location L in [LocalBegin, LocalEnd) maps to global location L + Delta.
diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp
index fc1d0094a84d8..ab20a0914a856 100644
--- a/clang/lib/Basic/SourceManager.cpp
+++ b/clang/lib/Basic/SourceManager.cpp
@@ -2154,7 +2154,7 @@ void SourceManager::PrintStats() const {
<< "B of SLoc address space used.\n";
if (NumDuplicateLoadedFiles)
llvm::errs() << NumDuplicateLoadedFiles
- << " duplicate loaded file SLocEntries de-duplicated ("
+ << " duplicate loaded file SLocEntries deduplicated ("
<< DuplicateLoadedBytes
<< "B of SLoc address space reused).\n";
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 5df770034e7db..3cf5f3d1a5dcc 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -1901,8 +1901,10 @@ ASTReader::remapSLocEntryOffset(ModuleFile &F, uint32_t LocalOffset) const {
return static_cast<SourceLocation::UIntTy>(static_cast<int64_t>(Low) +
Seg.Delta);
}
+ // The segments cover the whole value range, so one always matches.
+ llvm_unreachable("SLocRemap segments must cover every source location");
}
- // No remap, or no segment matched. Use the original flat shift.
+ // No remap for this module. Use the flat shift.
return F.SLocEntryBaseOffset + LocalOffset;
}
@@ -4354,6 +4356,7 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
// file as it goes, so checking against the map there would treat a file
// that appears more than once in this module as a duplicate of its own
// first occurrence.
+ // Entry I's size is the gap to the next offset (block end for the last).
auto entrySize = [&](unsigned I) -> uint64_t {
return (I + 1 < N ? Offsets[I + 1] : SLocSpaceSize) - Offsets[I];
};
>From 8430b38aa3c530ced447636b8a0cdf9c9bfcedb2 Mon Sep 17 00:00:00 2001
From: Ayokunle Amodu <ayokunle321 at gmail.com>
Date: Wed, 15 Jul 2026 14:19:29 +0000
Subject: [PATCH 12/15] clean up git ignore
---
.gitignore | 3 ---
1 file changed, 3 deletions(-)
diff --git a/.gitignore b/.gitignore
index 1bceeef94e7e4..a4382c9ea7390 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,9 +31,6 @@
# Nested build directory
/build*
-/ Test directory
-/dedup-test
-
#==============================================================================#
# Explicit files to ignore (only matches one).
#==============================================================================#
>From 0b6514cc4395a38b3dad8cc5895569bf294281aa Mon Sep 17 00:00:00 2001
From: Ayokunle Amodu <ayokunle321 at gmail.com>
Date: Wed, 15 Jul 2026 14:35:13 +0000
Subject: [PATCH 13/15] clean up comments
---
clang/include/clang/Serialization/ASTReader.h | 8 +++-----
clang/lib/Serialization/ASTReader.cpp | 6 ++----
2 files changed, 5 insertions(+), 9 deletions(-)
diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h
index 429d7fc3e653f..ac54818e850b7 100644
--- a/clang/include/clang/Serialization/ASTReader.h
+++ b/clang/include/clang/Serialization/ASTReader.h
@@ -2399,11 +2399,9 @@ class ASTReader : public ExternalPreprocessorSource,
llvm::Expected<SourceLocation::UIntTy> readSLocOffset(ModuleFile *F,
unsigned Index);
- /// Identity of an input file, from serialized metadata (no filesystem
- /// access). Uses the stored name, size, and modification time that Clang's
- /// own input-file staleness check relies on. ContentHash is not used because
- /// it is zero unless -fvalidate-ast-input-files-content is set. An empty Name
- /// marks a non-file entry (a buffer or expansion), which never deduplicates.
+ /// Identity of an input file, built from serialized metadata so we touch no
+ /// files at load. An empty Name means a non-file entry like a buffer or
+ /// expansion, and never deduplicates.
struct SLocFileIdentity {
StringRef Name;
off_t Size = 0;
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 3cf5f3d1a5dcc..e51a56e3de0da 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -1868,10 +1868,8 @@ bool ASTReader::scanLoadedSLocEntries(
}
Offsets[I] = (uint32_t)Record[0];
if (Code.get() == SM_SLOC_FILE_ENTRY) {
- // Identify the file from serialized metadata only. Resolving it on disk
- // here (getInputFile) would stat and open every input file of every
- // module at load, which is prohibitive. The stored name, size, and time
- // are the identity Clang's own staleness check already uses.
+ // File identity comes from serialized metadata, so no input file is
+ // touched on disk at load.
InputFileInfo IFI = getInputFileInfo(F, Record[4]);
if (IFI.isValid())
Files[I] = SLocFileIdentity{IFI.UnresolvedImportedFilename,
>From e12d6251bfc1eec070da2326a765a7608b1bf62c Mon Sep 17 00:00:00 2001
From: Ayokunle Amodu <ayokunle321 at gmail.com>
Date: Wed, 15 Jul 2026 11:43:19 -0400
Subject: [PATCH 14/15] run clang format
---
clang/include/clang/Serialization/ASTReader.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h
index ac54818e850b7..a2d673beb90c5 100644
--- a/clang/include/clang/Serialization/ASTReader.h
+++ b/clang/include/clang/Serialization/ASTReader.h
@@ -2400,7 +2400,7 @@ class ASTReader : public ExternalPreprocessorSource,
unsigned Index);
/// Identity of an input file, built from serialized metadata so we touch no
- /// files at load. An empty Name means a non-file entry like a buffer or
+ /// files at load. An empty Name means a non-file entry like a buffer or
/// expansion, and never deduplicates.
struct SLocFileIdentity {
StringRef Name;
>From 7765cb9287be48013699fec86413574fe06b9952 Mon Sep 17 00:00:00 2001
From: Ayokunle Amodu <ayokunle321 at gmail.com>
Date: Thu, 30 Jul 2026 11:57:09 -0400
Subject: [PATCH 15/15] get rid of un needed function
---
clang/lib/CIR/CodeGen/CIRGenBuiltinAMDGPU.cpp | 9 +++------
clang/test/CIR/CodeGenHIP/builtins-amdgcn.hip | 16 ++++++++++++++++
2 files changed, 19 insertions(+), 6 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinAMDGPU.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinAMDGPU.cpp
index 63bc9d8b6b144..46226eed2c884 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltinAMDGPU.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinAMDGPU.cpp
@@ -241,12 +241,9 @@ CIRGenFunction::emitAMDGPUBuiltinExpr(unsigned builtinId,
mlir::ValueRange{src0, src1, src2});
}
case AMDGPU::BI__builtin_amdgcn_trig_preop:
- case AMDGPU::BI__builtin_amdgcn_trig_preopf: {
- cgm.errorNYI(expr->getSourceRange(),
- std::string("unimplemented AMDGPU builtin call: ") +
- getContext().BuiltinInfo.getName(builtinId));
- return mlir::Value{};
- }
+ case AMDGPU::BI__builtin_amdgcn_trig_preopf:
+ return emitBuiltinWithOneOverloadedType<2>(expr, "amdgcn.trig.preop")
+ .getValue();
case AMDGPU::BI__builtin_amdgcn_rcp:
case AMDGPU::BI__builtin_amdgcn_rcpf:
case AMDGPU::BI__builtin_amdgcn_rcph:
diff --git a/clang/test/CIR/CodeGenHIP/builtins-amdgcn.hip b/clang/test/CIR/CodeGenHIP/builtins-amdgcn.hip
index 5dfc95490209b..546e851461ce4 100644
--- a/clang/test/CIR/CodeGenHIP/builtins-amdgcn.hip
+++ b/clang/test/CIR/CodeGenHIP/builtins-amdgcn.hip
@@ -223,3 +223,19 @@ __device__ void test_frexp_mant_f32(float* out, float a) {
__device__ void test_frexp_mant_f64(double* out, double a) {
*out = __builtin_amdgcn_frexp_mant(a);
}
+
+// CIR-LABEL: @_Z19test_trig_preop_f32Pffi
+// CIR: cir.call_llvm_intrinsic "amdgcn.trig.preop" {{.*}} : (!cir.float, !s32i) -> !cir.float
+// LLVM: define{{.*}} void @_Z19test_trig_preop_f32Pffi
+// LLVM: call{{.*}} float @llvm.amdgcn.trig.preop.f32(float %{{.+}}, i32 %{{.+}})
+__device__ void test_trig_preop_f32(float* out, float a, int b) {
+ *out = __builtin_amdgcn_trig_preopf(a, b);
+}
+
+// CIR-LABEL: @_Z19test_trig_preop_f64Pddi
+// CIR: cir.call_llvm_intrinsic "amdgcn.trig.preop" {{.*}} : (!cir.double, !s32i) -> !cir.double
+// LLVM: define{{.*}} void @_Z19test_trig_preop_f64Pddi
+// LLVM: call{{.*}} double @llvm.amdgcn.trig.preop.f64(double %{{.+}}, i32 %{{.+}})
+__device__ void test_trig_preop_f64(double* out, double a, int b) {
+ *out = __builtin_amdgcn_trig_preop(a, b);
+}
More information about the cfe-commits
mailing list