Skip to content

Commit b5bc1bc

Browse files
committed
[C++20] [Modules] Introduce reduced BMI
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 cdc0392 commit b5bc1bc

File tree

108 files changed

+974
-83
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

+974
-83
lines changed

clang/include/clang/Driver/Options.td

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7302,7 +7302,9 @@ def ast_view : Flag<["-"], "ast-view">,
73027302
def emit_module : Flag<["-"], "emit-module">,
73037303
HelpText<"Generate pre-compiled module file from a module map">;
73047304
def emit_module_interface : Flag<["-"], "emit-module-interface">,
7305-
HelpText<"Generate pre-compiled module file from a C++ module interface">;
7305+
HelpText<"Generate pre-compiled module file from a standard C++ module interface unit">;
7306+
def emit_reduced_module_interface : Flag<["-"], "emit-reduced-module-interface">,
7307+
HelpText<"Generate reduced prebuilt module interface from a standard C++ module interface unit">;
73067308
def emit_header_unit : Flag<["-"], "emit-header-unit">,
73077309
HelpText<"Generate C++20 header units from header files">;
73087310
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: 28 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;
@@ -582,7 +586,8 @@ class ASTWriter : public ASTDeserializationListener,
582586
ASTWriter(llvm::BitstreamWriter &Stream, SmallVectorImpl<char> &Buffer,
583587
InMemoryModuleCache &ModuleCache,
584588
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
585-
bool IncludeTimestamps = true, bool BuildingImplicitModule = false);
589+
bool IncludeTimestamps = true, bool BuildingImplicitModule = false,
590+
bool GeneratingReducedBMI = false);
586591
~ASTWriter() override;
587592

