Skip to content

Commit da00c60

Browse files
authored
[C++20] [Modules] Introduce reduced BMI (#75894)
Close #71034 See https://discourse.llvm.org/t/rfc-c-20-modules-introduce-thin-bmi-and-decls-hash/74755 This patch introduces reduced BMI, which doesn't contain the definitions of functions and variables if its definitions won't contribute to the ABI. Testing is a big part of the patch. We want to make sure the reduced BMI contains the same behavior with the existing and relatively stable fatBMI. This is pretty helpful for further reduction. The user interfaces part it left to following patches to ease the reviewing.
1 parent cc34e56 commit da00c60

File tree

108 files changed

+977
-84
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

108 files changed

+977
-84
lines changed

clang/include/clang/Driver/Options.td

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7414,7 +7414,9 @@ def ast_view : Flag<["-"], "ast-view">,
74147414
def emit_module : Flag<["-"], "emit-module">,
74157415
HelpText<"Generate pre-compiled module file from a module map">;
74167416
def emit_module_interface : Flag<["-"], "emit-module-interface">,
7417-
HelpText<"Generate pre-compiled module file from a C++ module interface">;
7417+
HelpText<"Generate pre-compiled module file from a standard C++ module interface unit">;
7418+
def emit_reduced_module_interface : Flag<["-"], "emit-reduced-module-interface">,
7419+
HelpText<"Generate reduced prebuilt module interface from a standard C++ module interface unit">;
74187420
def emit_header_unit : Flag<["-"], "emit-header-unit">,
74197421
HelpText<"Generate C++20 header units from header files">;
74207422
def emit_pch : Flag<["-"], "emit-pch">,

clang/include/clang/Frontend/FrontendActions.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ class GenerateModuleAction : public ASTFrontendAction {
118118
CreateOutputFile(CompilerInstance &CI, StringRef InFile) = 0;
119119

120120
protected:
121+
std::vector<std::unique_ptr<ASTConsumer>>
122+
CreateMultiplexConsumer(CompilerInstance &CI, StringRef InFile);
123+
121124
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
122125
StringRef InFile) override;
123126

@@ -147,8 +150,10 @@ class GenerateModuleFromModuleMapAction : public GenerateModuleAction {
147150
CreateOutputFile(CompilerInstance &CI, StringRef InFile) override;
148151
};
149152

153+
/// Generates full BMI (which contains full information to generate the object
154+
/// files) for C++20 Named Modules.
150155
class GenerateModuleInterfaceAction : public GenerateModuleAction {
151-
private:
156+
protected:
152157
bool BeginSourceFileAction(CompilerInstance &CI) override;
153158

154159
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
@@ -158,6 +163,14 @@ class GenerateModuleInterfaceAction : public GenerateModuleAction {
158163
CreateOutputFile(CompilerInstance &CI, StringRef InFile) override;
159164
};
160165

166+
/// Only generates the reduced BMI. This action is mainly used by tests.
167+
class GenerateReducedModuleInterfaceAction
168+
: public GenerateModuleInterfaceAction {
169+
private:
170+
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
171+
StringRef InFile) override;
172+
};
173+
161174
class GenerateHeaderUnitAction : public GenerateModuleAction {
162175

163176
private:

clang/include/clang/Frontend/FrontendOptions.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,13 @@ enum ActionKind {
8585
/// Generate pre-compiled module from a module map.
8686
GenerateModule,
8787

88-
/// Generate pre-compiled module from a C++ module interface file.
88+
/// Generate pre-compiled module from a standard C++ module interface unit.
8989
GenerateModuleInterface,
9090

91+
/// Generate reduced module interface for a standard C++ module interface
92+
/// unit.
93+
GenerateReducedModuleInterface,
94+
9195
/// Generate a C++20 header unit module from a header file.
9296
GenerateHeaderUnit,
9397

clang/include/clang/Serialization/ASTWriter.h

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@ class ASTWriter : public ASTDeserializationListener,
166166
/// Indicates that the AST contained compiler errors.
167167
bool ASTHasCompilerErrors = false;
168168

169+
/// Indicates that we're going to generate the reduced BMI for C++20
170+
/// named modules.
171+
bool GeneratingReducedBMI = false;
172+
169173
/// Mapping from input file entries to the index into the
170174
/// offset table where information about that input file is stored.
171175
llvm::DenseMap<const FileEntry *, uint32_t> InputFileIDs;
@@ -596,7 +600,8 @@ class ASTWriter : public ASTDeserializationListener,
596600
ASTWriter(llvm::BitstreamWriter &Stream, SmallVectorImpl<char> &Buffer,
597601
InMemoryModuleCache &ModuleCache,
598602
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
599-
bool IncludeTimestamps = true, bool BuildingImplicitModule = false);
603+
bool IncludeTimestamps = true, bool BuildingImplicitModule = false,
604+
bool GeneratingReducedBMI = false);
600605
~ASTWriter() override;
601606

602607
ASTContext &getASTContext() const {
@@ -856,14 +861,22 @@ class PCHGenerator : public SemaConsumer {
856861
const ASTWriter &getWriter() const { return Writer; }
857862
SmallVectorImpl<char> &getPCH() const { return Buffer->Data; }
858863

864+
bool isComplete() const { return Buffer->IsComplete; }
865+
PCHBuffer *getBufferPtr() { return Buffer.get(); }
866+
StringRef getOutputFile() const { return OutputFile; }
867+
DiagnosticsEngine &getDiagnostics() const {
868+
return SemaPtr->getDiagnostics();
869+
}
870+
859871
public:
860872
PCHGenerator(const Preprocessor &PP, InMemoryModuleCache &ModuleCache,
861873
StringRef OutputFile, StringRef isysroot,
862874
std::shared_ptr<PCHBuffer> Buffer,
863875
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
864876
bool AllowASTWithErrors = false, bool IncludeTimestamps = true,
865877
bool BuildingImplicitModule = false,
866-
bool ShouldCacheASTInMemory = false);
878+
bool ShouldCacheASTInMemory = false,
879+
bool GeneratingReducedBMI = false);
867880
~PCHGenerator() override;
868881

869882
void InitializeSema(Sema &S) override { SemaPtr = &S; }
@@ -873,6 +886,21 @@ class PCHGenerator : public SemaConsumer {
873886
bool hasEmittedPCH() const { return Buffer->IsComplete; }
874887
};
875888

889+
class ReducedBMIGenerator : public PCHGenerator {
890+
public:
891+
ReducedBMIGenerator(const Preprocessor &PP, InMemoryModuleCache &ModuleCache,
892+
StringRef OutputFile, std::shared_ptr<PCHBuffer> Buffer,
893+
bool IncludeTimestamps);
894+
895+
void HandleTranslationUnit(ASTContext &Ctx) override;
896+
};
897+
898+
/// If we can elide the definition of \param D in reduced BMI.
899+
///
900+
/// Generally, we can elide the definition of a declaration if it won't affect
901+
/// the ABI. e.g., the non-inline function bodies.
902+
bool CanElideDeclDef(const Decl *D);
903+
876904
/// A simple helper class to pack several bits in order into (a) 32 bit
877905
/// integer(s).
878906
class BitsPacker {

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2556,6 +2556,8 @@ static const auto &getFrontendActionTable() {
25562556

25572557
{frontend::GenerateModule, OPT_emit_module},
25582558
{frontend::GenerateModuleInterface, OPT_emit_module_interface},
2559+
{frontend::GenerateReducedModuleInterface,
2560+
OPT_emit_reduced_module_interface},
25592561
{frontend::GenerateHeaderUnit, OPT_emit_header_unit},
25602562
{frontend::GeneratePCH, OPT_emit_pch},
25612563
{frontend::GenerateInterfaceStubs, OPT_emit_interface_stubs},
@@ -4280,6 +4282,7 @@ static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) {
42804282
case frontend::FixIt:
42814283
case frontend::GenerateModule:
42824284
case frontend::GenerateModuleInterface:
4285+
case frontend::GenerateReducedModuleInterface:
42834286
case frontend::GenerateHeaderUnit:
42844287
case frontend::GeneratePCH:
42854288
case frontend::GenerateInterfaceStubs:

clang/lib/Frontend/FrontendActions.cpp

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -184,12 +184,12 @@ bool GeneratePCHAction::BeginSourceFileAction(CompilerInstance &CI) {
184184
return true;
185185
}
186186

187-
std::unique_ptr<ASTConsumer>
188-
GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
189-
StringRef InFile) {
187+
std::vector<std::unique_ptr<ASTConsumer>>
188+
GenerateModuleAction::CreateMultiplexConsumer(CompilerInstance &CI,
189+
StringRef InFile) {
190190
std::unique_ptr<raw_pwrite_stream> OS = CreateOutputFile(CI, InFile);
191191
if (!OS)
192-
return nullptr;
192+
return {};
193193

194194
std::string OutputFile = CI.getFrontendOpts().OutputFile;
195195
std::string Sysroot;
@@ -210,6 +210,17 @@ GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
210210
+CI.getFrontendOpts().BuildingImplicitModule));
211211
Consumers.push_back(CI.getPCHContainerWriter().CreatePCHContainerGenerator(
212212
CI, std::string(InFile), OutputFile, std::move(OS), Buffer));
213+
return std::move(Consumers);
214+
}
215+
216+
std::unique_ptr<ASTConsumer>
217+
GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI,
218+
StringRef InFile) {
219+
std::vector<std::unique_ptr<ASTConsumer>> Consumers =
220+
CreateMultiplexConsumer(CI, InFile);
221+
if (Consumers.empty())
222+
return nullptr;
223+
213224
return std::make_unique<MultiplexConsumer>(std::move(Consumers));
214225
}
215226

@@ -265,7 +276,12 @@ GenerateModuleInterfaceAction::CreateASTConsumer(CompilerInstance &CI,
265276
CI.getHeaderSearchOpts().ModulesSkipHeaderSearchPaths = true;
266277
CI.getHeaderSearchOpts().ModulesSkipPragmaDiagnosticMappings = true;
267278

268-
return GenerateModuleAction::CreateASTConsumer(CI, InFile);
279+
std::vector<std::unique_ptr<ASTConsumer>> Consumers =
280+
CreateMultiplexConsumer(CI, InFile);
281+
if (Consumers.empty())
282+
return nullptr;
283+
284+
return std::make_unique<MultiplexConsumer>(std::move(Consumers));
269285
}
270286

271287
std::unique_ptr<raw_pwrite_stream>
@@ -274,6 +290,16 @@ GenerateModuleInterfaceAction::CreateOutputFile(CompilerInstance &CI,
274290
return CI.createDefaultOutputFile(/*Binary=*/true, InFile, "pcm");
275291
}
276292

293+
std::unique_ptr<ASTConsumer>
294+
GenerateReducedModuleInterfaceAction::CreateASTConsumer(CompilerInstance &CI,
295+
StringRef InFile) {
296+
auto Buffer = std::make_shared<PCHBuffer>();
297+
return std::make_unique<ReducedBMIGenerator>(
298+
CI.getPreprocessor(), CI.getModuleCache(),
299+
CI.getFrontendOpts().OutputFile, Buffer,
300+
/*IncludeTimestamps=*/+CI.getFrontendOpts().IncludeTimestamps);
301+
}
302+
277303
bool GenerateHeaderUnitAction::BeginSourceFileAction(CompilerInstance &CI) {
278304
if (!CI.getLangOpts().CPlusPlusModules) {
279305
CI.getDiagnostics().Report(diag::err_module_interface_requires_cpp_modules);
@@ -839,7 +865,6 @@ void DumpModuleInfoAction::ExecuteAction() {
839865

840866
const LangOptions &LO = getCurrentASTUnit().getLangOpts();
841867
if (LO.CPlusPlusModules && !LO.CurrentModule.empty()) {
842-
843868
ASTReader *R = getCurrentASTUnit().getASTReader().get();
844869
unsigned SubModuleCount = R->getTotalNumSubmodules();
845870
serialization::ModuleFile &MF = R->getModuleManager().getPrimaryModule();

clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ CreateFrontendBaseAction(CompilerInstance &CI) {
6565
return std::make_unique<GenerateModuleFromModuleMapAction>();
6666
case GenerateModuleInterface:
6767
return std::make_unique<GenerateModuleInterfaceAction>();
68+
case GenerateReducedModuleInterface:
69+
return std::make_unique<GenerateReducedModuleInterfaceAction>();
6870
case GenerateHeaderUnit:
6971
return std::make_unique<GenerateHeaderUnitAction>();
7072
case GeneratePCH: return std::make_unique<GeneratePCHAction>();

clang/lib/Serialization/ASTWriter.cpp

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4623,10 +4623,12 @@ ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream,
46234623
SmallVectorImpl<char> &Buffer,
46244624
InMemoryModuleCache &ModuleCache,
46254625
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
4626-
bool IncludeTimestamps, bool BuildingImplicitModule)
4626+
bool IncludeTimestamps, bool BuildingImplicitModule,
4627+
bool GeneratingReducedBMI)
46274628
: Stream(Stream), Buffer(Buffer), ModuleCache(ModuleCache),
46284629
IncludeTimestamps(IncludeTimestamps),
4629-
BuildingImplicitModule(BuildingImplicitModule) {
4630+
BuildingImplicitModule(BuildingImplicitModule),
4631+
GeneratingReducedBMI(GeneratingReducedBMI) {
46304632
for (const auto &Ext : Extensions) {
46314633
if (auto Writer = Ext->createExtensionWriter(*this))
46324634
ModuleFileExtensionWriters.push_back(std::move(Writer));
@@ -5457,18 +5459,20 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
54575459

54585460
// Add a trailing update record, if any. These must go last because we
54595461
// lazily load their attached statement.
5460-
if (HasUpdatedBody) {
5461-
const auto *Def = cast<FunctionDecl>(D);
5462-
Record.push_back(UPD_CXX_ADDED_FUNCTION_DEFINITION);
5463-
Record.push_back(Def->isInlined());
5464-
Record.AddSourceLocation(Def->getInnerLocStart());
5465-
Record.AddFunctionDefinition(Def);
5466-
} else if (HasAddedVarDefinition) {
5467-
const auto *VD = cast<VarDecl>(D);
5468-
Record.push_back(UPD_CXX_ADDED_VAR_DEFINITION);
5469-
Record.push_back(VD->isInline());
5470-
Record.push_back(VD->isInlineSpecified());
5471-
Record.AddVarDeclInit(VD);
5462+
if (!GeneratingReducedBMI || !CanElideDeclDef(D)) {
5463+
if (HasUpdatedBody) {
5464+
const auto *Def = cast<FunctionDecl>(D);
5465+
Record.push_back(UPD_CXX_ADDED_FUNCTION_DEFINITION);
5466+
Record.push_back(Def->isInlined());
5467+
Record.AddSourceLocation(Def->getInnerLocStart());
5468+
Record.AddFunctionDefinition(Def);
5469+
} else if (HasAddedVarDefinition) {
5470+
const auto *VD = cast<VarDecl>(D);
5471+
Record.push_back(UPD_CXX_ADDED_VAR_DEFINITION);
5472+
Record.push_back(VD->isInline());
5473+
Record.push_back(VD->isInlineSpecified());
5474+
Record.AddVarDeclInit(VD);
5475+
}
54725476
}
54735477

54745478
OffsetsRecord.push_back(GetDeclRef(D));

clang/lib/Serialization/ASTWriterDecl.cpp

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "clang/AST/DeclTemplate.h"
1717
#include "clang/AST/DeclVisitor.h"
1818
#include "clang/AST/Expr.h"
19+
#include "clang/AST/ODRHash.h"
1920
#include "clang/AST/OpenMPClause.h"
2021
#include "clang/AST/PrettyDeclStackTrace.h"
2122
#include "clang/Basic/SourceManager.h"
@@ -40,11 +41,14 @@ namespace clang {
4041
serialization::DeclCode Code;
4142
unsigned AbbrevToUse;
4243

44+
bool GeneratingReducedBMI = false;
45+
4346
public:
4447
ASTDeclWriter(ASTWriter &Writer, ASTContext &Context,
45-
ASTWriter::RecordDataImpl &Record)
48+
ASTWriter::RecordDataImpl &Record, bool GeneratingReducedBMI)
4649
: Writer(Writer), Context(Context), Record(Writer, Record),
47-
Code((serialization::DeclCode)0), AbbrevToUse(0) {}
50+
Code((serialization::DeclCode)0), AbbrevToUse(0),
51+
GeneratingReducedBMI(GeneratingReducedBMI) {}
4852

4953
uint64_t Emit(Decl *D) {
5054
if (!Code)
@@ -270,6 +274,27 @@ namespace clang {
270274
};
271275
}
272276

277+
bool clang::CanElideDeclDef(const Decl *D) {
278+
if (auto *FD = dyn_cast<FunctionDecl>(D)) {
279+
if (FD->isInlined() || FD->isConstexpr())
280+
return false;
281+
282+
if (FD->isDependentContext())
283+
return false;
284+
}
285+
286+
if (auto *VD = dyn_cast<VarDecl>(D)) {
287+
if (!VD->getDeclContext()->getRedeclContext()->isFileContext() ||
288+
VD->isInline() || VD->isConstexpr() || isa<ParmVarDecl>(VD))
289+
return false;
290+
291+
if (VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
292+
return false;
293+
}
294+
295+
return true;
296+
}
297+
273298
void ASTDeclWriter::Visit(Decl *D) {
274299
DeclVisitor<ASTDeclWriter>::Visit(D);
275300

@@ -285,17 +310,23 @@ void ASTDeclWriter::Visit(Decl *D) {
285310
// have been written. We want it last because we will not read it back when
286311
// retrieving it from the AST, we'll just lazily set the offset.
287312
if (auto *FD = dyn_cast<FunctionDecl>(D)) {
288-
Record.push_back(FD->doesThisDeclarationHaveABody());
289-
if (FD->doesThisDeclarationHaveABody())
290-
Record.AddFunctionDefinition(FD);
313+
if (!GeneratingReducedBMI || !CanElideDeclDef(FD)) {
314+
Record.push_back(FD->doesThisDeclarationHaveABody());
315+
if (FD->doesThisDeclarationHaveABody())
316+
Record.AddFunctionDefinition(FD);
317+
} else
318+
Record.push_back(0);
291319
}
292320

293321
// Similar to FunctionDecls, handle VarDecl's initializer here and write it
294322
// after all other Stmts/Exprs. We will not read the initializer until after
295323
// we have finished recursive deserialization, because it can recursively
296324
// refer back to the variable.
297325
if (auto *VD = dyn_cast<VarDecl>(D)) {
298-
Record.AddVarDeclInit(VD);
326+
if (!GeneratingReducedBMI || !CanElideDeclDef(VD))
327+
Record.AddVarDeclInit(VD);
328+
else
329+
Record.push_back(0);
299330
}
300331

301332
// And similarly for FieldDecls. We already serialized whether there is a
@@ -2729,7 +2760,7 @@ void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) {
27292760
assert(ID >= FirstDeclID && "invalid decl ID");
27302761

27312762
RecordData Record;
2732-
ASTDeclWriter W(*this, Context, Record);
2763+
ASTDeclWriter W(*this, Context, Record, GeneratingReducedBMI);
27332764

27342765
// Build a record for this declaration
27352766
W.Visit(D);

0 commit comments

Comments
 (0)