[C++20][Modules] Improve namespace look-up performance for modules. (Attempt #2)#177255
[C++20][Modules] Improve namespace look-up performance for modules. (Attempt #2)#177255
Conversation
…odules. (llvm#171769)" (llvm#174783) This reverts commit c6e0e7d.
|
@llvm/pr-subscribers-clang-modules @llvm/pr-subscribers-clang Author: Michael Park (mpark) ChangesThis is a reapplication of #171769 which was reverted in #174783. This adds TL;DR: Problem Surfaced in the ReproThe repro copied inline here: // RUN: rm -rf %t
// RUN: mkdir -p %t
// RUN: split-file %s %t
// RUN: cd %t
//
// RUN: %clang_cc1 -fmodule-name=A -fno-cxx-modules -xc++ -emit-module \
// RUN: -fmodules A.cppmap -o A.pcm
// RUN: %clang_cc1 -fmodule-name=B -fno-cxx-modules -xc++ -emit-module \
// RUN: -fmodules -fmodule-file=A.pcm B.cppmap -o B.pcm
// RUN: %clang_cc1 -fmodule-name=C -fno-cxx-modules -xc++ -emit-module \
// RUN: -fmodules C.cppmap -o C.pcm
// RUN: %clang_cc1 -fmodule-name=D -fno-cxx-modules -xc++ -emit-module \
// RUN: -fmodules -fmodule-file=C.pcm D.cppmap -o D.pcm
// RUN: %clang_cc1 -fmodule-name=E -fno-cxx-modules -xc++ -emit-module \
// RUN: -fmodules -fmodule-file=B.pcm E.cppmap -o E.pcm
// RUN: %clang_cc1 -fmodule-name=F -fno-cxx-modules -xc++ -emit-module \
// RUN: -fmodules -fmodule-file=D.pcm F.cppmap -o F.pcm
// RUN: %clang_cc1 -fmodule-name=G -fno-cxx-modules -xc++ -emit-module \
// RUN: -fmodules -fmodule-file=E.pcm -fmodule-file=F.pcm G.cppmap -o G.pcm
// RUN: %clang_cc1 -fno-cxx-modules -fmodules -fmodule-file=G.pcm src.cpp \
// RUN: -o /dev/null
//--- A.cppmap
module "A" { header "A.h" }
//--- A.h
int x;
//--- B.cppmap
module "B" {}
//--- C.cppmap
module "C" { header "C.h" }
//--- C.h
namespace xyz {}
//--- D.cppmap
module "D" {}
//--- E.cppmap
module "E" {}
//--- F.cppmap
module "F" { header "F.h" }
//--- F.h
namespace xyz { inline void func() {} }
//--- G.cppmap
module "G" { header "G.h" }
//--- G.h
#include "F.h"
namespace { void func2() { xyz::func(); } }
//--- hdr.h
#include "F.h"
namespace xyz_ns = xyz;
//--- src.cpp
#include "hdr.h"When we go to build module The main strategy is still the same, but with a tweak to the AST writing half of the problem. In #171769 I wrote about how we can use the > The other half of the problem is to write out all of the external namespaces that we used to store in However, it turns out this is insufficient. Specifically, population of I introduced The Issue of Merging
|
3e484e7 to
28585e0
Compare
|
I can't say anything about the implementation, but I patched this in and all failures we saw last time still build w/ this. So correctness-wise, this should be fine. I did see some longer compilation times on one file (151s -> 225s), but it's a pathologically large input (a generated file), so it's possible that was just a fluke, e.g. ran on a slow build machine. |
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/128/builds/10261 Here is the relevant piece of the build log for the reference |
This is a reapplication of #171769 which was reverted in #174783. This adds
clang/test/Modules/pr171769.cppwhich is a repro provided by @rupprecht .TL;DR:
forEachImportedKeyDeclsis insufficient to iterate over the decls of each module we need to emit. This PR uses an existing logicCollectFirstDeclFromEachModuleinASTWriterDecl.cppinstead to collect all the decls we need from the modules involved.Problem Surfaced in the Repro
The repro copied inline here:
When we go to build module
G, before #171769 it emitted bothC::xyzandF::xyz. After #171769 it started to only emitC::xyzwithoutF::xyz. This is the core of what is addressed in this PR.The main strategy is still the same, but with a tweak to the AST writing half of the problem. In #171769 I wrote about how we can use the
KeyDeclsdata structure:However, it turns out this is insufficient. Specifically, population of
KeyDeclsdoes not account for unimported modules in the dependency properly. We need to use a strategy already used inASTWriterDecl.cpp, which is toCollectFirstDeclFromEachModuleand emit those instead. For example, in building moduleG, I would've expectedforEachImportedKeyDeclsto visitF::xyzas well asC::xyz. But becauseCis transitively baked into moduleFwithout actually being imported anywhere, it gets pulled in throughFwhereF::xyzis considered a redecl ofC::xyz. So in buildingG,forEachImportedKeyDeclsvisitsC::xyzbut notF::xyz. Anyway, the conclusion is thatCollectFirstDeclFromEachModuledoes the correct thing of visiting bothC::xyzandF::xyz.I moved the
CollectFirstDeclFromEachModuleinASTWriterDeclover toASTWriter::CollectFirstDeclFromEachModuleand this is used inASTWriter.cppas well the existing two use cases inASTWriterDecl.cpp.The Issue of Merging
MultiOnDiskHashTableThis repro is extremely finicky however, where for example, removing the
-fmodule-file=E.pcmfrom this:to
the test passes.
Module
Eis literally empty, and it depends onBwhich is literally empty, and depends onAwhich has a dummyint x;declaration... None of this should have anything to do with namespacexyz... What's going on here?The issue here is that
MultiOnDiskHashTablewill merge after a specified number of modules are added. In our case, this number is 4. So without moduleE, moduleFwhich depends onDwhich depends onC, is under that threshold of merging. This makes it such that N-ary look-up is performed on each module. OnceEis introduced, we're past the threshold of 4, so merging occurs. Once merging occurs, the merged table is output in the PCM along with a list of "overriden files", which removes the tables provided by the modules before any table look-up. It gets even more complicated though, because the entries from the merged table is output only if there is not already an entry in the generator:In our case, we had an entry in the generator already, which makes the merged table drop its entry. All of this is rather complicated machinery... I'm mostly leaving here as a note.