Skip to content

Commit 8baafcd

Browse files
committed
[C++20] [Modules] Introduce -fgen-reduced-bmi
1 parent 37eb0d4 commit 8baafcd

File tree

9 files changed

+158
-2
lines changed

9 files changed

+158
-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
@@ -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 modules_reduced_bmi : Flag<["-"], "fexperimental-modules-reduced-bmi">,
3035+
Group<f_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/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
@@ -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 'fexperimental-modules-reduced-bmi', we don't want to run the
4753+
// precompile phase unless the user specified '--precompile'. In the case
4754+
// the '--precompile' flag is enabled, we will try to emit the reduced BMI
4755+
// as a by product in GenerateModuleInterfaceAction.
4756+
if (Args.hasArg(options::OPT_modules_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!");
@@ -5903,8 +5911,10 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA,
59035911
// If we're emitting a module output with the specified option
59045912
// `-fmodule-output`.
59055913
if (!AtTopLevel && isa<PrecompileJobAction>(JA) &&
5906-
JA.getType() == types::TY_ModuleFile && SpecifiedModuleOutput)
5914+
JA.getType() == types::TY_ModuleFile && SpecifiedModuleOutput) {
5915+
assert(!C.getArgs().hasArg(options::OPT_modules_reduced_bmi));
59075916
return GetModuleOutputPath(C, JA, BaseInput);
5917+
}
59085918

59095919
// Output to a temporary file?
59105920
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
@@ -284,6 +284,13 @@ GenerateModuleInterfaceAction::CreateASTConsumer(CompilerInstance &CI,
284284
if (Consumers.empty())
285285
return nullptr;
286286

287+
if (CI.getFrontendOpts().GenReducedBMI &&
288+
!CI.getFrontendOpts().ModuleOutputPath.empty()) {
289+
Consumers.push_back(std::make_unique<ReducedBMIGenerator>(
290+
CI.getPreprocessor(), CI.getModuleCache(),
291+
CI.getFrontendOpts().ModuleOutputPath));
292+
}
293+
287294
return std::make_unique<MultiplexConsumer>(std::move(Consumers));
288295
}
289296

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)