Skip to content

Commit b46c8fa

Browse files
committed
[C++20] [Modules] Introduce -fgen-reduced-bmi
1 parent 912e2c4 commit b46c8fa

File tree

13 files changed

+220
-27
lines changed

13 files changed

+220
-27
lines changed

clang/include/clang/CodeGen/CodeGenAction.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ class CodeGenAction : public ASTFrontendAction {
5757
bool loadLinkModules(CompilerInstance &CI);
5858

5959
protected:
60+
bool BeginSourceFileAction(CompilerInstance &CI) override;
61+
6062
/// Create a new code generation action. If the optional \p _VMContext
6163
/// parameter is supplied, the action uses it without taking ownership,
6264
/// otherwise it creates a fresh LLVM context and takes ownership.

clang/include/clang/Driver/Options.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3017,6 +3017,7 @@ defm prebuilt_implicit_modules : BoolFOption<"prebuilt-implicit-modules",
30173017

30183018
def fmodule_output_EQ : Joined<["-"], "fmodule-output=">,
30193019
Flags<[NoXarchOption]>, Visibility<[ClangOption, CC1Option]>,
3020+
MarshallingInfoString<FrontendOpts<"ModuleOutputPath">>,
30203021
HelpText<"Save intermediate module file results when compiling a standard C++ module unit.">;
30213022
def fmodule_output : Flag<["-"], "fmodule-output">, Flags<[NoXarchOption]>,
30223023
Visibility<[ClangOption, CC1Option]>,
@@ -3030,6 +3031,11 @@ defm skip_odr_check_in_gmf : BoolOption<"f", "skip-odr-check-in-gmf",
30303031
"Perform ODR checks for decls in the global module fragment.">>,
30313032
Group<f_Group>;
30323033

3034+
def gen_reduced_bmi : Flag<["-"], "fgen-reduced-bmi">,
3035+
Group<i_Group>, Visibility<[ClangOption, CC1Option]>,
3036+
HelpText<"Generate the reduced BMI">,
3037+
MarshallingInfoFlag<FrontendOpts<"GenReducedBMI">>;
3038+
30333039
def fmodules_prune_interval : Joined<["-"], "fmodules-prune-interval=">, Group<i_Group>,
30343040
Visibility<[ClangOption, CC1Option]>, MetaVarName<"<seconds>">,
30353041
HelpText<"Specify the interval (in seconds) between attempts to prune the module cache">,

clang/include/clang/Frontend/FrontendOptions.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,10 @@ class FrontendOptions {
387387
LLVM_PREFERRED_TYPE(bool)
388388
unsigned ModulesShareFileManager : 1;
389389

390+
/// Whether to generate reduced BMI for C++20 named modules.
391+
LLVM_PREFERRED_TYPE(bool)
392+
unsigned GenReducedBMI : 1;
393+
390394
CodeCompleteOptions CodeCompleteOpts;
391395

392396
/// Specifies the output format of the AST.
@@ -553,6 +557,9 @@ class FrontendOptions {
553557
/// Path which stores the output files for -ftime-trace
554558
std::string TimeTracePath;
555559

560+
/// Output Path for module output file.
561+
std::string ModuleOutputPath;
562+
556563
public:
557564
FrontendOptions()
558565
: DisableFree(false), RelocatablePCH(false), ShowHelp(false),
@@ -565,7 +572,7 @@ class FrontendOptions {
565572
BuildingImplicitModuleUsesLock(true), ModulesEmbedAllFiles(false),
566573
IncludeTimestamps(true), UseTemporary(true),
567574
AllowPCMWithCompilerErrors(false), ModulesShareFileManager(true),
568-
TimeTraceGranularity(500) {}
575+
GenReducedBMI(false), TimeTraceGranularity(500) {}
569576

570577
/// getInputKindForExtension - Return the appropriate input kind for a file
571578
/// extension. For example, "c" would return Language::C.

clang/include/clang/Serialization/ASTWriter.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -846,7 +846,7 @@ class ASTWriter : public ASTDeserializationListener,
846846
/// AST and semantic-analysis consumer that generates a
847847
/// precompiled header from the parsed source code.
848848
class PCHGenerator : public SemaConsumer {
849-
const Preprocessor &PP;
849+
Preprocessor &PP;
850850
std::string OutputFile;
851851
std::string isysroot;
852852
Sema *SemaPtr;
@@ -867,11 +867,12 @@ class PCHGenerator : public SemaConsumer {
867867
DiagnosticsEngine &getDiagnostics() const {
868868
return SemaPtr->getDiagnostics();
869869
}
870+
Preprocessor &getPreprocessor() { return PP; }
870871

871872
virtual Module *getEmittingModule(ASTContext &Ctx);
872873

873874
public:
874-
PCHGenerator(const Preprocessor &PP, InMemoryModuleCache &ModuleCache,
875+
PCHGenerator(Preprocessor &PP, InMemoryModuleCache &ModuleCache,
875876
StringRef OutputFile, StringRef isysroot,
876877
std::shared_ptr<PCHBuffer> Buffer,
877878
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
@@ -893,7 +894,7 @@ class ReducedBMIGenerator : public PCHGenerator {
893894
virtual Module *getEmittingModule(ASTContext &Ctx) override;
894895

895896
public:
896-
ReducedBMIGenerator(const Preprocessor &PP, InMemoryModuleCache &ModuleCache,
897+
ReducedBMIGenerator(Preprocessor &PP, InMemoryModuleCache &ModuleCache,
897898
StringRef OutputFile);
898899

899900
void HandleTranslationUnit(ASTContext &Ctx) override;

clang/lib/CodeGen/CodeGenAction.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,11 @@
2525
#include "clang/CodeGen/ModuleBuilder.h"
2626
#include "clang/Driver/DriverDiagnostic.h"
2727
#include "clang/Frontend/CompilerInstance.h"
28+
#include "clang/Frontend/FrontendActions.h"
2829
#include "clang/Frontend/FrontendDiagnostic.h"
30+
#include "clang/Frontend/MultiplexConsumer.h"
2931
#include "clang/Lex/Preprocessor.h"
32+
#include "clang/Serialization/ASTWriter.h"
3033
#include "llvm/ADT/Hashing.h"
3134
#include "llvm/Bitcode/BitcodeReader.h"
3235
#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
@@ -1003,6 +1006,12 @@ CodeGenerator *CodeGenAction::getCodeGenerator() const {
10031006
return BEConsumer->getCodeGenerator();
10041007
}
10051008

1009+
bool CodeGenAction::BeginSourceFileAction(CompilerInstance &CI) {
1010+
if (CI.getFrontendOpts().GenReducedBMI)
1011+
CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleInterface);
1012+
return true;
1013+
}
1014+
10061015
static std::unique_ptr<raw_pwrite_stream>
10071016
GetOutputStream(CompilerInstance &CI, StringRef InFile, BackendAction Action) {
10081017
switch (Action) {
@@ -1061,6 +1070,16 @@ CodeGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
10611070
CI.getPreprocessor().addPPCallbacks(std::move(Callbacks));
10621071
}
10631072

1073+
if (CI.getFrontendOpts().GenReducedBMI &&
1074+
!CI.getFrontendOpts().ModuleOutputPath.empty()) {
1075+
std::vector<std::unique_ptr<ASTConsumer>> Consumers{2};
1076+
Consumers[0] = std::make_unique<ReducedBMIGenerator>(
1077+
CI.getPreprocessor(), CI.getModuleCache(),
1078+
CI.getFrontendOpts().ModuleOutputPath);
1079+
Consumers[1] = std::move(Result);
1080+
return std::make_unique<MultiplexConsumer>(std::move(Consumers));
1081+
}
1082+
10641083
return std::move(Result);
10651084
}
10661085

clang/lib/Driver/Driver.cpp

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4749,6 +4749,14 @@ Action *Driver::ConstructPhaseAction(
47494749
if (Args.hasArg(options::OPT_extract_api))
47504750
return C.MakeAction<ExtractAPIJobAction>(Input, types::TY_API_INFO);
47514751

4752+
// With '-fgen-reduced-bmi', we don't want to run the precompile phase
4753+
// unless the user specified '--precompile'. In the case the '--precompile'
4754+
// flag is enabled, we will try to emit the reduced BMI as a by product
4755+
// in GenerateModuleInterfaceAction.
4756+
if (Args.hasArg(options::OPT_gen_reduced_bmi) &&
4757+
!Args.getLastArg(options::OPT__precompile))
4758+
return Input;
4759+
47524760
types::ID OutputTy = getPrecompiledType(Input->getType());
47534761
assert(OutputTy != types::TY_INVALID &&
47544762
"Cannot precompile this input type!");
@@ -5814,19 +5822,8 @@ static const char *GetModuleOutputPath(Compilation &C, const JobAction &JA,
58145822
(C.getArgs().hasArg(options::OPT_fmodule_output) ||
58155823
C.getArgs().hasArg(options::OPT_fmodule_output_EQ)));
58165824

5817-
if (Arg *ModuleOutputEQ =
5818-
C.getArgs().getLastArg(options::OPT_fmodule_output_EQ))
5819-
return C.addResultFile(ModuleOutputEQ->getValue(), &JA);
5820-
5821-
SmallString<64> OutputPath;
5822-
Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o);
5823-
if (FinalOutput && C.getArgs().hasArg(options::OPT_c))
5824-
OutputPath = FinalOutput->getValue();
5825-
else
5826-
OutputPath = BaseInput;
5827-
5828-
const char *Extension = types::getTypeTempSuffix(JA.getType());
5829-
llvm::sys::path::replace_extension(OutputPath, Extension);
5825+
SmallString<256> OutputPath =
5826+
tools::getCXX20NamedModuleOutputPath(C.getArgs(), BaseInput);
58305827
return C.addResultFile(C.getArgs().MakeArgString(OutputPath.c_str()), &JA);
58315828
}
58325829

@@ -5913,8 +5910,10 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
59135910
// If we're emitting a module output with the specified option
59145911
// `-fmodule-output`.
59155912
if (!AtTopLevel && isa<PrecompileJobAction>(JA) &&
5916-
JA.getType() == types::TY_ModuleFile && SpecifiedModuleOutput)
5913+
JA.getType() == types::TY_ModuleFile && SpecifiedModuleOutput) {
5914+
assert(!C.getArgs().hasArg(options::OPT_gen_reduced_bmi));
59175915
return GetModuleOutputPath(C, JA, BaseInput);
5916+
}
59185917

59195918
// Output to a temporary file?
59205919
if ((!AtTopLevel && !isSaveTempsEnabled() &&

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3839,6 +3839,24 @@ bool Driver::getDefaultModuleCachePath(SmallVectorImpl<char> &Result) {
38393839
return false;
38403840
}
38413841

3842+
llvm::SmallString<256>
3843+
clang::driver::tools::getCXX20NamedModuleOutputPath(const ArgList &Args,
3844+
const char *BaseInput) {
3845+
if (Arg *ModuleOutputEQ = Args.getLastArg(options::OPT_fmodule_output_EQ))
3846+
return StringRef(ModuleOutputEQ->getValue());
3847+
3848+
SmallString<256> OutputPath;
3849+
if (Arg *FinalOutput = Args.getLastArg(options::OPT_o);
3850+
FinalOutput && Args.hasArg(options::OPT_c))
3851+
OutputPath = FinalOutput->getValue();
3852+
else
3853+
OutputPath = BaseInput;
3854+
3855+
const char *Extension = types::getTypeTempSuffix(types::TY_ModuleFile);
3856+
llvm::sys::path::replace_extension(OutputPath, Extension);
3857+
return OutputPath;
3858+
}
3859+
38423860
static bool RenderModulesOptions(Compilation &C, const Driver &D,
38433861
const ArgList &Args, const InputInfo &Input,
38443862
const InputInfo &Output, bool HaveStd20,
@@ -4027,9 +4045,26 @@ static bool RenderModulesOptions(Compilation &C, const Driver &D,
40274045
// module fragment.
40284046
CmdArgs.push_back("-fskip-odr-check-in-gmf");
40294047

4030-
// Claim `-fmodule-output` and `-fmodule-output=` to avoid unused warnings.
4031-
Args.ClaimAllArgs(options::OPT_fmodule_output);
4032-
Args.ClaimAllArgs(options::OPT_fmodule_output_EQ);
4048+
// Noop if we see '-fgen-reduced-bmi' with other translation units than module
4049+
// units. This is more user friendly to allow end uers to enable this feature
4050+
// without asking for help from build systems.
4051+
if (Args.hasArg(options::OPT_gen_reduced_bmi) &&
4052+
(Input.getType() == driver::types::TY_CXXModule ||
4053+
Input.getType() == driver::types::TY_PP_CXXModule)) {
4054+
CmdArgs.push_back("-fgen-reduced-bmi");
4055+
4056+
if (Args.hasArg(options::OPT_fmodule_output_EQ))
4057+
Args.AddLastArg(CmdArgs, options::OPT_fmodule_output_EQ);
4058+
else
4059+
CmdArgs.push_back(Args.MakeArgString(
4060+
"-fmodule-output=" +
4061+
getCXX20NamedModuleOutputPath(Args, Input.getBaseInput())));
4062+
} else {
4063+
// To avoid unused warnings.
4064+
Args.ClaimAllArgs(options::OPT_gen_reduced_bmi);
4065+
Args.ClaimAllArgs(options::OPT_fmodule_output);
4066+
Args.ClaimAllArgs(options::OPT_fmodule_output_EQ);
4067+
}
40334068

40344069
return HaveModules;
40354070
}

clang/lib/Driver/ToolChains/Clang.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,20 @@ DwarfFissionKind getDebugFissionKind(const Driver &D,
193193
const llvm::opt::ArgList &Args,
194194
llvm::opt::Arg *&Arg);
195195

196+
// Calculate the output path of the module file when compiling a module unit
197+
// with the `-fmodule-output` option or `-fmodule-output=` option specified.
198+
// The behavior is:
199+
// - If `-fmodule-output=` is specfied, then the module file is
200+
// writing to the value.
201+
// - Otherwise if the output object file of the module unit is specified, the
202+
// output path
203+
// of the module file should be the same with the output object file except
204+
// the corresponding suffix. This requires both `-o` and `-c` are specified.
205+
// - Otherwise, the output path of the module file will be the same with the
206+
// input with the corresponding suffix.
207+
llvm::SmallString<256>
208+
getCXX20NamedModuleOutputPath(const llvm::opt::ArgList &Args,
209+
const char *BaseInput);
196210
} // end namespace tools
197211

198212
} // end namespace driver

clang/lib/Frontend/FrontendActions.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,13 @@ GenerateModuleInterfaceAction::CreateASTConsumer(CompilerInstance &CI,
281281
if (Consumers.empty())
282282
return nullptr;
283283

284+
if (CI.getFrontendOpts().GenReducedBMI &&
285+
!CI.getFrontendOpts().ModuleOutputPath.empty()) {
286+
Consumers.push_back(std::make_unique<ReducedBMIGenerator>(
287+
CI.getPreprocessor(), CI.getModuleCache(),
288+
CI.getFrontendOpts().ModuleOutputPath));
289+
}
290+
284291
return std::make_unique<MultiplexConsumer>(std::move(Consumers));
285292
}
286293

clang/lib/Frontend/PrecompiledPreamble.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,8 +290,7 @@ class PrecompilePreambleAction : public ASTFrontendAction {
290290

291291
class PrecompilePreambleConsumer : public PCHGenerator {
292292
public:
293-
PrecompilePreambleConsumer(PrecompilePreambleAction &Action,
294-
const Preprocessor &PP,
293+
PrecompilePreambleConsumer(PrecompilePreambleAction &Action, Preprocessor &PP,
295294
InMemoryModuleCache &ModuleCache,
296295
StringRef isysroot,
297296
std::shared_ptr<PCHBuffer> Buffer)

clang/lib/Serialization/GeneratePCH.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "clang/AST/ASTContext.h"
1515
#include "clang/Frontend/FrontendDiagnostic.h"
1616
#include "clang/Lex/HeaderSearch.h"
17+
#include "clang/Lex/HeaderSearchOptions.h"
1718
#include "clang/Lex/Preprocessor.h"
1819
#include "clang/Sema/SemaConsumer.h"
1920
#include "clang/Serialization/ASTReader.h"
@@ -23,8 +24,8 @@
2324
using namespace clang;
2425

2526
PCHGenerator::PCHGenerator(
26-
const Preprocessor &PP, InMemoryModuleCache &ModuleCache,
27-
StringRef OutputFile, StringRef isysroot, std::shared_ptr<PCHBuffer> Buffer,
27+
Preprocessor &PP, InMemoryModuleCache &ModuleCache, StringRef OutputFile,
28+
StringRef isysroot, std::shared_ptr<PCHBuffer> Buffer,
2829
ArrayRef<std::shared_ptr<ModuleFileExtension>> Extensions,
2930
bool AllowASTWithErrors, bool IncludeTimestamps,
3031
bool BuildingImplicitModule, bool ShouldCacheASTInMemory,
@@ -88,7 +89,7 @@ ASTDeserializationListener *PCHGenerator::GetASTDeserializationListener() {
8889
return &Writer;
8990
}
9091

91-
ReducedBMIGenerator::ReducedBMIGenerator(const Preprocessor &PP,
92+
ReducedBMIGenerator::ReducedBMIGenerator(Preprocessor &PP,
9293
InMemoryModuleCache &ModuleCache,
9394
StringRef OutputFile)
9495
: PCHGenerator(
@@ -101,12 +102,26 @@ ReducedBMIGenerator::ReducedBMIGenerator(const Preprocessor &PP,
101102

102103
Module *ReducedBMIGenerator::getEmittingModule(ASTContext &Ctx) {
103104
Module *M = Ctx.getCurrentNamedModule();
104-
assert(M->isNamedModuleUnit() &&
105+
assert(M && M->isNamedModuleUnit() &&
105106
"ReducedBMIGenerator should only be used with C++20 Named modules.");
106107
return M;
107108
}
108109

109110
void ReducedBMIGenerator::HandleTranslationUnit(ASTContext &Ctx) {
111+
// FIMXE: We'd better to wrap such options to a new class ASTWriterOptions.
112+
getPreprocessor()
113+
.getHeaderSearchInfo()
114+
.getHeaderSearchOpts()
115+
.ModulesSkipDiagnosticOptions = true;
116+
getPreprocessor()
117+
.getHeaderSearchInfo()
118+
.getHeaderSearchOpts()
119+
.ModulesSkipHeaderSearchPaths = true;
120+
getPreprocessor()
121+
.getHeaderSearchInfo()
122+
.getHeaderSearchOpts()
123+
.ModulesSkipPragmaDiagnosticMappings = true;
124+
110125
PCHGenerator::HandleTranslationUnit(Ctx);
111126

112127
if (!isComplete())
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// It is annoying to handle different slash direction
2+
// in Windows and Linux. So we disable the test on Windows
3+
// here.
4+
// REQUIRES: !system-windows
5+
// On AIX, the default output for `-c` may be `.s` instead of `.o`,
6+
// which makes the test fail. So disable the test on AIX.
7+
// REQUIRES: !system-aix
8+
//
9+
// RUN: rm -rf %t
10+
// RUN: mkdir %t
11+
// RUN: split-file %s %t
12+
//
13+
// RUN: %clang -std=c++20 %t/Hello.cppm -fmodule-output=%t/Hello.pcm \
14+
// RUN: -fgen-reduced-bmi -c -o %t/Hello.o -### 2>&1 | FileCheck %t/Hello.cppm
15+
//
16+
// RUN: %clang -std=c++20 %t/Hello.cppm \
17+
// RUN: -fgen-reduced-bmi -c -o %t/Hello.o -### 2>&1 | \
18+
// RUN: FileCheck %t/Hello.cppm --check-prefix=CHECK-UNSPECIFIED
19+
//
20+
// RUN: %clang -std=c++20 %t/Hello.cppm \
21+
// RUN: -fgen-reduced-bmi -c -### 2>&1 | \
22+
// RUN: FileCheck %t/Hello.cppm --check-prefix=CHECK-NO-O
23+
//
24+
// RUN: %clang -std=c++20 %t/Hello.cppm \
25+
// RUN: -fgen-reduced-bmi -c -o %t/AnotherName.o -### 2>&1 | \
26+
// RUN: FileCheck %t/Hello.cppm --check-prefix=CHECK-ANOTHER-NAME
27+
//
28+
// RUN: %clang -std=c++20 %t/Hello.cppm --precompile -fgen-reduced-bmi \
29+
// RUN: -o %t/Hello.full.pcm -### 2>&1 | FileCheck %t/Hello.cppm \
30+
// RUN: --check-prefix=CHECK-EMIT-MODULE-INTERFACE
31+
//
32+
// RUN: %clang -std=c++20 %t/Hello.cc -fgen-reduced-bmi -Wall -Werror \
33+
// RUN: -c -o %t/Hello.o -### 2>&1 | FileCheck %t/Hello.cc
34+
35+
//--- Hello.cppm
36+
export module Hello;
37+
38+
// Test that we won't generate the emit-module-interface as 2 phase compilation model.
39+
// CHECK-NOT: -emit-module-interface
40+
// CHECK: "-fgen-reduced-bmi"
41+
42+
// CHECK-UNSPECIFIED: -fmodule-output={{.*}}/Hello.pcm
43+
44+
// CHECK-NO-O: -fmodule-output={{.*}}/Hello.pcm
45+
// CHECK-ANOTHER-NAME: -fmodule-output={{.*}}/AnotherName.pcm
46+
47+
// With `-emit-module-interface` specified, we should still see the `-emit-module-interface`
48+
// flag.
49+
// CHECK-EMIT-MODULE-INTERFACE: -emit-module-interface
50+
51+
//--- Hello.cc
52+
53+
// CHECK-NOT: "-fgen-reduced-bmi"

0 commit comments

Comments
 (0)