Skip to content

Commit 44af53b

Browse files
authored
[clang][modules] Avoid calling expensive SourceManager::translateFile() (#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).
1 parent 5b06de7 commit 44af53b

File tree

6 files changed

+78
-50
lines changed

6 files changed

+78
-50
lines changed

clang/include/clang/Lex/ModuleMap.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,8 @@ class ModuleMap {
263263
Attributes Attrs;
264264

265265
/// If \c InferModules is non-zero, the module map file that allowed
266-
/// inferred modules. Otherwise, nullopt.
267-
OptionalFileEntryRef ModuleMapFile;
266+
/// inferred modules. Otherwise, invalid.
267+
FileID ModuleMapFID;
268268

269269
/// The names of modules that cannot be inferred within this
270270
/// directory.
@@ -279,8 +279,7 @@ class ModuleMap {
279279

280280
/// A mapping from an inferred module to the module map that allowed the
281281
/// inference.
282-
// FIXME: Consider making the values non-optional.
283-
llvm::DenseMap<const Module *, OptionalFileEntryRef> InferredModuleAllowedBy;
282+
llvm::DenseMap<const Module *, FileID> InferredModuleAllowedBy;
284283

285284
llvm::DenseMap<const Module *, AdditionalModMapsSet> AdditionalModMaps;
286285

@@ -618,8 +617,9 @@ class ModuleMap {
618617
///
619618
/// \param Module The module whose module map file will be returned, if known.
620619
///
621-
/// \returns The file entry for the module map file containing the given
622-
/// module, or nullptr if the module definition was inferred.
620+
/// \returns The FileID for the module map file containing the given module,
621+
/// invalid if the module definition was inferred.
622+
FileID getContainingModuleMapFileID(const Module *Module) const;
623623
OptionalFileEntryRef getContainingModuleMapFile(const Module *Module) const;
624624

625625
/// Get the module map file that (along with the module name) uniquely
@@ -631,9 +631,10 @@ class ModuleMap {
631631
/// of inferred modules, returns the module map that allowed the inference
632632
/// (e.g. contained 'module *'). Otherwise, returns
633633
/// getContainingModuleMapFile().
634+
FileID getModuleMapFileIDForUniquing(const Module *M) const;
634635
OptionalFileEntryRef getModuleMapFileForUniquing(const Module *M) const;
635636

636-
void setInferredModuleAllowedBy(Module *M, OptionalFileEntryRef ModMap);
637+
void setInferredModuleAllowedBy(Module *M, FileID ModMapFID);
637638

638639
/// Canonicalize \p Path in a manner suitable for a module map file. In
639640
/// 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
@@ -1337,9 +1337,24 @@ static bool compileModule(CompilerInstance &ImportingInstance,
13371337
// Get or create the module map that we'll use to build this module.
13381338
ModuleMap &ModMap
13391339
= ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
1340+
SourceManager &SourceMgr = ImportingInstance.getSourceManager();
13401341
bool Result;
1341-
if (OptionalFileEntryRef ModuleMapFile =
1342-
ModMap.getContainingModuleMapFile(Module)) {
1342+
if (FileID ModuleMapFID = ModMap.getContainingModuleMapFileID(Module);
1343+
ModuleMapFID.isValid()) {
1344+
// We want to use the top-level module map. If we don't, the compiling
1345+
// instance may think the containing module map is a top-level one, while
1346+
// the importing instance knows it's included from a parent module map via
1347+
// the extern directive. This mismatch could bite us later.
1348+
SourceLocation Loc = SourceMgr.getIncludeLoc(ModuleMapFID);
1349+
while (Loc.isValid() && isModuleMap(SourceMgr.getFileCharacteristic(Loc))) {
1350+
ModuleMapFID = SourceMgr.getFileID(Loc);
1351+
Loc = SourceMgr.getIncludeLoc(ModuleMapFID);
1352+
}
1353+
1354+
OptionalFileEntryRef ModuleMapFile =
1355+
SourceMgr.getFileEntryRefForID(ModuleMapFID);
1356+
assert(ModuleMapFile && "Top-level module map with no FileID");
1357+
13431358
// Canonicalize compilation to start with the public module map. This is
13441359
// vital for submodules declarations in the private module maps to be
13451360
// 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
@@ -535,8 +535,14 @@ static Module *prepareToBuildModule(CompilerInstance &CI,
535535
if (*OriginalModuleMap != CI.getSourceManager().getFileEntryRefForID(
536536
CI.getSourceManager().getMainFileID())) {
537537
M->IsInferred = true;
538-
CI.getPreprocessor().getHeaderSearchInfo().getModuleMap()
539-
.setInferredModuleAllowedBy(M, *OriginalModuleMap);
538+
auto FileCharacter =
539+
M->IsSystem ? SrcMgr::C_System_ModuleMap : SrcMgr::C_User_ModuleMap;
540+
FileID OriginalModuleMapFID = CI.getSourceManager().getOrCreateFileID(
541+
*OriginalModuleMap, FileCharacter);
542+
CI.getPreprocessor()
543+
.getHeaderSearchInfo()
544+
.getModuleMap()
545+
.setInferredModuleAllowedBy(M, OriginalModuleMapFID);
540546
}
541547
}
542548

clang/lib/Lex/ModuleMap.cpp

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

650650
if (UmbrellaModule->InferSubmodules) {
651-
OptionalFileEntryRef UmbrellaModuleMap =
652-
getModuleMapFileForUniquing(UmbrellaModule);
651+
FileID UmbrellaModuleMap = getModuleMapFileIDForUniquing(UmbrellaModule);
653652

654653
// Infer submodules for each of the directories we found between
655654
// the directory of the umbrella header and the directory where
@@ -1021,7 +1020,7 @@ Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir,
10211020

10221021
// If the framework has a parent path from which we're allowed to infer
10231022
// a framework module, do so.
1024-
OptionalFileEntryRef ModuleMapFile;
1023+
FileID ModuleMapFID;
10251024
if (!Parent) {
10261025
// Determine whether we're allowed to infer a module map.
10271026
bool canInfer = false;
@@ -1060,7 +1059,7 @@ Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir,
10601059
Attrs.IsExhaustive |= inferred->second.Attrs.IsExhaustive;
10611060
Attrs.NoUndeclaredIncludes |=
10621061
inferred->second.Attrs.NoUndeclaredIncludes;
1063-
ModuleMapFile = inferred->second.ModuleMapFile;
1062+
ModuleMapFID = inferred->second.ModuleMapFID;
10641063
}
10651064
}
10661065
}
@@ -1069,7 +1068,7 @@ Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir,
10691068
if (!canInfer)
10701069
return nullptr;
10711070
} else {
1072-
ModuleMapFile = getModuleMapFileForUniquing(Parent);
1071+
ModuleMapFID = getModuleMapFileIDForUniquing(Parent);
10731072
}
10741073

10751074
// Look for an umbrella header.
@@ -1086,7 +1085,7 @@ Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir,
10861085
Module *Result = new Module(ModuleName, SourceLocation(), Parent,
10871086
/*IsFramework=*/true, /*IsExplicit=*/false,
10881087
NumCreatedModules++);
1089-
InferredModuleAllowedBy[Result] = ModuleMapFile;
1088+
InferredModuleAllowedBy[Result] = ModuleMapFID;
10901089
Result->IsInferred = true;
10911090
if (!Parent) {
10921091
if (LangOpts.CurrentModule == ModuleName)
@@ -1307,28 +1306,34 @@ void ModuleMap::addHeader(Module *Mod, Module::Header Header,
13071306
Cb->moduleMapAddHeader(Header.Entry.getName());
13081307
}
13091308

1310-
OptionalFileEntryRef
1311-
ModuleMap::getContainingModuleMapFile(const Module *Module) const {
1309+
FileID ModuleMap::getContainingModuleMapFileID(const Module *Module) const {
13121310
if (Module->DefinitionLoc.isInvalid())
1313-
return std::nullopt;
1311+
return {};
13141312

1315-
return SourceMgr.getFileEntryRefForID(
1316-
SourceMgr.getFileID(Module->DefinitionLoc));
1313+
return SourceMgr.getFileID(Module->DefinitionLoc);
13171314
}
13181315

13191316
OptionalFileEntryRef
1320-
ModuleMap::getModuleMapFileForUniquing(const Module *M) const {
1317+
ModuleMap::getContainingModuleMapFile(const Module *Module) const {
1318+
return SourceMgr.getFileEntryRefForID(getContainingModuleMapFileID(Module));
1319+
}
1320+
1321+
FileID ModuleMap::getModuleMapFileIDForUniquing(const Module *M) const {
13211322
if (M->IsInferred) {
13221323
assert(InferredModuleAllowedBy.count(M) && "missing inferred module map");
13231324
return InferredModuleAllowedBy.find(M)->second;
13241325
}
1325-
return getContainingModuleMapFile(M);
1326+
return getContainingModuleMapFileID(M);
1327+
}
1328+
1329+
OptionalFileEntryRef
1330+
ModuleMap::getModuleMapFileForUniquing(const Module *M) const {
1331+
return SourceMgr.getFileEntryRefForID(getModuleMapFileIDForUniquing(M));
13261332
}
13271333

1328-
void ModuleMap::setInferredModuleAllowedBy(Module *M,
1329-
OptionalFileEntryRef ModMap) {
1334+
void ModuleMap::setInferredModuleAllowedBy(Module *M, FileID ModMapFID) {
13301335
assert(M->IsInferred && "module not inferred");
1331-
InferredModuleAllowedBy[M] = ModMap;
1336+
InferredModuleAllowedBy[M] = ModMapFID;
13321337
}
13331338

13341339
std::error_code
@@ -1517,7 +1522,7 @@ namespace clang {
15171522
ModuleMap &Map;
15181523

15191524
/// The current module map file.
1520-
FileEntryRef ModuleMapFile;
1525+
FileID ModuleMapFID;
15211526

15221527
/// Source location of most recent parsed module declaration
15231528
SourceLocation CurrModuleDeclLoc;
@@ -1585,13 +1590,12 @@ namespace clang {
15851590
bool parseOptionalAttributes(Attributes &Attrs);
15861591

15871592
public:
1588-
explicit ModuleMapParser(Lexer &L, SourceManager &SourceMgr,
1589-
const TargetInfo *Target, DiagnosticsEngine &Diags,
1590-
ModuleMap &Map, FileEntryRef ModuleMapFile,
1591-
DirectoryEntryRef Directory, bool IsSystem)
1593+
ModuleMapParser(Lexer &L, SourceManager &SourceMgr,
1594+
const TargetInfo *Target, DiagnosticsEngine &Diags,
1595+
ModuleMap &Map, FileID ModuleMapFID,
1596+
DirectoryEntryRef Directory, bool IsSystem)
15921597
: L(L), SourceMgr(SourceMgr), Target(Target), Diags(Diags), Map(Map),
1593-
ModuleMapFile(ModuleMapFile), Directory(Directory),
1594-
IsSystem(IsSystem) {
1598+
ModuleMapFID(ModuleMapFID), Directory(Directory), IsSystem(IsSystem) {
15951599
Tok.clear();
15961600
consumeToken();
15971601
}
@@ -2011,11 +2015,13 @@ void ModuleMapParser::parseModuleDecl() {
20112015
}
20122016

20132017
if (TopLevelModule &&
2014-
ModuleMapFile != Map.getContainingModuleMapFile(TopLevelModule)) {
2015-
assert(ModuleMapFile != Map.getModuleMapFileForUniquing(TopLevelModule) &&
2018+
ModuleMapFID != Map.getContainingModuleMapFileID(TopLevelModule)) {
2019+
assert(ModuleMapFID !=
2020+
Map.getModuleMapFileIDForUniquing(TopLevelModule) &&
20162021
"submodule defined in same file as 'module *' that allowed its "
20172022
"top-level module");
2018-
Map.addAdditionalModuleMapFile(TopLevelModule, ModuleMapFile);
2023+
Map.addAdditionalModuleMapFile(
2024+
TopLevelModule, *SourceMgr.getFileEntryRefForID(ModuleMapFID));
20192025
}
20202026
}
20212027

@@ -2120,7 +2126,8 @@ void ModuleMapParser::parseModuleDecl() {
21202126
ActiveModule->NoUndeclaredIncludes = true;
21212127
ActiveModule->Directory = Directory;
21222128

2123-
StringRef MapFileName(ModuleMapFile.getName());
2129+
StringRef MapFileName(
2130+
SourceMgr.getFileEntryRefForID(ModuleMapFID)->getName());
21242131
if (MapFileName.ends_with("module.private.modulemap") ||
21252132
MapFileName.ends_with("module_private.map")) {
21262133
ActiveModule->ModuleMapIsPrivate = true;
@@ -2906,7 +2913,7 @@ void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) {
29062913
// We'll be inferring framework modules for this directory.
29072914
Map.InferredDirectories[Directory].InferModules = true;
29082915
Map.InferredDirectories[Directory].Attrs = Attrs;
2909-
Map.InferredDirectories[Directory].ModuleMapFile = ModuleMapFile;
2916+
Map.InferredDirectories[Directory].ModuleMapFID = ModuleMapFID;
29102917
// FIXME: Handle the 'framework' keyword.
29112918
}
29122919

@@ -3139,8 +3146,7 @@ bool ModuleMap::parseModuleMapFile(FileEntryRef File, bool IsSystem,
31393146
Buffer->getBufferStart() + (Offset ? *Offset : 0),
31403147
Buffer->getBufferEnd());
31413148
SourceLocation Start = L.getSourceLocation();
3142-
ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, File, Dir,
3143-
IsSystem);
3149+
ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, ID, Dir, IsSystem);
31443150
bool Result = Parser.parseModuleMapFile();
31453151
ParsedModuleMap[File] = Result;
31463152

clang/lib/Serialization/ASTWriter.cpp

Lines changed: 8 additions & 9 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

@@ -4728,7 +4728,6 @@ void ASTWriter::computeNonAffectingInputFiles() {
47284728
continue;
47294729

47304730
if (!isModuleMap(File.getFileCharacteristic()) ||
4731-
AffectingModuleMaps.empty() ||
47324731
llvm::is_contained(AffectingModuleMaps, *Cache->OrigEntry))
47334732
continue;
47344733

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)