https://github.com/jansvoboda11 created https://github.com/llvm/llvm-project/pull/112795
In `clang-scan-deps`, we're creating lots of `Module` instances. Allocating them all in a bump-pointer allocator reduces the number of retired instructions by 1-1.5% on my workload. >From 7e00bbe74f71c55dfd3e3a75d4459187a90f6426 Mon Sep 17 00:00:00 2001 From: Jan Svoboda <jan_svob...@apple.com> Date: Thu, 17 Oct 2024 15:26:18 -0700 Subject: [PATCH] [clang] Allocate `Module` instances in `BumpPtrAllocator` --- clang/include/clang/Basic/Module.h | 16 +++++-- clang/include/clang/Lex/ModuleMap.h | 9 +++- clang/lib/Basic/Module.cpp | 26 ++--------- clang/lib/Lex/ModuleMap.cpp | 72 +++++++++++++++++------------ clang/lib/Lex/Pragma.cpp | 3 +- 5 files changed, 68 insertions(+), 58 deletions(-) diff --git a/clang/include/clang/Basic/Module.h b/clang/include/clang/Basic/Module.h index e86f4303d732b8..9c5d33fbb562cc 100644 --- a/clang/include/clang/Basic/Module.h +++ b/clang/include/clang/Basic/Module.h @@ -48,6 +48,7 @@ namespace clang { class FileManager; class LangOptions; +class ModuleMap; class TargetInfo; /// Describes the name of a module. @@ -99,6 +100,15 @@ struct ASTFileSignature : std::array<uint8_t, 20> { } }; +/// Required to construct a Module. +/// +/// This tag type is only constructible by ModuleMap, guaranteeing it ownership +/// of all Module instances. +class ModuleConstructorTag { + explicit ModuleConstructorTag() = default; + friend ModuleMap; +}; + /// Describes a module or submodule. /// /// Aligned to 8 bytes to allow for llvm::PointerIntPair<Module *, 3>. @@ -497,8 +507,9 @@ class alignas(8) Module { std::vector<Conflict> Conflicts; /// Construct a new module or submodule. - Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent, - bool IsFramework, bool IsExplicit, unsigned VisibilityID); + Module(ModuleConstructorTag, StringRef Name, SourceLocation DefinitionLoc, + Module *Parent, bool IsFramework, bool IsExplicit, + unsigned VisibilityID); ~Module(); @@ -749,7 +760,6 @@ class alignas(8) Module { /// /// \returns The submodule if found, or NULL otherwise. Module *findSubmodule(StringRef Name) const; - Module *findOrInferSubmodule(StringRef Name); /// Get the Global Module Fragment (sub-module) for this module, it there is /// one. diff --git a/clang/include/clang/Lex/ModuleMap.h b/clang/include/clang/Lex/ModuleMap.h index 2e28ff6823cb2a..75b567a347cb6c 100644 --- a/clang/include/clang/Lex/ModuleMap.h +++ b/clang/include/clang/Lex/ModuleMap.h @@ -93,9 +93,12 @@ class ModuleMap { /// named LangOpts::CurrentModule, if we've loaded it). Module *SourceModule = nullptr; + /// The allocator for all (sub)modules. + llvm::SpecificBumpPtrAllocator<Module> ModulesAlloc; + /// Submodules of the current module that have not yet been attached to it. - /// (Ownership is transferred if/when we create an enclosing module.) - llvm::SmallVector<std::unique_ptr<Module>, 8> PendingSubmodules; + /// (Relationship is set up if/when we create an enclosing module.) + llvm::SmallVector<Module *, 8> PendingSubmodules; /// The top-level modules that are known. llvm::StringMap<Module *> Modules; @@ -502,6 +505,8 @@ class ModuleMap { /// \returns The named module, if known; otherwise, returns null. Module *findModule(StringRef Name) const; + Module *findOrInferSubmodule(Module *Parent, StringRef Name); + /// Retrieve a module with the given name using lexical name lookup, /// starting at the given context. /// diff --git a/clang/lib/Basic/Module.cpp b/clang/lib/Basic/Module.cpp index fee372bce3a367..ad52fccff5dc7f 100644 --- a/clang/lib/Basic/Module.cpp +++ b/clang/lib/Basic/Module.cpp @@ -34,8 +34,9 @@ using namespace clang; -Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent, - bool IsFramework, bool IsExplicit, unsigned VisibilityID) +Module::Module(ModuleConstructorTag, StringRef Name, + SourceLocation DefinitionLoc, Module *Parent, bool IsFramework, + bool IsExplicit, unsigned VisibilityID) : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent), VisibilityID(VisibilityID), IsUnimportable(false), HasIncompatibleModuleFile(false), IsAvailable(true), @@ -58,11 +59,7 @@ Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent, } } -Module::~Module() { - for (auto *Submodule : SubModules) { - delete Submodule; - } -} +Module::~Module() = default; static bool isPlatformEnvironment(const TargetInfo &Target, StringRef Feature) { StringRef Platform = Target.getPlatformName(); @@ -361,21 +358,6 @@ Module *Module::findSubmodule(StringRef Name) const { return SubModules[Pos->getValue()]; } -Module *Module::findOrInferSubmodule(StringRef Name) { - llvm::StringMap<unsigned>::const_iterator Pos = SubModuleIndex.find(Name); - if (Pos != SubModuleIndex.end()) - return SubModules[Pos->getValue()]; - if (!InferSubmodules) - return nullptr; - Module *Result = new Module(Name, SourceLocation(), this, false, InferExplicitSubmodules, 0); - Result->InferExplicitSubmodules = InferExplicitSubmodules; - Result->InferSubmodules = InferSubmodules; - Result->InferExportWildcard = InferExportWildcard; - if (Result->InferExportWildcard) - Result->Exports.push_back(Module::ExportDecl(nullptr, true)); - return Result; -} - Module *Module::getGlobalModuleFragment() const { assert(isNamedModuleUnit() && "We should only query the global module " "fragment from the C++20 Named modules"); diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index 2aada51c71c503..fd6bc17ae9cdac 100644 --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -362,12 +362,7 @@ ModuleMap::ModuleMap(SourceManager &SourceMgr, DiagnosticsEngine &Diags, MMapLangOpts.LineComment = true; } -ModuleMap::~ModuleMap() { - for (auto &M : Modules) - delete M.getValue(); - for (auto *M : ShadowModules) - delete M; -} +ModuleMap::~ModuleMap() = default; void ModuleMap::setTarget(const TargetInfo &Target) { assert((!this->Target || this->Target == &Target) && @@ -831,6 +826,22 @@ Module *ModuleMap::findModule(StringRef Name) const { return nullptr; } +Module *ModuleMap::findOrInferSubmodule(Module *Parent, StringRef Name) { + if (Module *SubM = Parent->findSubmodule(Name)) + return SubM; + if (!Parent->InferSubmodules) + return nullptr; + Module *Result = new (ModulesAlloc.Allocate()) + Module(ModuleConstructorTag{}, Name, SourceLocation(), Parent, false, + Parent->InferExplicitSubmodules, 0); + Result->InferExplicitSubmodules = Parent->InferExplicitSubmodules; + Result->InferSubmodules = Parent->InferSubmodules; + Result->InferExportWildcard = Parent->InferExportWildcard; + if (Result->InferExportWildcard) + Result->Exports.push_back(Module::ExportDecl(nullptr, true)); + return Result; +} + Module *ModuleMap::lookupModuleUnqualified(StringRef Name, Module *Context) const { for(; Context; Context = Context->Parent) { @@ -857,8 +868,9 @@ std::pair<Module *, bool> ModuleMap::findOrCreateModule(StringRef Name, return std::make_pair(Sub, false); // Create a new module with this name. - Module *Result = new Module(Name, SourceLocation(), Parent, IsFramework, - IsExplicit, NumCreatedModules++); + Module *Result = new (ModulesAlloc.Allocate()) + Module(ModuleConstructorTag{}, Name, SourceLocation(), Parent, + IsFramework, IsExplicit, NumCreatedModules++); if (!Parent) { if (LangOpts.CurrentModule == Name) SourceModule = Result; @@ -870,8 +882,9 @@ std::pair<Module *, bool> ModuleMap::findOrCreateModule(StringRef Name, Module *ModuleMap::createGlobalModuleFragmentForModuleUnit(SourceLocation Loc, Module *Parent) { - auto *Result = new Module("<global>", Loc, Parent, /*IsFramework*/ false, - /*IsExplicit*/ true, NumCreatedModules++); + auto *Result = new (ModulesAlloc.Allocate()) Module( + ModuleConstructorTag{}, "<global>", Loc, Parent, /*IsFramework=*/false, + /*IsExplicit=*/true, NumCreatedModules++); Result->Kind = Module::ExplicitGlobalModuleFragment; // If the created module isn't owned by a parent, send it to PendingSubmodules // to wait for its parent. @@ -888,9 +901,9 @@ ModuleMap::createImplicitGlobalModuleFragmentForModuleUnit(SourceLocation Loc, // Note: Here the `IsExplicit` parameter refers to the semantics in clang // modules. All the non-explicit submodules in clang modules will be exported // too. Here we simplify the implementation by using the concept. - auto *Result = - new Module("<implicit global>", Loc, Parent, /*IsFramework=*/false, - /*IsExplicit=*/false, NumCreatedModules++); + auto *Result = new (ModulesAlloc.Allocate()) + Module(ModuleConstructorTag{}, "<implicit global>", Loc, Parent, + /*IsFramework=*/false, /*IsExplicit=*/false, NumCreatedModules++); Result->Kind = Module::ImplicitGlobalModuleFragment; return Result; } @@ -898,25 +911,23 @@ ModuleMap::createImplicitGlobalModuleFragmentForModuleUnit(SourceLocation Loc, Module * ModuleMap::createPrivateModuleFragmentForInterfaceUnit(Module *Parent, SourceLocation Loc) { - auto *Result = - new Module("<private>", Loc, Parent, /*IsFramework*/ false, - /*IsExplicit*/ true, NumCreatedModules++); + auto *Result = new (ModulesAlloc.Allocate()) Module( + ModuleConstructorTag{}, "<private>", Loc, Parent, /*IsFramework=*/false, + /*IsExplicit=*/true, NumCreatedModules++); Result->Kind = Module::PrivateModuleFragment; return Result; } Module *ModuleMap::createModuleUnitWithKind(SourceLocation Loc, StringRef Name, Module::ModuleKind Kind) { - auto *Result = - new Module(Name, Loc, nullptr, /*IsFramework*/ false, - /*IsExplicit*/ false, NumCreatedModules++); + auto *Result = new (ModulesAlloc.Allocate()) + Module(ModuleConstructorTag{}, Name, Loc, nullptr, /*IsFramework=*/false, + /*IsExplicit=*/false, NumCreatedModules++); Result->Kind = Kind; // Reparent any current global module fragment as a submodule of this module. - for (auto &Submodule : PendingSubmodules) { + for (auto &Submodule : PendingSubmodules) Submodule->setParent(Result); - Submodule.release(); // now owned by parent - } PendingSubmodules.clear(); return Result; } @@ -968,8 +979,9 @@ Module *ModuleMap::createHeaderUnit(SourceLocation Loc, StringRef Name, assert(LangOpts.CurrentModule == Name && "module name mismatch"); assert(!Modules[Name] && "redefining existing module"); - auto *Result = new Module(Name, Loc, nullptr, /*IsFramework*/ false, - /*IsExplicit*/ false, NumCreatedModules++); + auto *Result = new (ModulesAlloc.Allocate()) + Module(ModuleConstructorTag{}, Name, Loc, nullptr, /*IsFramework=*/false, + /*IsExplicit=*/false, NumCreatedModules++); Result->Kind = Module::ModuleHeaderUnit; Modules[Name] = SourceModule = Result; addHeader(Result, H, NormalHeader); @@ -1082,9 +1094,9 @@ Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir, if (!UmbrellaHeader) return nullptr; - Module *Result = new Module(ModuleName, SourceLocation(), Parent, - /*IsFramework=*/true, /*IsExplicit=*/false, - NumCreatedModules++); + Module *Result = new (ModulesAlloc.Allocate()) + Module(ModuleConstructorTag{}, ModuleName, SourceLocation(), Parent, + /*IsFramework=*/true, /*IsExplicit=*/false, NumCreatedModules++); InferredModuleAllowedBy[Result] = ModuleMapFID; Result->IsInferred = true; if (!Parent) { @@ -1173,9 +1185,9 @@ Module *ModuleMap::createShadowedModule(StringRef Name, bool IsFramework, Module *ShadowingModule) { // Create a new module with this name. - Module *Result = - new Module(Name, SourceLocation(), /*Parent=*/nullptr, IsFramework, - /*IsExplicit=*/false, NumCreatedModules++); + Module *Result = new (ModulesAlloc.Allocate()) + Module(ModuleConstructorTag{}, Name, SourceLocation(), /*Parent=*/nullptr, + IsFramework, /*IsExplicit=*/false, NumCreatedModules++); Result->ShadowingModule = ShadowingModule; Result->markUnavailable(/*Unimportable*/true); ModuleScopeIDs[Result] = CurrentModuleScopeID; diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp index 10f0ab7180e62d..6ec63b91df4bec 100644 --- a/clang/lib/Lex/Pragma.cpp +++ b/clang/lib/Lex/Pragma.cpp @@ -1752,6 +1752,7 @@ struct PragmaModuleBeginHandler : public PragmaHandler { // Find the module we're entering. We require that a module map for it // be loaded or implicitly loadable. auto &HSI = PP.getHeaderSearchInfo(); + auto &MM = HSI.getModuleMap(); Module *M = HSI.lookupModule(Current, ModuleName.front().second); if (!M) { PP.Diag(ModuleName.front().second, @@ -1759,7 +1760,7 @@ struct PragmaModuleBeginHandler : public PragmaHandler { return; } for (unsigned I = 1; I != ModuleName.size(); ++I) { - auto *NewM = M->findOrInferSubmodule(ModuleName[I].first->getName()); + auto *NewM = MM.findOrInferSubmodule(M, ModuleName[I].first->getName()); if (!NewM) { PP.Diag(ModuleName[I].second, diag::err_pp_module_begin_no_submodule) << M->getFullModuleName() << ModuleName[I].first; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits