Skip to content

Commit 77c6642

Browse files
committed
[C++20] [Modules] Introduce -fgen-reduced-bmi
1 parent 4d62929 commit 77c6642

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
@@ -3018,6 +3018,7 @@ defm prebuilt_implicit_modules : BoolFOption<"prebuilt-implicit-modules",
30183018

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

3035+
def gen_reduced_bmi : Flag<["-"], "fgen-reduced-bmi">,
3036+
Group<i_Group>, Visibility<[ClangOption, CC1Option]>,
3037+
HelpText<"Generate the reduced BMI">,
3038+
MarshallingInfoFlag<FrontendOpts<"GenReducedBMI">>;
3039+
30343040
def fmodules_prune_interval : Joined<["-"], "fmodules-prune-interval=">, Group<i_Group>,
30353041
Visibility<[ClangOption, CC1Option]>, MetaVarName<"<seconds>">,
30363042
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::move(Result);
1077+
Consumers[1] = std::make_unique<ReducedBMIGenerator>(
1078+
CI.getPreprocessor(), CI.getModuleCache(),
1079+
CI.getFrontendOpts().ModuleOutputPath);
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
@@ -4737,6 +4737,14 @@ Action *Driver::ConstructPhaseAction(
47374737
if (Args.hasArg(options::OPT_extract_api))
47384738
return C.MakeAction<ExtractAPIJobAction>(Input, types::TY_API_INFO);
47394739

4740+
// With '-fgen-reduced-bmi', we don't want to run the precompile phase
4741+
// unless the user specified '--precompile'. In the case the '--precompile'
4742+
// flag is enabled, we will try to emit the reduced BMI as a by product
4743+
// in GenerateModuleInterfaceAction.
4744+
if (Args.hasArg(options::OPT_gen_reduced_bmi) &&
4745+
!Args.getLastArg(options::OPT__precompile))
4746+
return Input;
4747+
47404748
types::ID OutputTy = getPrecompiledType(Input->getType());
47414749
assert(OutputTy != types::TY_INVALID &&
47424750
"Cannot precompile this input type!");
@@ -5802,19 +5810,8 @@ static const char *GetModuleOutputPath(Compilation &C, const JobAction &JA,
58025810
(C.getArgs().hasArg(options::OPT_fmodule_output) ||
58035811
C.getArgs().hasArg(options::OPT_fmodule_output_EQ)));
58045812

5805-
if (Arg *ModuleOutputEQ =
5806-
C.getArgs().getLastArg(options::OPT_fmodule_output_EQ))
5807-
return C.addResultFile(ModuleOutputEQ->getValue(), &JA);
5808-
5809-
SmallString<64> OutputPath;
5810-
Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o);
5811-
if (FinalOutput && C.getArgs().hasArg(options::OPT_c))
5812-
OutputPath = FinalOutput->getValue();
5813-
else
5814-
OutputPath = BaseInput;
5815-
5816-
const char *Extension = types::getTypeTempSuffix(JA.getType());
5817-
llvm::sys::path::replace_extension(OutputPath, Extension);
5813+
SmallString<256> OutputPath =
5814+
tools::getCXX20NamedModuleOutputPath(C.getArgs(), BaseInput);
58185815
return C.addResultFile(C.getArgs().MakeArgString(OutputPath.c_str()), &JA);
58195816
}
58205817

@@ -5901,8 +5898,10 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
59015898
// If we're emitting a module output with the specified option
59025899
// `-fmodule-output`.
59035900
if (!AtTopLevel && isa<PrecompileJobAction>(JA) &&
5904-
JA.getType() == types::TY_ModuleFile && SpecifiedModuleOutput)
5901+
JA.getType() == types::TY_ModuleFile && SpecifiedModuleOutput) {
5902+
assert(!C.getArgs().hasArg(options::OPT_gen_reduced_bmi));
59055903
return GetModuleOutputPath(C, JA, BaseInput);
5904+
}
59065905

59075906
// Output to a temporary file?
59085907
if ((!AtTopLevel && !isSaveTempsEnabled() &&

clang/lib/Driver/ToolChains/Clang.cpp

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

3780+
llvm::SmallString<256>
3781+
clang::driver::tools::getCXX20NamedModuleOutputPath(const ArgList &Args,
3782+
const char *BaseInput) {
3783+
if (Arg *ModuleOutputEQ = Args.getLastArg(options::OPT_fmodule_output_EQ))
3784+
return StringRef(ModuleOutputEQ->getValue());
3785+
3786+
SmallString<256> OutputPath;
3787+
if (Arg *FinalOutput = Args.getLastArg(options::OPT_o);
3788+
FinalOutput && Args.hasArg(options::OPT_c))
3789+
OutputPath = FinalOutput->getValue();
3790+
else
3791+
OutputPath = BaseInput;
3792+
3793+
const char *Extension = types::getTypeTempSuffix(types::TY_ModuleFile);
3794+
llvm::sys::path::replace_extension(OutputPath, Extension);
3795+
return OutputPath;
3796+
}
3797+
37803798
static bool RenderModulesOptions(Compilation &C, const Driver &D,
37813799
const ArgList &Args, const InputInfo &Input,
37823800
const InputInfo &Output, bool HaveStd20,
@@ -3965,9 +3983,26 @@ static bool RenderModulesOptions(Compilation &C, const Driver &D,
39653983
// module fragment.
39663984
CmdArgs.push_back("-fskip-odr-check-in-gmf");
39673985

3968-
// Claim `-fmodule-output` and `-fmodule-output=` to avoid unused warnings.
3969-
Args.ClaimAllArgs(options::OPT_fmodule_output);
3970-
Args.ClaimAllArgs(options::OPT_fmodule_output_EQ);
3986+
// Noop if we see '-fgen-reduced-bmi' with other translation units than module
3987+
// units. This is more user friendly to allow end uers to enable this feature
3988+
// without asking for help from build systems.
3989+
if (Args.hasArg(options::OPT_gen_reduced_bmi) &&
3990+
(Input.getType() == driver::types::TY_CXXModule ||
3991+
Input.getType() == driver::types::TY_PP_CXXModule)) {
3992+
CmdArgs.push_back("-fgen-reduced-bmi");
3993+
3994+
if (Args.hasArg(options::OPT_fmodule_output_EQ))
3995+
Args.AddLastArg(CmdArgs, options::OPT_fmodule_output_EQ);
3996+
else
3997+
CmdArgs.push_back(Args.MakeArgString(
3998+
"-fmodule-output=" +
3999+
getCXX20NamedModuleOutputPath(Args, Input.getBaseInput())));
4000+
} else {
4001+
// To avoid unused warnings.
4002+
Args.ClaimAllArgs(options::OPT_gen_reduced_bmi);
4003+
Args.ClaimAllArgs(options::OPT_fmodule_output);
4004+
Args.ClaimAllArgs(options::OPT_fmodule_output_EQ);
4005+
}
39714006

39724007
return HaveModules;
39734008
}

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)