588593
ASTContext &getASTContext() const {
@@ -813,14 +818,22 @@ class PCHGenerator : public SemaConsumer {
813818
const ASTWriter &getWriter() const { return Writer; }
814819
SmallVectorImpl<char> &getPCH() const { return Buffer->Data; }
815820

821+
bool isComplete() const { return Buffer->IsComplete; }
822+
PCHBuffer *getBufferPtr() { return Buffer.get(); }
823+
StringRef getOutputFile() const { return OutputFile; }
824+
DiagnosticsEngine &getDiagnostics() const {
825+
return SemaPtr->getDiagnostics();
826+
}
827+
816828
public:
817829
PCHGenerator(const Preprocessor &PP, InMemoryModuleCache &ModuleCache,
818830
StringRef OutputFile, StringRef isysroot,
819831
std::shared_ptr<PCHBuffer> Buffer,
820832
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
821833
bool AllowASTWithErrors = false, bool IncludeTimestamps = true,
822834
bool BuildingImplicitModule = false,
823-
bool ShouldCacheASTInMemory = false);
835+
bool ShouldCacheASTInMemory = false,
836+
bool GeneratingReducedBMI = false);
824837
~PCHGenerator() override;
825838

826839
void InitializeSema(Sema &S) override { SemaPtr = &S; }
@@ -830,6 +843,19 @@ class PCHGenerator : public SemaConsumer {
830843
bool hasEmittedPCH() const { return Buffer->IsComplete; }
831844
};
832845

846+
class ReducedBMIGenerator : public PCHGenerator {
847+
public:
848+
ReducedBMIGenerator(const Preprocessor &PP, InMemoryModuleCache &ModuleCache,
849+
StringRef OutputFile, std::shared_ptr<PCHBuffer> Buffer,
850+
bool IncludeTimestamps);
851+
852+
void HandleTranslationUnit(ASTContext &Ctx) override;
853+
};
854+
855+
/// If the definition may impact the ABI. If yes, we're allowed to eliminate
856+
/// the definition of D in reduced BMI.
857+
bool MayDefAffectABI(const Decl *D);
858+
833859
/// A simple helper class to pack several bits in order into (a) 32 bit
834860
/// integer(s).
835861
class BitsPacker {

clang/lib/Frontend/CompilerInvocation.cpp

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

25682568
{frontend::GenerateModule, OPT_emit_module},
25692569
{frontend::GenerateModuleInterface, OPT_emit_module_interface},
2570+
{frontend::GenerateReducedModuleInterface,
2571+
OPT_emit_reduced_module_interface},
25702572
{frontend::GenerateHeaderUnit, OPT_emit_header_unit},
25712573
{frontend::GeneratePCH, OPT_emit_pch},
25722574
{frontend::GenerateInterfaceStubs, OPT_emit_interface_stubs},
@@ -4274,6 +4276,7 @@ static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) {
42744276
case frontend::FixIt:
42754277
case frontend::GenerateModule:
42764278
case frontend::GenerateModuleInterface:
4279+
case frontend::GenerateReducedModuleInterface:
42774280
case frontend::GenerateHeaderUnit:
42784281
case frontend::GeneratePCH:
42794282
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);
@@ -840,7 +866,6 @@ void DumpModuleInfoAction::ExecuteAction() {
840866

841867
const LangOptions &LO = getCurrentASTUnit().getLangOpts();
842868
if (LO.CPlusPlusModules && !LO.CurrentModule.empty()) {
843-
844869
ASTReader *R = getCurrentASTUnit().getASTReader().get();
845870
unsigned SubModuleCount = R->getTotalNumSubmodules();
846871
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
@@ -4595,10 +4595,12 @@ ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream,
45954595
SmallVectorImpl<char> &Buffer,
45964596
InMemoryModuleCache &ModuleCache,
45974597
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
4598-
bool IncludeTimestamps, bool BuildingImplicitModule)
4598+
bool IncludeTimestamps, bool BuildingImplicitModule,
4599+
bool GeneratingReducedBMI)
45994600
: Stream(Stream), Buffer(Buffer), ModuleCache(ModuleCache),
46004601
IncludeTimestamps(IncludeTimestamps),
4601-
BuildingImplicitModule(BuildingImplicitModule) {
4602+
BuildingImplicitModule(BuildingImplicitModule),
4603+
GeneratingReducedBMI(GeneratingReducedBMI) {
46024604
for (const auto &Ext : Extensions) {
46034605
if (auto Writer = Ext->createExtensionWriter(*this))
46044606
ModuleFileExtensionWriters.push_back(std::move(Writer));
@@ -5405,18 +5407,20 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
54055407

54065408
// Add a trailing update record, if any. These must go last because we
54075409
// lazily load their attached statement.
5408-
if (HasUpdatedBody) {
5409-
const auto *Def = cast<FunctionDecl>(D);
5410-
Record.push_back(UPD_CXX_ADDED_FUNCTION_DEFINITION);
5411-
Record.push_back(Def->isInlined());
5412-
Record.AddSourceLocation(Def->getInnerLocStart());
5413-
Record.AddFunctionDefinition(Def);
5414-
} else if (HasAddedVarDefinition) {
5415-
const auto *VD = cast<VarDecl>(D);
5416-
Record.push_back(UPD_CXX_ADDED_VAR_DEFINITION);
5417-
Record.push_back(VD->isInline());
5418-
Record.push_back(VD->isInlineSpecified());
5419-
Record.AddVarDeclInit(VD);
5410+
if (!GeneratingReducedBMI || MayDefAffectABI(D)) {
5411+
if (HasUpdatedBody) {
5412+
const auto *Def = cast<FunctionDecl>(D);
5413+
Record.push_back(UPD_CXX_ADDED_FUNCTION_DEFINITION);
5414+
Record.push_back(Def->isInlined());
5415+
Record.AddSourceLocation(Def->getInnerLocStart());
5416+
Record.AddFunctionDefinition(Def);
5417+
} else if (HasAddedVarDefinition) {
5418+
const auto *VD = cast<VarDecl>(D);
5419+
Record.push_back(UPD_CXX_ADDED_VAR_DEFINITION);
5420+
Record.push_back(VD->isInline());
5421+
Record.push_back(VD->isInlineSpecified());
5422+
Record.AddVarDeclInit(VD);
5423+
}
54205424
}
54215425

54225426
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::MayDefAffectABI(const Decl *D) {
278+
if (auto *FD = dyn_cast<FunctionDecl>(D)) {
279+
if (FD->isInlined() || FD->isConstexpr())
280+
return true;
281+
282+
if (FD->isDependentContext())
283+
return true;
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 true;
290+
291+
if (VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
292+
return true;
293+
}
294+
295+
return false;
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 || MayDefAffectABI(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 || MayDefAffectABI(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
@@ -2474,7 +2505,7 @@ void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) {
24742505
assert(ID >= FirstDeclID && "invalid decl ID");
24752506

24762507
RecordData Record;
2477-
ASTDeclWriter W(*this, Context, Record);
2508+
ASTDeclWriter W(*this, Context, Record, GeneratingReducedBMI);
24782509

24792510
// Build a record for this declaration
24802511
W.Visit(D);

0 commit comments

Comments
 (0)