Skip to content

Commit 58b2daa

Browse files
committed
[clang][modules] Avoid calling expensive SourceManager::translateFile() (llvm#86216)
The `ASTWriter` algorithm for computing affecting module maps uses `SourceManager::translateFile()` to get a `FileID` from a `FileEntry`. This is slow (O(n)) since the function performs a linear walk over `SLocEntries` until it finds one with a matching `FileEntry`. This patch removes this use of `SourceManager::translateFile()` by tracking `FileID` instead of `FileEntry` in couple of places in `ModuleMap`, giving `ASTWriter` the desired `FileID` directly. There are no changes required for clients that still want a `FileEntry` from `ModuleMap`: the existing APIs internally use `SourceManager` to perform the reverse `FileID` to `FileEntry` conversion in O(1). (cherry picked from commit 44af53b)
1 parent c4f8022 commit 58b2daa

File tree

6 files changed

+79
-53
lines changed

6 files changed

+79
-53
lines changed

clang/include/clang/Lex/ModuleMap.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -270,8 +270,8 @@ class ModuleMap {
270270
Attributes Attrs;
271271

272272
/// If \c InferModules is non-zero, the module map file that allowed
273-
/// inferred modules. Otherwise, nullopt.
274-
OptionalFileEntryRef ModuleMapFile;
273+
/// inferred modules. Otherwise, invalid.
274+
FileID ModuleMapFID;
275275

276276
/// The names of modules that cannot be inferred within this
277277
/// directory.
@@ -286,8 +286,7 @@ class ModuleMap {
286286

287287
/// A mapping from an inferred module to the module map that allowed the
288288
/// inference.
289-
// FIXME: Consider making the values non-optional.
290-
llvm::DenseMap<const Module *, OptionalFileEntryRef> InferredModuleAllowedBy;
289+
llvm::DenseMap<const Module *, FileID> InferredModuleAllowedBy;
291290

292291
llvm::DenseMap<const Module *, AdditionalModMapsSet> AdditionalModMaps;
293292

@@ -630,8 +629,9 @@ class ModuleMap {
630629
///
631630
/// \param Module The module whose module map file will be returned, if known.
632631
///
633-
/// \returns The file entry for the module map file containing the given
634-
/// module, or nullptr if the module definition was inferred.
632+
/// \returns The FileID for the module map file containing the given module,
633+
/// invalid if the module definition was inferred.
634+
FileID getContainingModuleMapFileID(const Module *Module) const;
635635
OptionalFileEntryRef getContainingModuleMapFile(const Module *Module) const;
636636

637637
/// Get the module map file that (along with the module name) uniquely
@@ -643,9 +643,10 @@ class ModuleMap {
643643
/// of inferred modules, returns the module map that allowed the inference
644644
/// (e.g. contained 'module *'). Otherwise, returns
645645
/// getContainingModuleMapFile().
646+
FileID getModuleMapFileIDForUniquing(const Module *M) const;
646647
OptionalFileEntryRef getModuleMapFileForUniquing(const Module *M) const;
647648

648-
void setInferredModuleAllowedBy(Module *M, OptionalFileEntryRef ModMap);
649+
void setInferredModuleAllowedBy(Module *M, FileID ModMapFID);
649650

650651
/// Canonicalize \p Path in a manner suitable for a module map file. In
651652
/// particular, this canonicalizes the parent directory separately from the

clang/lib/Frontend/CompilerInstance.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1427,9 +1427,24 @@ static bool compileModule(CompilerInstance &ImportingInstance,
14271427
// Get or create the module map that we'll use to build this module.
14281428
ModuleMap &ModMap
14291429
= ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
1430+
SourceManager &SourceMgr = ImportingInstance.getSourceManager();
14301431
bool Result;
1431-
if (OptionalFileEntryRef ModuleMapFile =
1432-
ModMap.getContainingModuleMapFile(Module)) {
1432+
if (FileID ModuleMapFID = ModMap.getContainingModuleMapFileID(Module);
1433+
ModuleMapFID.isValid()) {
1434+
// We want to use the top-level module map. If we don't, the compiling
1435+
// instance may think the containing module map is a top-level one, while
1436+
// the importing instance knows it's included from a parent module map via
1437+
// the extern directive. This mismatch could bite us later.
1438+
SourceLocation Loc = SourceMgr.getIncludeLoc(ModuleMapFID);
1439+
while (Loc.isValid() && isModuleMap(SourceMgr.getFileCharacteristic(Loc))) {
1440+
ModuleMapFID = SourceMgr.getFileID(Loc);
1441+
Loc = SourceMgr.getIncludeLoc(ModuleMapFID);
1442+
}
1443+
1444+
OptionalFileEntryRef ModuleMapFile =
1445+
SourceMgr.getFileEntryRefForID(ModuleMapFID);
1446+
assert(ModuleMapFile && "Top-level module map with no FileID");
1447+
14331448
// Canonicalize compilation to start with the public module map. This is
14341449
// vital for submodules declarations in the private module maps to be
14351450
// correctly parsed when depending on a top level module in the public one.

clang/lib/Frontend/FrontendAction.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -543,8 +543,14 @@ static Module *prepareToBuildModule(CompilerInstance &CI,
543543
if (*OriginalModuleMap != CI.getSourceManager().getFileEntryRefForID(
544544
CI.getSourceManager().getMainFileID())) {
545545
M->IsInferred = true;
546-
CI.getPreprocessor().getHeaderSearchInfo().getModuleMap()
547-
.setInferredModuleAllowedBy(M, *OriginalModuleMap);
546+
auto FileCharacter =
547+
M->IsSystem ? SrcMgr::C_System_ModuleMap : SrcMgr::C_User_ModuleMap;
548+
FileID OriginalModuleMapFID = CI.getSourceManager().getOrCreateFileID(
549+
*OriginalModuleMap, FileCharacter);
550+
CI.getPreprocessor()
551+
.getHeaderSearchInfo()
552+
.getModuleMap()
553+
.setInferredModuleAllowedBy(M, OriginalModuleMapFID);
548554
}
549555
}
550556

clang/lib/Lex/ModuleMap.cpp

Lines changed: 36 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -649,8 +649,7 @@ ModuleMap::findOrCreateModuleForHeaderInUmbrellaDir(FileEntryRef File) {
649649
UmbrellaModule = UmbrellaModule->Parent;
650650

651651
if (UmbrellaModule->InferSubmodules) {
652-
OptionalFileEntryRef UmbrellaModuleMap =
653-
getModuleMapFileForUniquing(UmbrellaModule);
652+
FileID UmbrellaModuleMap = getModuleMapFileIDForUniquing(UmbrellaModule);
654653

655654
// Infer submodules for each of the directories we found between
656655
// the directory of the umbrella header and the directory where
@@ -1031,7 +1030,7 @@ Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir,
10311030

10321031
// If the framework has a parent path from which we're allowed to infer
10331032
// a framework module, do so.
1034-
OptionalFileEntryRef ModuleMapFile;
1033+
FileID ModuleMapFID;
10351034
if (!Parent) {
10361035
// Determine whether we're allowed to infer a module map.
10371036
bool canInfer = false;
@@ -1070,7 +1069,7 @@ Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir,
10701069
Attrs.IsExhaustive |= inferred->second.Attrs.IsExhaustive;
10711070
Attrs.NoUndeclaredIncludes |=
10721071
inferred->second.Attrs.NoUndeclaredIncludes;
1073-
ModuleMapFile = inferred->second.ModuleMapFile;
1072+
ModuleMapFID = inferred->second.ModuleMapFID;
10741073
}
10751074
}
10761075
}
@@ -1079,9 +1078,7 @@ Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir,
10791078
if (!canInfer)
10801079
return nullptr;
10811080
} else {
1082-
OptionalFileEntryRefDegradesToFileEntryPtr ModuleMapRef =
1083-
getModuleMapFileForUniquing(Parent);
1084-
ModuleMapFile = ModuleMapRef;
1081+
ModuleMapFID = getModuleMapFileIDForUniquing(Parent);
10851082
}
10861083

10871084
// Look for an umbrella header.
@@ -1098,7 +1095,7 @@ Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir,
10981095
Module *Result = new Module(ModuleName, SourceLocation(), Parent,
10991096
/*IsFramework=*/true, /*IsExplicit=*/false,
11001097
NumCreatedModules++);
1101-
InferredModuleAllowedBy[Result] = ModuleMapFile;
1098+
InferredModuleAllowedBy[Result] = ModuleMapFID;
11021099
Result->IsInferred = true;
11031100
if (!Parent) {
11041101
if (LangOpts.CurrentModule == ModuleName)
@@ -1319,28 +1316,34 @@ void ModuleMap::addHeader(Module *Mod, Module::Header Header,
13191316
Cb->moduleMapAddHeader(Header.Entry.getName());
13201317
}
13211318

1322-
OptionalFileEntryRef
1323-
ModuleMap::getContainingModuleMapFile(const Module *Module) const {
1319+
FileID ModuleMap::getContainingModuleMapFileID(const Module *Module) const {
13241320
if (Module->DefinitionLoc.isInvalid())
1325-
return std::nullopt;
1321+
return {};
13261322

1327-
return SourceMgr.getFileEntryRefForID(
1328-
SourceMgr.getFileID(Module->DefinitionLoc));
1323+
return SourceMgr.getFileID(Module->DefinitionLoc);
13291324
}
13301325

13311326
OptionalFileEntryRef
1332-
ModuleMap::getModuleMapFileForUniquing(const Module *M) const {
1327+
ModuleMap::getContainingModuleMapFile(const Module *Module) const {
1328+
return SourceMgr.getFileEntryRefForID(getContainingModuleMapFileID(Module));
1329+
}
1330+
1331+
FileID ModuleMap::getModuleMapFileIDForUniquing(const Module *M) const {
13331332
if (M->IsInferred) {
13341333
assert(InferredModuleAllowedBy.count(M) && "missing inferred module map");
13351334
return InferredModuleAllowedBy.find(M)->second;
13361335
}
1337-
return getContainingModuleMapFile(M);
1336+
return getContainingModuleMapFileID(M);
1337+
}
1338+
1339+
OptionalFileEntryRef
1340+
ModuleMap::getModuleMapFileForUniquing(const Module *M) const {
1341+
return SourceMgr.getFileEntryRefForID(getModuleMapFileIDForUniquing(M));
13381342
}
13391343

1340-
void ModuleMap::setInferredModuleAllowedBy(Module *M,
1341-
OptionalFileEntryRef ModMap) {
1344+
void ModuleMap::setInferredModuleAllowedBy(Module *M, FileID ModMapFID) {
13421345
assert(M->IsInferred && "module not inferred");
1343-
InferredModuleAllowedBy[M] = ModMap;
1346+
InferredModuleAllowedBy[M] = ModMapFID;
13441347
}
13451348

13461349
std::error_code
@@ -1529,7 +1532,7 @@ namespace clang {
15291532
ModuleMap &Map;
15301533

15311534
/// The current module map file.
1532-
FileEntryRef ModuleMapFile;
1535+
FileID ModuleMapFID;
15331536

15341537
/// Source location of most recent parsed module declaration
15351538
SourceLocation CurrModuleDeclLoc;
@@ -1599,13 +1602,12 @@ namespace clang {
15991602
bool parseOptionalAttributes(Attributes &Attrs);
16001603

16011604
public:
1602-
explicit ModuleMapParser(Lexer &L, SourceManager &SourceMgr,
1603-
const TargetInfo *Target, DiagnosticsEngine &Diags,
1604-
ModuleMap &Map, FileEntryRef ModuleMapFile,
1605-
DirectoryEntryRef Directory, bool IsSystem)
1605+
ModuleMapParser(Lexer &L, SourceManager &SourceMgr,
1606+
const TargetInfo *Target, DiagnosticsEngine &Diags,
1607+
ModuleMap &Map, FileID ModuleMapFID,
1608+
DirectoryEntryRef Directory, bool IsSystem)
16061609
: L(L), SourceMgr(SourceMgr), Target(Target), Diags(Diags), Map(Map),
1607-
ModuleMapFile(ModuleMapFile), Directory(Directory),
1608-
IsSystem(IsSystem) {
1610+
ModuleMapFID(ModuleMapFID), Directory(Directory), IsSystem(IsSystem) {
16091611
Tok.clear();
16101612
consumeToken();
16111613
}
@@ -2028,11 +2030,13 @@ void ModuleMapParser::parseModuleDecl() {
20282030
}
20292031

20302032
if (TopLevelModule &&
2031-
ModuleMapFile != Map.getContainingModuleMapFile(TopLevelModule)) {
2032-
assert(ModuleMapFile != Map.getModuleMapFileForUniquing(TopLevelModule) &&
2033+
ModuleMapFID != Map.getContainingModuleMapFileID(TopLevelModule)) {
2034+
assert(ModuleMapFID !=
2035+
Map.getModuleMapFileIDForUniquing(TopLevelModule) &&
20332036
"submodule defined in same file as 'module *' that allowed its "
20342037
"top-level module");
2035-
Map.addAdditionalModuleMapFile(TopLevelModule, ModuleMapFile);
2038+
Map.addAdditionalModuleMapFile(
2039+
TopLevelModule, *SourceMgr.getFileEntryRefForID(ModuleMapFID));
20362040
}
20372041
}
20382042

@@ -2137,7 +2141,8 @@ void ModuleMapParser::parseModuleDecl() {
21372141
ActiveModule->NoUndeclaredIncludes = true;
21382142
ActiveModule->Directory = Directory;
21392143

2140-
StringRef MapFileName(ModuleMapFile.getName());
2144+
StringRef MapFileName(
2145+
SourceMgr.getFileEntryRefForID(ModuleMapFID)->getName());
21412146
if (MapFileName.endswith("module.private.modulemap") ||
21422147
MapFileName.endswith("module_private.map")) {
21432148
ActiveModule->ModuleMapIsPrivate = true;
@@ -2922,7 +2927,7 @@ void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) {
29222927
// We'll be inferring framework modules for this directory.
29232928
Map.InferredDirectories[Directory].InferModules = true;
29242929
Map.InferredDirectories[Directory].Attrs = Attrs;
2925-
Map.InferredDirectories[Directory].ModuleMapFile = ModuleMapFile;
2930+
Map.InferredDirectories[Directory].ModuleMapFID = ModuleMapFID;
29262931
// FIXME: Handle the 'framework' keyword.
29272932
}
29282933

@@ -3160,8 +3165,7 @@ bool ModuleMap::parseModuleMapFile(FileEntryRef File, bool IsSystem,
31603165
Buffer->getBufferStart() + (Offset ? *Offset : 0),
31613166
Buffer->getBufferEnd());
31623167
SourceLocation Start = L.getSourceLocation();
3163-
ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, File, Dir,
3164-
IsSystem);
3168+
ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, ID, Dir, IsSystem);
31653169
bool Result = Parser.parseModuleMapFile();
31663170
ParsedModuleMap[File] = Result;
31673171

clang/lib/Serialization/ASTWriter.cpp

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -193,17 +193,17 @@ std::set<const FileEntry *> GetAffectingModuleMaps(const Preprocessor &PP,
193193
const ModuleMap &MM = HS.getModuleMap();
194194
SourceManager &SourceMgr = PP.getSourceManager();
195195

196-
std::set<const FileEntry *> ModuleMaps{};
197-
auto CollectIncludingModuleMaps = [&](FileEntryRef F) {
196+
std::set<const FileEntry *> ModuleMaps;
197+
auto CollectIncludingModuleMaps = [&](FileID FID, FileEntryRef F) {
198198
if (!ModuleMaps.insert(F).second)
199199
return;
200-
FileID FID = SourceMgr.translateFile(F);
201200
SourceLocation Loc = SourceMgr.getIncludeLoc(FID);
202201
// The include location of inferred module maps can point into the header
203202
// file that triggered the inferring. Cut off the walk if that's the case.
204203
while (Loc.isValid() && isModuleMap(SourceMgr.getFileCharacteristic(Loc))) {
205204
FID = SourceMgr.getFileID(Loc);
206-
if (!ModuleMaps.insert(*SourceMgr.getFileEntryRefForID(FID)).second)
205+
F = *SourceMgr.getFileEntryRefForID(FID);
206+
if (!ModuleMaps.insert(F).second)
207207
break;
208208
Loc = SourceMgr.getIncludeLoc(FID);
209209
}
@@ -216,13 +216,13 @@ std::set<const FileEntry *> GetAffectingModuleMaps(const Preprocessor &PP,
216216
break;
217217
// The containing module map is affecting, because it's being pointed
218218
// into by Module::DefinitionLoc.
219-
if (auto ModuleMapFile = MM.getContainingModuleMapFile(Mod))
220-
CollectIncludingModuleMaps(*ModuleMapFile);
219+
if (FileID FID = MM.getContainingModuleMapFileID(Mod); FID.isValid())
220+
CollectIncludingModuleMaps(FID, *SourceMgr.getFileEntryRefForID(FID));
221221
// For inferred modules, the module map that allowed inferring is not in
222222
// the include chain of the virtual containing module map file. It did
223223
// affect the compilation, though.
224-
if (auto ModuleMapFile = MM.getModuleMapFileForUniquing(Mod))
225-
CollectIncludingModuleMaps(*ModuleMapFile);
224+
if (FileID FID = MM.getModuleMapFileIDForUniquing(Mod); FID.isValid())
225+
CollectIncludingModuleMaps(FID, *SourceMgr.getFileEntryRefForID(FID));
226226
}
227227
};
228228

@@ -4685,8 +4685,7 @@ void ASTWriter::computeNonAffectingInputFiles() {
46854685
continue;
46864686

46874687
if (!isModuleMap(File.getFileCharacteristic()) ||
4688-
AffectingModuleMaps.empty() ||
4689-
AffectingModuleMaps.find(Cache->OrigEntry) != AffectingModuleMaps.end())
4688+
llvm::is_contained(AffectingModuleMaps, *Cache->OrigEntry))
46904689
continue;
46914690

46924691
IsSLocAffecting[I] = false;

clang/test/ClangScanDeps/modules-extern-unrelated.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
// CHECK-NEXT: "context-hash": "{{.*}}",
7272
// CHECK-NEXT: "file-deps": [
7373
// CHECK-NEXT: "[[PREFIX]]/first/module.modulemap",
74+
// CHECK-NEXT: "[[PREFIX]]/second/module.modulemap",
7475
// CHECK-NEXT: "[[PREFIX]]/second/second.h",
7576
// CHECK-NEXT: "[[PREFIX]]/second/second.modulemap"
7677
// CHECK-NEXT: ],

0 commit comments

Comments
 (0)