Skip to content

Commit fe6a0af

Browse files
ChuanqiXu9aniplcc
authored andcommitted
[C++20] [Modules] Introduce -fexperimental-modules-reduced-bmi (llvm#85050)
This is the driver part of llvm#75894. This patch introduces '-fexperimental-modules-reduced-bmi' to enable generating the reduced BMI. This patch did: - When `-fexperimental-modules-reduced-bmi` is specified but `--precompile` is not specified for a module unit, we'll skip the precompile phase to avoid unnecessary two-phase compilation phases. Then if `-c` is specified, we will generate the reduced BMI in CodeGenAction as a by-product. - When `-fexperimental-modules-reduced-bmi` is specified and `--precompile` is specified, we will generate the reduced BMI in GenerateModuleInterfaceAction as a by-product. - When `-fexperimental-modules-reduced-bmi` is specified for a non-module unit. We don't do anything nor try to give a warn. This is more user friendly so that the end users can try to test and experiment with the feature without asking help from the build systems. The core design idea is that users should be able to enable this easily with the existing cmake mechanisms. The future plan for the flag is: - Add this to clang19 and make it opt-in for 1~2 releases. It depends on the testing feedback to decide how long we like to make it opt-in. - Then we can announce the existing BMI generating may be deprecated and suggesting people (end users or build systems) to enable this for 1~2 releases. - Finally we will enable this by default. When that time comes, the term `BMI` will refer to the reduced BMI today and the existing BMI will only be meaningful to build systems which loves to support two phase compilations. I'll send release notes and document in seperate commits after this get landed.
1 parent 7e0b154 commit fe6a0af

File tree

9 files changed

+159
-2
lines changed

9 files changed

+159
-2
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
@@ -3036,6 +3036,7 @@ defm prebuilt_implicit_modules : BoolFOption<"prebuilt-implicit-modules",
30363036

30373037
def fmodule_output_EQ : Joined<["-"], "fmodule-output=">,
30383038
Flags<[NoXarchOption]>, Visibility<[ClangOption, CC1Option]>,
3039+
MarshallingInfoString<FrontendOpts<"ModuleOutputPath">>,
30393040
HelpText<"Save intermediate module file results when compiling a standard C++ module unit.">;
30403041
def fmodule_output : Flag<["-"], "fmodule-output">, Flags<[NoXarchOption]>,
30413042
Visibility<[ClangOption, CC1Option]>,
@@ -3049,6 +3050,11 @@ defm skip_odr_check_in_gmf : BoolOption<"f", "skip-odr-check-in-gmf",
30493050
"Perform ODR checks for decls in the global module fragment.">>,
30503051
Group<f_Group>;
30513052

3053+
def modules_reduced_bmi : Flag<["-"], "fexperimental-modules-reduced-bmi">,
3054+
Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
3055+
HelpText<"Generate the reduced BMI">,
3056+
MarshallingInfoFlag<FrontendOpts<"GenReducedBMI">>;
3057+
30523058
def fmodules_prune_interval : Joined<["-"], "fmodules-prune-interval=">, Group<i_Group>,
30533059
Visibility<[ClangOption, CC1Option]>, MetaVarName<"<seconds>">,
30543060
HelpText<"Specify the interval (in seconds) between attempts to prune the module cache">,

clang/include/clang/Frontend/FrontendOptions.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,10 @@ class FrontendOptions {
404404
LLVM_PREFERRED_TYPE(bool)
405405
unsigned EmitPrettySymbolGraphs : 1;
406406

407+
/// Whether to generate reduced BMI for C++20 named modules.
408+
LLVM_PREFERRED_TYPE(bool)
409+
unsigned GenReducedBMI : 1;
410+
407411
CodeCompleteOptions CodeCompleteOpts;
408412

409413
/// Specifies the output format of the AST.
@@ -568,6 +572,9 @@ class FrontendOptions {
568572
/// Path which stores the output files for -ftime-trace
569573
std::string TimeTracePath;
570574

575+
/// Output Path for module output file.
576+
std::string ModuleOutputPath;
577+
571578
public:
572579
FrontendOptions()
573580
: DisableFree(false), RelocatablePCH(false), ShowHelp(false),
@@ -582,7 +589,8 @@ class FrontendOptions {
582589
AllowPCMWithCompilerErrors(false), ModulesShareFileManager(true),
583590
EmitSymbolGraph(false), EmitExtensionSymbolGraphs(false),
584591
EmitSymbolGraphSymbolLabelsForTesting(false),
585-
EmitPrettySymbolGraphs(false), TimeTraceGranularity(500) {}
592+
EmitPrettySymbolGraphs(false), GenReducedBMI(false),
593+
TimeTraceGranularity(500) {}
586594

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

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: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4756,6 +4756,14 @@ Action *Driver::ConstructPhaseAction(
47564756
if (Args.hasArg(options::OPT_extract_api))
47574757
return C.MakeAction<ExtractAPIJobAction>(Input, types::TY_API_INFO);
47584758

4759+
// With 'fexperimental-modules-reduced-bmi', we don't want to run the
4760+
// precompile phase unless the user specified '--precompile'. In the case
4761+
// the '--precompile' flag is enabled, we will try to emit the reduced BMI
4762+
// as a by product in GenerateModuleInterfaceAction.
4763+
if (Args.hasArg(options::OPT_modules_reduced_bmi) &&
4764+
!Args.getLastArg(options::OPT__precompile))
4765+
return Input;
4766+
47594767
types::ID OutputTy = getPrecompiledType(Input->getType());
47604768
assert(OutputTy != types::TY_INVALID &&
47614769
"Cannot precompile this input type!");
@@ -5916,8 +5924,10 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
59165924
// If we're emitting a module output with the specified option
59175925
// `-fmodule-output`.
59185926
if (!AtTopLevel && isa<PrecompileJobAction>(JA) &&
5919-
JA.getType() == types::TY_ModuleFile && SpecifiedModuleOutput)
5927+
JA.getType() == types::TY_ModuleFile && SpecifiedModuleOutput) {
5928+
assert(!C.getArgs().hasArg(options::OPT_modules_reduced_bmi));
59205929
return GetModuleOutputPath(C, JA, BaseInput);
5930+
}
59215931

59225932
// Output to a temporary file?
59235933
if ((!AtTopLevel && !isSaveTempsEnabled() &&

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4045,6 +4045,24 @@ static bool RenderModulesOptions(Compilation &C, const Driver &D,
40454045
// module fragment.
40464046
CmdArgs.push_back("-fskip-odr-check-in-gmf");
40474047

4048+
if (Args.hasArg(options::OPT_modules_reduced_bmi) &&
4049+
(Input.getType() == driver::types::TY_CXXModule ||
4050+
Input.getType() == driver::types::TY_PP_CXXModule)) {
4051+
CmdArgs.push_back("-fexperimental-modules-reduced-bmi");
4052+
4053+
if (Args.hasArg(options::OPT_fmodule_output_EQ))
4054+
Args.AddLastArg(CmdArgs, options::OPT_fmodule_output_EQ);
4055+
else
4056+
CmdArgs.push_back(Args.MakeArgString(
4057+
"-fmodule-output=" +
4058+
getCXX20NamedModuleOutputPath(Args, Input.getBaseInput())));
4059+
}
4060+
4061+
// Noop if we see '-fexperimental-modules-reduced-bmi' with other translation
4062+
// units than module units. This is more user friendly to allow end uers to
4063+
// enable this feature without asking for help from build systems.
4064+
Args.ClaimAllArgs(options::OPT_modules_reduced_bmi);
4065+
40484066
// We need to include the case the input file is a module file here.
40494067
// Since the default compilation model for C++ module interface unit will
40504068
// create temporary module file and compile the temporary module file

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

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
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+
// UNSUPPORTED: system-aix
8+
//
9+
// RUN: rm -rf %t && split-file %s %t && cd %t
10+
//
11+
// RUN: %clang -std=c++20 Hello.cppm -fmodule-output=Hello.pcm \
12+
// RUN: -fexperimental-modules-reduced-bmi -c -o Hello.o -### 2>&1 | FileCheck Hello.cppm
13+
//
14+
// RUN: %clang -std=c++20 Hello.cppm \
15+
// RUN: -fexperimental-modules-reduced-bmi -c -o Hello.o -### 2>&1 | \
16+
// RUN: FileCheck Hello.cppm --check-prefix=CHECK-UNSPECIFIED
17+
//
18+
// RUN: %clang -std=c++20 Hello.cppm \
19+
// RUN: -fexperimental-modules-reduced-bmi -c -### 2>&1 | \
20+
// RUN: FileCheck Hello.cppm --check-prefix=CHECK-NO-O
21+
//
22+
// RUN: %clang -std=c++20 Hello.cppm \
23+
// RUN: -fexperimental-modules-reduced-bmi -c -o AnotherName.o -### 2>&1 | \
24+
// RUN: FileCheck Hello.cppm --check-prefix=CHECK-ANOTHER-NAME
25+
//
26+
// RUN: %clang -std=c++20 Hello.cppm --precompile -fexperimental-modules-reduced-bmi \
27+
// RUN: -o Hello.full.pcm -### 2>&1 | FileCheck Hello.cppm \
28+
// RUN: --check-prefix=CHECK-EMIT-MODULE-INTERFACE
29+
//
30+
// RUN: %clang -std=c++20 Hello.cc -fexperimental-modules-reduced-bmi -Wall -Werror \
31+
// RUN: -c -o Hello.o -### 2>&1 | FileCheck Hello.cc
32+
33+
//--- Hello.cppm
34+
export module Hello;
35+
36+
// Test that we won't generate the emit-module-interface as 2 phase compilation model.
37+
// CHECK-NOT: -emit-module-interface
38+
// CHECK: "-fexperimental-modules-reduced-bmi"
39+
40+
// CHECK-UNSPECIFIED: -fmodule-output=Hello.pcm
41+
42+
// CHECK-NO-O: -fmodule-output=Hello.pcm
43+
// CHECK-ANOTHER-NAME: -fmodule-output=AnotherName.pcm
44+
45+
// With `-emit-module-interface` specified, we should still see the `-emit-module-interface`
46+
// flag.
47+
// CHECK-EMIT-MODULE-INTERFACE: -emit-module-interface
48+
49+
//--- Hello.cc
50+
51+
// CHECK-NOT: "-fexperimental-modules-reduced-bmi"
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: rm -rf %t
2+
// RUN: mkdir -p %t
3+
// RUN: split-file %s %t
4+
//
5+
// RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-reduced-module-interface -o %t/a.reduced.pcm
6+
// RUN: %clang_cc1 -std=c++20 %t/a.cppm -fexperimental-modules-reduced-bmi -fmodule-output=%t/a.pcm \
7+
// RUN: -S -emit-llvm -o %t/a.ll
8+
//
9+
// Test that the generated BMI from `-fexperimental-modules-reduced-bmi -fmodule-output=` is same with
10+
// `-emit-reduced-module-interface`.
11+
// RUN: diff %t/a.reduced.pcm %t/a.pcm
12+
//
13+
// Test that we can consume the produced BMI correctly.
14+
// RUN: %clang_cc1 -std=c++20 %t/b.cppm -fmodule-file=a=%t/a.pcm -fsyntax-only -verify
15+
//
16+
// RUN: rm -f %t/a.pcm
17+
// RUN: %clang_cc1 -std=c++20 %t/a.cppm -fexperimental-modules-reduced-bmi -fmodule-output=%t/a.pcm \
18+
// RUN: -emit-module-interface -o %t/a.full.pcm
19+
// RUN: diff %t/a.reduced.pcm %t/a.pcm
20+
// RUN: not diff %t/a.pcm %t/a.full.pcm
21+
//
22+
// RUN: %clang_cc1 -std=c++20 %t/b.cppm -fmodule-file=a=%t/a.pcm -fsyntax-only -verify
23+
// RUN: %clang_cc1 -std=c++20 %t/b.cppm -fmodule-file=a=%t/a.full.pcm -fsyntax-only -verify
24+
25+
//--- a.cppm
26+
export module a;
27+
export int a() {
28+
return 43;
29+
}
30+
31+
//--- b.cppm
32+
// Test that we can consume the produced BMI correctly as a smocking test.
33+
// expected-no-diagnostics
34+
export module b;
35+
import a;
36+
export int b() { return a(); }

0 commit comments

Comments
 (0)