[clang] [clang][modules] Avoid calling expensive `SourceManager::translateFile()` (PR #86216)
https://github.com/jansvoboda11 closed https://github.com/llvm/llvm-project/pull/86216 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][modules] Avoid calling expensive `SourceManager::translateFile()` (PR #86216)
https://github.com/benlangmuir approved this pull request. Thanks for explaining; LGTM https://github.com/llvm/llvm-project/pull/86216 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][modules] Avoid calling expensive `SourceManager::translateFile()` (PR #86216)
https://github.com/jansvoboda11 edited https://github.com/llvm/llvm-project/pull/86216 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][modules] Avoid calling expensive `SourceManager::translateFile()` (PR #86216)
https://github.com/jansvoboda11 edited https://github.com/llvm/llvm-project/pull/86216 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][modules] Avoid calling expensive `SourceManager::translateFile()` (PR #86216)
@@ -71,6 +71,7 @@ // CHECK-NEXT: "context-hash": "{{.*}}", // CHECK-NEXT: "file-deps": [ // CHECK-NEXT: "[[PREFIX]]/first/module.modulemap", +// CHECK-NEXT: "[[PREFIX]]/second/module.modulemap", jansvoboda11 wrote: This is a side-effect of the change in `CompilerInstance.cpp`. The implicit scan now uses the top-level module map to compile modules instead of the containing module map and that makes it included in file dependencies. This change is a bit unfortunate, since the explicit command line we generate actually only uses the containing module map, not the top-level one. Ideally, we'd either find a way to remove this file dependency or we'd make the explicit compile to also consume the top-level module map (in which case this file dependency would be real). https://github.com/llvm/llvm-project/pull/86216 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][modules] Avoid calling expensive `SourceManager::translateFile()` (PR #86216)
@@ -1337,9 +1337,24 @@ static bool compileModule(CompilerInstance &ImportingInstance, // Get or create the module map that we'll use to build this module. ModuleMap &ModMap = ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap(); + SourceManager &SourceMgr = ImportingInstance.getSourceManager(); bool Result; - if (OptionalFileEntryRef ModuleMapFile = - ModMap.getContainingModuleMapFile(Module)) { + if (FileID ModuleMapFID = ModMap.getContainingModuleMapFileID(Module); + ModuleMapFID.isValid()) { +// We want to use the top-level module map. If we don't, the compiling jansvoboda11 wrote: Consider that `SourceManager::translateFile()` always prefers local `SLocEntries`. Now let's say that a module is defined in a module map that gets included via the `extern` directive from a top-level module map Clang find via header search. Before loading PCM for this module, the following code will resolve to the local `SLocEntry` (there are no loaded entries yet). ``` SourceManager::translateFile( SourceManager::getFileEntryRefForID( // ModuleMap::getContainingModuleMapFile(Module) SourceManager::getFileID( // Module::DefinitionLoc))) // ``` After compiling and loading the PCM for such module, `Module::DefinitionLoc` gets updated and now points into the loaded `SLocEntry`. Therefore, `ModuleMap::getContainingModuleMapFile(Module)` returns the loaded `SLocEntry`. Then, `SourceManager::translateFile()` maps that to the **local** `SLocEntry`, so we end up with a result identical to the previous one. This patch gets rid of the unnecessary conversions and does this instead. ``` SourceManager::getFileID(Module::DefinitionLoc))) ``` This means that after loading the PCM for the module, this points into the table of loaded `SLocEntries`. The importer knows that the containing module map is not a top level module map. When it attempts to walk up the include chain to get the the top-level module map for this module (using `SourceManager::getIncludeLoc()`) it gets an invalid `SourceLocation`. This is because the PCM was not compiled from the top-level module map, its `SourceManager` never knew about the file, and therefore can't walk up. This means that the true top-level module map never makes it into the set of affecting module maps we compute in `ASTWriter`. It's in turn left out from the `INPUT_FILE` block that only has the containing module map that's marked as not-top-level file. This ultimately breaks the dependency scanner. When generating `-fmodule-map-file=` arguments for the explicit compilation, it only uses files that made it into the `INPUT_FILE` block (are affecting) and are top-level (to avoid exploding the command line with transitive module maps). This then breaks the explicit compile, which doesn't have any (neither the top-level nor the containing module map) for the module in question. So this piece of code is here to ensure implicit builds are always invoked with the top-level module map, not the containing one. This fixes the walk over the include chain of loaded `SLocEntries` and fixes `clang/test/ClangScanDeps/modules-extern-unrelated.m`. https://github.com/llvm/llvm-project/pull/86216 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][modules] Avoid calling expensive `SourceManager::translateFile()` (PR #86216)
@@ -71,6 +71,7 @@ // CHECK-NEXT: "context-hash": "{{.*}}", // CHECK-NEXT: "file-deps": [ // CHECK-NEXT: "[[PREFIX]]/first/module.modulemap", +// CHECK-NEXT: "[[PREFIX]]/second/module.modulemap", benlangmuir wrote: Why did this change? https://github.com/llvm/llvm-project/pull/86216 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][modules] Avoid calling expensive `SourceManager::translateFile()` (PR #86216)
@@ -1337,9 +1337,24 @@ static bool compileModule(CompilerInstance &ImportingInstance, // Get or create the module map that we'll use to build this module. ModuleMap &ModMap = ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap(); + SourceManager &SourceMgr = ImportingInstance.getSourceManager(); bool Result; - if (OptionalFileEntryRef ModuleMapFile = - ModMap.getContainingModuleMapFile(Module)) { + if (FileID ModuleMapFID = ModMap.getContainingModuleMapFileID(Module); + ModuleMapFID.isValid()) { +// We want to use the top-level module map. If we don't, the compiling benlangmuir wrote: What is the connection between this change and the rest of the commit? https://github.com/llvm/llvm-project/pull/86216 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][modules] Avoid calling expensive `SourceManager::translateFile()` (PR #86216)
https://github.com/jansvoboda11 updated https://github.com/llvm/llvm-project/pull/86216 >From 4dd48b40a034edf0b124ab08055a334ad7abd5ba Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Thu, 21 Mar 2024 14:40:02 -0700 Subject: [PATCH 1/4] [clang][modules] Avoid calling expensive `SourceManager::translateFile()` --- clang/include/clang/Lex/ModuleMap.h | 15 +++--- clang/lib/Frontend/FrontendAction.cpp | 7 ++- clang/lib/Lex/ModuleMap.cpp | 66 +++ clang/lib/Serialization/ASTWriter.cpp | 23 +- 4 files changed, 61 insertions(+), 50 deletions(-) diff --git a/clang/include/clang/Lex/ModuleMap.h b/clang/include/clang/Lex/ModuleMap.h index 867cb6eab42f2d..2e28ff6823cb2a 100644 --- a/clang/include/clang/Lex/ModuleMap.h +++ b/clang/include/clang/Lex/ModuleMap.h @@ -263,8 +263,8 @@ class ModuleMap { Attributes Attrs; /// If \c InferModules is non-zero, the module map file that allowed -/// inferred modules. Otherwise, nullopt. -OptionalFileEntryRef ModuleMapFile; +/// inferred modules. Otherwise, invalid. +FileID ModuleMapFID; /// The names of modules that cannot be inferred within this /// directory. @@ -279,8 +279,7 @@ class ModuleMap { /// A mapping from an inferred module to the module map that allowed the /// inference. - // FIXME: Consider making the values non-optional. - llvm::DenseMap InferredModuleAllowedBy; + llvm::DenseMap InferredModuleAllowedBy; llvm::DenseMap AdditionalModMaps; @@ -618,8 +617,9 @@ class ModuleMap { /// /// \param Module The module whose module map file will be returned, if known. /// - /// \returns The file entry for the module map file containing the given - /// module, or nullptr if the module definition was inferred. + /// \returns The FileID for the module map file containing the given module, + /// invalid if the module definition was inferred. + FileID getContainingModuleMapFileID(const Module *Module) const; OptionalFileEntryRef getContainingModuleMapFile(const Module *Module) const; /// Get the module map file that (along with the module name) uniquely @@ -631,9 +631,10 @@ class ModuleMap { /// of inferred modules, returns the module map that allowed the inference /// (e.g. contained 'module *'). Otherwise, returns /// getContainingModuleMapFile(). + FileID getModuleMapFileIDForUniquing(const Module *M) const; OptionalFileEntryRef getModuleMapFileForUniquing(const Module *M) const; - void setInferredModuleAllowedBy(Module *M, OptionalFileEntryRef ModMap); + void setInferredModuleAllowedBy(Module *M, FileID ModMapFID); /// Canonicalize \p Path in a manner suitable for a module map file. In /// particular, this canonicalizes the parent directory separately from the diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index b9fd9b8897b7e7..bc4c901325c7e1 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -535,8 +535,13 @@ static Module *prepareToBuildModule(CompilerInstance &CI, if (*OriginalModuleMap != CI.getSourceManager().getFileEntryRefForID( CI.getSourceManager().getMainFileID())) { M->IsInferred = true; + bool IsSystem = false; // TODO: Propagate the real thing here. + auto FileCharacter = + IsSystem ? SrcMgr::C_System_ModuleMap : SrcMgr::C_User_ModuleMap; + FileID OriginalModuleMapFID = CI.getSourceManager().getOrCreateFileID( + *OriginalModuleMap, FileCharacter); CI.getPreprocessor().getHeaderSearchInfo().getModuleMap() -.setInferredModuleAllowedBy(M, *OriginalModuleMap); +.setInferredModuleAllowedBy(M, OriginalModuleMapFID); } } diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index 10c475f617d485..eed7eca2e73562 100644 --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -648,8 +648,7 @@ ModuleMap::findOrCreateModuleForHeaderInUmbrellaDir(FileEntryRef File) { UmbrellaModule = UmbrellaModule->Parent; if (UmbrellaModule->InferSubmodules) { - OptionalFileEntryRef UmbrellaModuleMap = - getModuleMapFileForUniquing(UmbrellaModule); + FileID UmbrellaModuleMap = getModuleMapFileIDForUniquing(UmbrellaModule); // Infer submodules for each of the directories we found between // the directory of the umbrella header and the directory where @@ -1021,7 +1020,7 @@ Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir, // If the framework has a parent path from which we're allowed to infer // a framework module, do so. - OptionalFileEntryRef ModuleMapFile; + FileID ModuleMapFID; if (!Parent) { // Determine whether we're allowed to infer a module map. bool canInfer = false; @@ -1060,7 +1059,7 @@ Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir, Attrs.IsExhaustive |= infer
[clang] [clang][modules] Avoid calling expensive `SourceManager::translateFile()` (PR #86216)
github-actions[bot] wrote: :white_check_mark: With the latest revision this PR passed the Python code formatter. https://github.com/llvm/llvm-project/pull/86216 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][modules] Avoid calling expensive `SourceManager::translateFile()` (PR #86216)
llvmbot wrote: @llvm/pr-subscribers-clang Author: Jan Svoboda (jansvoboda11) Changes 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). --- Full diff: https://github.com/llvm/llvm-project/pull/86216.diff 6 Files Affected: - (modified) clang/include/clang/Lex/ModuleMap.h (+8-7) - (modified) clang/lib/Frontend/CompilerInstance.cpp (+17-2) - (modified) clang/lib/Frontend/FrontendAction.cpp (+5-1) - (modified) clang/lib/Lex/ModuleMap.cpp (+36-30) - (modified) clang/lib/Serialization/ASTWriter.cpp (+8-9) - (modified) clang/test/ClangScanDeps/modules-extern-unrelated.m (+1) ``diff diff --git a/clang/include/clang/Lex/ModuleMap.h b/clang/include/clang/Lex/ModuleMap.h index 867cb6eab42f2d..2e28ff6823cb2a 100644 --- a/clang/include/clang/Lex/ModuleMap.h +++ b/clang/include/clang/Lex/ModuleMap.h @@ -263,8 +263,8 @@ class ModuleMap { Attributes Attrs; /// If \c InferModules is non-zero, the module map file that allowed -/// inferred modules. Otherwise, nullopt. -OptionalFileEntryRef ModuleMapFile; +/// inferred modules. Otherwise, invalid. +FileID ModuleMapFID; /// The names of modules that cannot be inferred within this /// directory. @@ -279,8 +279,7 @@ class ModuleMap { /// A mapping from an inferred module to the module map that allowed the /// inference. - // FIXME: Consider making the values non-optional. - llvm::DenseMap InferredModuleAllowedBy; + llvm::DenseMap InferredModuleAllowedBy; llvm::DenseMap AdditionalModMaps; @@ -618,8 +617,9 @@ class ModuleMap { /// /// \param Module The module whose module map file will be returned, if known. /// - /// \returns The file entry for the module map file containing the given - /// module, or nullptr if the module definition was inferred. + /// \returns The FileID for the module map file containing the given module, + /// invalid if the module definition was inferred. + FileID getContainingModuleMapFileID(const Module *Module) const; OptionalFileEntryRef getContainingModuleMapFile(const Module *Module) const; /// Get the module map file that (along with the module name) uniquely @@ -631,9 +631,10 @@ class ModuleMap { /// of inferred modules, returns the module map that allowed the inference /// (e.g. contained 'module *'). Otherwise, returns /// getContainingModuleMapFile(). + FileID getModuleMapFileIDForUniquing(const Module *M) const; OptionalFileEntryRef getModuleMapFileForUniquing(const Module *M) const; - void setInferredModuleAllowedBy(Module *M, OptionalFileEntryRef ModMap); + void setInferredModuleAllowedBy(Module *M, FileID ModMapFID); /// Canonicalize \p Path in a manner suitable for a module map file. In /// particular, this canonicalizes the parent directory separately from the diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 019f847ccbaad0..79ebb0ae0ee98f 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1337,9 +1337,24 @@ static bool compileModule(CompilerInstance &ImportingInstance, // Get or create the module map that we'll use to build this module. ModuleMap &ModMap = ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap(); + SourceManager &SourceMgr = ImportingInstance.getSourceManager(); bool Result; - if (OptionalFileEntryRef ModuleMapFile = - ModMap.getContainingModuleMapFile(Module)) { + if (FileID ModuleMapFID = ModMap.getContainingModuleMapFileID(Module); + ModuleMapFID.isValid()) { +// We want to use the top-level module map. If we don't, the compiling +// instance may think the containing module map is a top-level one, while +// the importing instance knows it's included from a parent module map via +// the extern directive. This mismatch could bite us later. +SourceLocation Loc = SourceMgr.getIncludeLoc(ModuleMapFID); +while (Loc.isValid() && isModuleMap(SourceMgr.getFileCharacteristic(Loc))) { + ModuleMapFID = SourceMgr.getFileID(Loc); + Loc = SourceMgr.getIncludeLoc(ModuleMapFID); +} + +OptionalFileEntryRef ModuleMapFile = +SourceMgr.getFileEntryRefForID(ModuleMapFID); +assert(ModuleMapFile && "Top-level module map with no FileID"); + // Canonicalize compilation to start with the pu
[clang] [clang][modules] Avoid calling expensive `SourceManager::translateFile()` (PR #86216)
https://github.com/jansvoboda11 ready_for_review https://github.com/llvm/llvm-project/pull/86216 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][modules] Avoid calling expensive `SourceManager::translateFile()` (PR #86216)
https://github.com/jansvoboda11 updated https://github.com/llvm/llvm-project/pull/86216 >From 4dd48b40a034edf0b124ab08055a334ad7abd5ba Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Thu, 21 Mar 2024 14:40:02 -0700 Subject: [PATCH 1/3] [clang][modules] Avoid calling expensive `SourceManager::translateFile()` --- clang/include/clang/Lex/ModuleMap.h | 15 +++--- clang/lib/Frontend/FrontendAction.cpp | 7 ++- clang/lib/Lex/ModuleMap.cpp | 66 +++ clang/lib/Serialization/ASTWriter.cpp | 23 +- 4 files changed, 61 insertions(+), 50 deletions(-) diff --git a/clang/include/clang/Lex/ModuleMap.h b/clang/include/clang/Lex/ModuleMap.h index 867cb6eab42f2d..2e28ff6823cb2a 100644 --- a/clang/include/clang/Lex/ModuleMap.h +++ b/clang/include/clang/Lex/ModuleMap.h @@ -263,8 +263,8 @@ class ModuleMap { Attributes Attrs; /// If \c InferModules is non-zero, the module map file that allowed -/// inferred modules. Otherwise, nullopt. -OptionalFileEntryRef ModuleMapFile; +/// inferred modules. Otherwise, invalid. +FileID ModuleMapFID; /// The names of modules that cannot be inferred within this /// directory. @@ -279,8 +279,7 @@ class ModuleMap { /// A mapping from an inferred module to the module map that allowed the /// inference. - // FIXME: Consider making the values non-optional. - llvm::DenseMap InferredModuleAllowedBy; + llvm::DenseMap InferredModuleAllowedBy; llvm::DenseMap AdditionalModMaps; @@ -618,8 +617,9 @@ class ModuleMap { /// /// \param Module The module whose module map file will be returned, if known. /// - /// \returns The file entry for the module map file containing the given - /// module, or nullptr if the module definition was inferred. + /// \returns The FileID for the module map file containing the given module, + /// invalid if the module definition was inferred. + FileID getContainingModuleMapFileID(const Module *Module) const; OptionalFileEntryRef getContainingModuleMapFile(const Module *Module) const; /// Get the module map file that (along with the module name) uniquely @@ -631,9 +631,10 @@ class ModuleMap { /// of inferred modules, returns the module map that allowed the inference /// (e.g. contained 'module *'). Otherwise, returns /// getContainingModuleMapFile(). + FileID getModuleMapFileIDForUniquing(const Module *M) const; OptionalFileEntryRef getModuleMapFileForUniquing(const Module *M) const; - void setInferredModuleAllowedBy(Module *M, OptionalFileEntryRef ModMap); + void setInferredModuleAllowedBy(Module *M, FileID ModMapFID); /// Canonicalize \p Path in a manner suitable for a module map file. In /// particular, this canonicalizes the parent directory separately from the diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index b9fd9b8897b7e7..bc4c901325c7e1 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -535,8 +535,13 @@ static Module *prepareToBuildModule(CompilerInstance &CI, if (*OriginalModuleMap != CI.getSourceManager().getFileEntryRefForID( CI.getSourceManager().getMainFileID())) { M->IsInferred = true; + bool IsSystem = false; // TODO: Propagate the real thing here. + auto FileCharacter = + IsSystem ? SrcMgr::C_System_ModuleMap : SrcMgr::C_User_ModuleMap; + FileID OriginalModuleMapFID = CI.getSourceManager().getOrCreateFileID( + *OriginalModuleMap, FileCharacter); CI.getPreprocessor().getHeaderSearchInfo().getModuleMap() -.setInferredModuleAllowedBy(M, *OriginalModuleMap); +.setInferredModuleAllowedBy(M, OriginalModuleMapFID); } } diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index 10c475f617d485..eed7eca2e73562 100644 --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -648,8 +648,7 @@ ModuleMap::findOrCreateModuleForHeaderInUmbrellaDir(FileEntryRef File) { UmbrellaModule = UmbrellaModule->Parent; if (UmbrellaModule->InferSubmodules) { - OptionalFileEntryRef UmbrellaModuleMap = - getModuleMapFileForUniquing(UmbrellaModule); + FileID UmbrellaModuleMap = getModuleMapFileIDForUniquing(UmbrellaModule); // Infer submodules for each of the directories we found between // the directory of the umbrella header and the directory where @@ -1021,7 +1020,7 @@ Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir, // If the framework has a parent path from which we're allowed to infer // a framework module, do so. - OptionalFileEntryRef ModuleMapFile; + FileID ModuleMapFID; if (!Parent) { // Determine whether we're allowed to infer a module map. bool canInfer = false; @@ -1060,7 +1059,7 @@ Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir, Attrs.IsExhaustive |= infer
[clang] [clang][modules] Avoid calling expensive `SourceManager::translateFile()` (PR #86216)
github-actions[bot] wrote: :warning: C/C++ code formatter, clang-format found issues in your code. :warning: You can test this locally with the following command: ``bash git-clang-format --diff 6b1cf0040059c407264d2609403c4fc090673167 4dd48b40a034edf0b124ab08055a334ad7abd5ba -- clang/include/clang/Lex/ModuleMap.h clang/lib/Frontend/FrontendAction.cpp clang/lib/Lex/ModuleMap.cpp clang/lib/Serialization/ASTWriter.cpp `` View the diff from clang-format here. ``diff diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index bc4c901325..5921a8c065 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -540,8 +540,10 @@ static Module *prepareToBuildModule(CompilerInstance &CI, IsSystem ? SrcMgr::C_System_ModuleMap : SrcMgr::C_User_ModuleMap; FileID OriginalModuleMapFID = CI.getSourceManager().getOrCreateFileID( *OriginalModuleMap, FileCharacter); - CI.getPreprocessor().getHeaderSearchInfo().getModuleMap() -.setInferredModuleAllowedBy(M, OriginalModuleMapFID); + CI.getPreprocessor() + .getHeaderSearchInfo() + .getModuleMap() + .setInferredModuleAllowedBy(M, OriginalModuleMapFID); } } `` https://github.com/llvm/llvm-project/pull/86216 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang][modules] Avoid calling expensive `SourceManager::translateFile()` (PR #86216)
https://github.com/jansvoboda11 created https://github.com/llvm/llvm-project/pull/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). >From 4dd48b40a034edf0b124ab08055a334ad7abd5ba Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Thu, 21 Mar 2024 14:40:02 -0700 Subject: [PATCH] [clang][modules] Avoid calling expensive `SourceManager::translateFile()` --- clang/include/clang/Lex/ModuleMap.h | 15 +++--- clang/lib/Frontend/FrontendAction.cpp | 7 ++- clang/lib/Lex/ModuleMap.cpp | 66 +++ clang/lib/Serialization/ASTWriter.cpp | 23 +- 4 files changed, 61 insertions(+), 50 deletions(-) diff --git a/clang/include/clang/Lex/ModuleMap.h b/clang/include/clang/Lex/ModuleMap.h index 867cb6eab42f2d..2e28ff6823cb2a 100644 --- a/clang/include/clang/Lex/ModuleMap.h +++ b/clang/include/clang/Lex/ModuleMap.h @@ -263,8 +263,8 @@ class ModuleMap { Attributes Attrs; /// If \c InferModules is non-zero, the module map file that allowed -/// inferred modules. Otherwise, nullopt. -OptionalFileEntryRef ModuleMapFile; +/// inferred modules. Otherwise, invalid. +FileID ModuleMapFID; /// The names of modules that cannot be inferred within this /// directory. @@ -279,8 +279,7 @@ class ModuleMap { /// A mapping from an inferred module to the module map that allowed the /// inference. - // FIXME: Consider making the values non-optional. - llvm::DenseMap InferredModuleAllowedBy; + llvm::DenseMap InferredModuleAllowedBy; llvm::DenseMap AdditionalModMaps; @@ -618,8 +617,9 @@ class ModuleMap { /// /// \param Module The module whose module map file will be returned, if known. /// - /// \returns The file entry for the module map file containing the given - /// module, or nullptr if the module definition was inferred. + /// \returns The FileID for the module map file containing the given module, + /// invalid if the module definition was inferred. + FileID getContainingModuleMapFileID(const Module *Module) const; OptionalFileEntryRef getContainingModuleMapFile(const Module *Module) const; /// Get the module map file that (along with the module name) uniquely @@ -631,9 +631,10 @@ class ModuleMap { /// of inferred modules, returns the module map that allowed the inference /// (e.g. contained 'module *'). Otherwise, returns /// getContainingModuleMapFile(). + FileID getModuleMapFileIDForUniquing(const Module *M) const; OptionalFileEntryRef getModuleMapFileForUniquing(const Module *M) const; - void setInferredModuleAllowedBy(Module *M, OptionalFileEntryRef ModMap); + void setInferredModuleAllowedBy(Module *M, FileID ModMapFID); /// Canonicalize \p Path in a manner suitable for a module map file. In /// particular, this canonicalizes the parent directory separately from the diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index b9fd9b8897b7e7..bc4c901325c7e1 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -535,8 +535,13 @@ static Module *prepareToBuildModule(CompilerInstance &CI, if (*OriginalModuleMap != CI.getSourceManager().getFileEntryRefForID( CI.getSourceManager().getMainFileID())) { M->IsInferred = true; + bool IsSystem = false; // TODO: Propagate the real thing here. + auto FileCharacter = + IsSystem ? SrcMgr::C_System_ModuleMap : SrcMgr::C_User_ModuleMap; + FileID OriginalModuleMapFID = CI.getSourceManager().getOrCreateFileID( + *OriginalModuleMap, FileCharacter); CI.getPreprocessor().getHeaderSearchInfo().getModuleMap() -.setInferredModuleAllowedBy(M, *OriginalModuleMap); +.setInferredModuleAllowedBy(M, OriginalModuleMapFID); } } diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index 10c475f617d485..eed7eca2e73562 100644 --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -648,8 +648,7 @@ ModuleMap::findOrCreateModuleForHeaderInUmbrellaDir(FileEntryRef File) { UmbrellaModule = UmbrellaModule->Parent; if (UmbrellaModule->InferSubmodules) { - OptionalFileEntryRef UmbrellaModuleMap = - getModuleMapFileForUniquing(UmbrellaModule); + FileID UmbrellaModuleMap = getModuleMapFileIDForUniquing