Skip to content

[clang][modules] Optimize construction and usage of the submodule index #113391

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions clang/include/clang/Basic/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ class alignas(8) Module {

/// A mapping from the submodule name to the index into the
/// \c SubModules vector at which that submodule resides.
llvm::StringMap<unsigned> SubModuleIndex;
mutable llvm::StringMap<unsigned> SubModuleIndex;

/// The AST file if this is a top-level module which has a
/// corresponding serialized AST file, or null otherwise.
Expand Down Expand Up @@ -612,7 +612,6 @@ class alignas(8) Module {
void setParent(Module *M) {
assert(!Parent);
Parent = M;
Parent->SubModuleIndex[Name] = Parent->SubModules.size();
Parent->SubModules.push_back(this);
}

Expand Down
13 changes: 8 additions & 5 deletions clang/include/clang/Lex/ModuleMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -541,11 +541,14 @@ class ModuleMap {
///
/// \param IsExplicit Whether this is an explicit submodule.
///
/// \returns The found or newly-created module, along with a boolean value
/// that will be true if the module is newly-created.
std::pair<Module *, bool> findOrCreateModule(StringRef Name, Module *Parent,
bool IsFramework,
bool IsExplicit);
/// \returns The found or newly-created module.
Module *findOrCreateModule(StringRef Name, Module *Parent, bool IsFramework,
bool IsExplicit);
/// Create new submodule, assuming it does not exist. This function can only
/// be called when it is guaranteed that this submodule does not exist yet.
/// The parameters have same semantics as \c ModuleMap::findOrCreateModule.
Module *createModule(StringRef Name, Module *Parent, bool IsFramework,
bool IsExplicit);

/// Create a global module fragment for a C++ module unit.
///
Expand Down
12 changes: 7 additions & 5 deletions clang/lib/Basic/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ Module::Module(ModuleConstructorTag, StringRef Name,
NoUndeclaredIncludes = Parent->NoUndeclaredIncludes;
ModuleMapIsPrivate = Parent->ModuleMapIsPrivate;

Parent->SubModuleIndex[Name] = Parent->SubModules.size();
Parent->SubModules.push_back(this);
}
}
Expand Down Expand Up @@ -351,11 +350,14 @@ void Module::markUnavailable(bool Unimportable) {
}

Module *Module::findSubmodule(StringRef Name) const {
llvm::StringMap<unsigned>::const_iterator Pos = SubModuleIndex.find(Name);
if (Pos == SubModuleIndex.end())
return nullptr;
// Add new submodules into the index.
for (unsigned I = SubModuleIndex.size(), E = SubModules.size(); I != E; ++I)
SubModuleIndex[SubModules[I]->Name] = I;

return SubModules[Pos->getValue()];
if (auto It = SubModuleIndex.find(Name); It != SubModuleIndex.end())
return SubModules[It->second];

return nullptr;
}

Module *Module::getGlobalModuleFragment() const {
Expand Down
29 changes: 17 additions & 12 deletions clang/lib/Lex/ModuleMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -655,8 +655,8 @@ ModuleMap::findOrCreateModuleForHeaderInUmbrellaDir(FileEntryRef File) {
SmallString<32> NameBuf;
StringRef Name = sanitizeFilenameAsIdentifier(
llvm::sys::path::stem(SkippedDir.getName()), NameBuf);
Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
Explicit).first;
Result =
findOrCreateModule(Name, Result, /*IsFramework=*/false, Explicit);
setInferredModuleAllowedBy(Result, UmbrellaModuleMap);

// Associate the module and the directory.
Expand All @@ -672,8 +672,8 @@ ModuleMap::findOrCreateModuleForHeaderInUmbrellaDir(FileEntryRef File) {
SmallString<32> NameBuf;
StringRef Name = sanitizeFilenameAsIdentifier(
llvm::sys::path::stem(File.getName()), NameBuf);
Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
Explicit).first;
Result =
findOrCreateModule(Name, Result, /*IsFramework=*/false, Explicit);
setInferredModuleAllowedBy(Result, UmbrellaModuleMap);
Result->addTopHeader(File);

Expand Down Expand Up @@ -857,15 +857,21 @@ Module *ModuleMap::lookupModuleQualified(StringRef Name, Module *Context) const{
return Context->findSubmodule(Name);
}

std::pair<Module *, bool> ModuleMap::findOrCreateModule(StringRef Name,
Module *Parent,
bool IsFramework,
bool IsExplicit) {
Module *ModuleMap::findOrCreateModule(StringRef Name, Module *Parent,
bool IsFramework, bool IsExplicit) {
// Try to find an existing module with this name.
if (Module *Sub = lookupModuleQualified(Name, Parent))
return std::make_pair(Sub, false);
return Sub;

// Create a new module with this name.
return createModule(Name, Parent, IsFramework, IsExplicit);
}

Module *ModuleMap::createModule(StringRef Name, Module *Parent,
bool IsFramework, bool IsExplicit) {
assert(lookupModuleQualified(Name, Parent) == nullptr &&
"Creating duplicate submodule");

Module *Result = new (ModulesAlloc.Allocate())
Module(ModuleConstructorTag{}, Name, SourceLocation(), Parent,
IsFramework, IsExplicit, NumCreatedModules++);
Expand All @@ -875,7 +881,7 @@ std::pair<Module *, bool> ModuleMap::findOrCreateModule(StringRef Name,
Modules[Name] = Result;
ModuleScopeIDs[Result] = CurrentModuleScopeID;
}
return std::make_pair(Result, true);
return Result;
}

Module *ModuleMap::createGlobalModuleFragmentForModuleUnit(SourceLocation Loc,
Expand Down Expand Up @@ -2124,8 +2130,7 @@ void ModuleMapParser::parseModuleDecl() {
Map.createShadowedModule(ModuleName, Framework, ShadowingModule);
} else {
ActiveModule =
Map.findOrCreateModule(ModuleName, ActiveModule, Framework, Explicit)
.first;
Map.findOrCreateModule(ModuleName, ActiveModule, Framework, Explicit);
}

ActiveModule->DefinitionLoc = ModuleNameLoc;
Expand Down
14 changes: 9 additions & 5 deletions clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5756,6 +5756,13 @@ llvm::Error ASTReader::ReadSubmoduleBlock(ModuleFile &F,
return Err;

ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap();
bool KnowsTopLevelModule = ModMap.findModule(F.ModuleName) != nullptr;
// If we don't know the top-level module, there's no point in doing qualified
// lookup of its submodules; it won't find anything anywhere within this tree.
// Let's skip that and avoid some string lookups.
auto CreateModule = !KnowsTopLevelModule ? &ModuleMap::createModule
: &ModuleMap::findOrCreateModule;

bool First = true;
Module *CurrentModule = nullptr;
RecordData Record;
Expand Down Expand Up @@ -5829,11 +5836,8 @@ llvm::Error ASTReader::ReadSubmoduleBlock(ModuleFile &F,
if (Parent)
ParentModule = getSubmodule(Parent);

// Retrieve this (sub)module from the module map, creating it if
// necessary.
CurrentModule =
ModMap.findOrCreateModule(Name, ParentModule, IsFramework, IsExplicit)
.first;
CurrentModule = std::invoke(CreateModule, &ModMap, Name, ParentModule,
IsFramework, IsExplicit);

SubmoduleID GlobalIndex = GlobalID - NUM_PREDEF_SUBMODULE_IDS;
if (GlobalIndex >= SubmodulesLoaded.size() ||
Expand Down
Loading