diff options
author | Chuanqi Xu <yedeng.yd@linux.alibaba.com> | 2024-04-15 11:55:45 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-15 11:55:45 +0800 |
commit | f811d7b50957b801788d7b171ddeb25b1fda415a (patch) | |
tree | f7e3bd860856eb29ed670b383560d17807d87b2d | |
parent | 1e16a35fbcc6b21d1bee597c7e76f2444b7000e5 (diff) | |
download | llvm-f811d7b50957b801788d7b171ddeb25b1fda415a.zip llvm-f811d7b50957b801788d7b171ddeb25b1fda415a.tar.gz llvm-f811d7b50957b801788d7b171ddeb25b1fda415a.tar.bz2 |
[C++20] [Modules] Introduce -fexperimental-modules-reduced-bmi (#85050)
This is the driver part of
https://github.com/llvm/llvm-project/pull/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.
-rw-r--r-- | clang/include/clang/CodeGen/CodeGenAction.h | 2 | ||||
-rw-r--r-- | clang/include/clang/Driver/Options.td | 6 | ||||
-rw-r--r-- | clang/include/clang/Frontend/FrontendOptions.h | 10 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenAction.cpp | 19 | ||||
-rw-r--r-- | clang/lib/Driver/Driver.cpp | 12 | ||||
-rw-r--r-- | clang/lib/Driver/ToolChains/Clang.cpp | 18 | ||||
-rw-r--r-- | clang/lib/Frontend/FrontendActions.cpp | 7 | ||||
-rw-r--r-- | clang/test/Driver/module-fgen-reduced-bmi.cppm | 51 | ||||
-rw-r--r-- | clang/test/Modules/modules-reduced-bmi.cppm | 36 |
9 files changed, 159 insertions, 2 deletions
diff --git a/clang/include/clang/CodeGen/CodeGenAction.h b/clang/include/clang/CodeGen/CodeGenAction.h index 7ad2988..186dbb4 100644 --- a/clang/include/clang/CodeGen/CodeGenAction.h +++ b/clang/include/clang/CodeGen/CodeGenAction.h @@ -57,6 +57,8 @@ private: bool loadLinkModules(CompilerInstance &CI); protected: + bool BeginSourceFileAction(CompilerInstance &CI) override; + /// Create a new code generation action. If the optional \p _VMContext /// parameter is supplied, the action uses it without taking ownership, /// otherwise it creates a fresh LLVM context and takes ownership. diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 9a0b5d3..e246269 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -3036,6 +3036,7 @@ defm prebuilt_implicit_modules : BoolFOption<"prebuilt-implicit-modules", def fmodule_output_EQ : Joined<["-"], "fmodule-output=">, Flags<[NoXarchOption]>, Visibility<[ClangOption, CC1Option]>, + MarshallingInfoString<FrontendOpts<"ModuleOutputPath">>, HelpText<"Save intermediate module file results when compiling a standard C++ module unit.">; def fmodule_output : Flag<["-"], "fmodule-output">, Flags<[NoXarchOption]>, Visibility<[ClangOption, CC1Option]>, @@ -3049,6 +3050,11 @@ defm skip_odr_check_in_gmf : BoolOption<"f", "skip-odr-check-in-gmf", "Perform ODR checks for decls in the global module fragment.">>, Group<f_Group>; +def modules_reduced_bmi : Flag<["-"], "fexperimental-modules-reduced-bmi">, + Group<f_Group>, Visibility<[ClangOption, CC1Option]>, + HelpText<"Generate the reduced BMI">, + MarshallingInfoFlag<FrontendOpts<"GenReducedBMI">>; + def fmodules_prune_interval : Joined<["-"], "fmodules-prune-interval=">, Group<i_Group>, Visibility<[ClangOption, CC1Option]>, MetaVarName<"<seconds>">, HelpText<"Specify the interval (in seconds) between attempts to prune the module cache">, diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h index 5ee4d47..a738c1f 100644 --- a/clang/include/clang/Frontend/FrontendOptions.h +++ b/clang/include/clang/Frontend/FrontendOptions.h @@ -404,6 +404,10 @@ public: LLVM_PREFERRED_TYPE(bool) unsigned EmitPrettySymbolGraphs : 1; + /// Whether to generate reduced BMI for C++20 named modules. + LLVM_PREFERRED_TYPE(bool) + unsigned GenReducedBMI : 1; + CodeCompleteOptions CodeCompleteOpts; /// Specifies the output format of the AST. @@ -568,6 +572,9 @@ public: /// Path which stores the output files for -ftime-trace std::string TimeTracePath; + /// Output Path for module output file. + std::string ModuleOutputPath; + public: FrontendOptions() : DisableFree(false), RelocatablePCH(false), ShowHelp(false), @@ -582,7 +589,8 @@ public: AllowPCMWithCompilerErrors(false), ModulesShareFileManager(true), EmitSymbolGraph(false), EmitExtensionSymbolGraphs(false), EmitSymbolGraphSymbolLabelsForTesting(false), - EmitPrettySymbolGraphs(false), TimeTraceGranularity(500) {} + EmitPrettySymbolGraphs(false), GenReducedBMI(false), + TimeTraceGranularity(500) {} /// getInputKindForExtension - Return the appropriate input kind for a file /// extension. For example, "c" would return Language::C. diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index bb9aaba..1a6b628 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -25,8 +25,11 @@ #include "clang/CodeGen/ModuleBuilder.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/MultiplexConsumer.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Serialization/ASTWriter.h" #include "llvm/ADT/Hashing.h" #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h" @@ -1003,6 +1006,12 @@ CodeGenerator *CodeGenAction::getCodeGenerator() const { return BEConsumer->getCodeGenerator(); } +bool CodeGenAction::BeginSourceFileAction(CompilerInstance &CI) { + if (CI.getFrontendOpts().GenReducedBMI) + CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleInterface); + return true; +} + static std::unique_ptr<raw_pwrite_stream> GetOutputStream(CompilerInstance &CI, StringRef InFile, BackendAction Action) { switch (Action) { @@ -1061,6 +1070,16 @@ CodeGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { CI.getPreprocessor().addPPCallbacks(std::move(Callbacks)); } + if (CI.getFrontendOpts().GenReducedBMI && + !CI.getFrontendOpts().ModuleOutputPath.empty()) { + std::vector<std::unique_ptr<ASTConsumer>> Consumers(2); + Consumers[0] = std::make_unique<ReducedBMIGenerator>( + CI.getPreprocessor(), CI.getModuleCache(), + CI.getFrontendOpts().ModuleOutputPath); + Consumers[1] = std::move(Result); + return std::make_unique<MultiplexConsumer>(std::move(Consumers)); + } + return std::move(Result); } diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index e7335a6..0da9200 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -4756,6 +4756,14 @@ Action *Driver::ConstructPhaseAction( if (Args.hasArg(options::OPT_extract_api)) return C.MakeAction<ExtractAPIJobAction>(Input, types::TY_API_INFO); + // With 'fexperimental-modules-reduced-bmi', we don't want to run the + // precompile phase unless the user specified '--precompile'. In the case + // the '--precompile' flag is enabled, we will try to emit the reduced BMI + // as a by product in GenerateModuleInterfaceAction. + if (Args.hasArg(options::OPT_modules_reduced_bmi) && + !Args.getLastArg(options::OPT__precompile)) + return Input; + types::ID OutputTy = getPrecompiledType(Input->getType()); assert(OutputTy != types::TY_INVALID && "Cannot precompile this input type!"); @@ -5916,8 +5924,10 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, // If we're emitting a module output with the specified option // `-fmodule-output`. if (!AtTopLevel && isa<PrecompileJobAction>(JA) && - JA.getType() == types::TY_ModuleFile && SpecifiedModuleOutput) + JA.getType() == types::TY_ModuleFile && SpecifiedModuleOutput) { + assert(!C.getArgs().hasArg(options::OPT_modules_reduced_bmi)); return GetModuleOutputPath(C, JA, BaseInput); + } // Output to a temporary file? if ((!AtTopLevel && !isSaveTempsEnabled() && diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 766a9b91..6d52ece 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -4045,6 +4045,24 @@ static bool RenderModulesOptions(Compilation &C, const Driver &D, // module fragment. CmdArgs.push_back("-fskip-odr-check-in-gmf"); + if (Args.hasArg(options::OPT_modules_reduced_bmi) && + (Input.getType() == driver::types::TY_CXXModule || + Input.getType() == driver::types::TY_PP_CXXModule)) { + CmdArgs.push_back("-fexperimental-modules-reduced-bmi"); + + if (Args.hasArg(options::OPT_fmodule_output_EQ)) + Args.AddLastArg(CmdArgs, options::OPT_fmodule_output_EQ); + else + CmdArgs.push_back(Args.MakeArgString( + "-fmodule-output=" + + getCXX20NamedModuleOutputPath(Args, Input.getBaseInput()))); + } + + // Noop if we see '-fexperimental-modules-reduced-bmi' with other translation + // units than module units. This is more user friendly to allow end uers to + // enable this feature without asking for help from build systems. + Args.ClaimAllArgs(options::OPT_modules_reduced_bmi); + // We need to include the case the input file is a module file here. // Since the default compilation model for C++ module interface unit will // create temporary module file and compile the temporary module file diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index 642b14d..04eb104 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -281,6 +281,13 @@ GenerateModuleInterfaceAction::CreateASTConsumer(CompilerInstance &CI, if (Consumers.empty()) return nullptr; + if (CI.getFrontendOpts().GenReducedBMI && + !CI.getFrontendOpts().ModuleOutputPath.empty()) { + Consumers.push_back(std::make_unique<ReducedBMIGenerator>( + CI.getPreprocessor(), CI.getModuleCache(), + CI.getFrontendOpts().ModuleOutputPath)); + } + return std::make_unique<MultiplexConsumer>(std::move(Consumers)); } diff --git a/clang/test/Driver/module-fgen-reduced-bmi.cppm b/clang/test/Driver/module-fgen-reduced-bmi.cppm new file mode 100644 index 0000000..1223189 --- /dev/null +++ b/clang/test/Driver/module-fgen-reduced-bmi.cppm @@ -0,0 +1,51 @@ +// It is annoying to handle different slash direction +// in Windows and Linux. So we disable the test on Windows +// here. +// REQUIRES: !system-windows +// On AIX, the default output for `-c` may be `.s` instead of `.o`, +// which makes the test fail. So disable the test on AIX. +// UNSUPPORTED: system-aix +// +// RUN: rm -rf %t && split-file %s %t && cd %t +// +// RUN: %clang -std=c++20 Hello.cppm -fmodule-output=Hello.pcm \ +// RUN: -fexperimental-modules-reduced-bmi -c -o Hello.o -### 2>&1 | FileCheck Hello.cppm +// +// RUN: %clang -std=c++20 Hello.cppm \ +// RUN: -fexperimental-modules-reduced-bmi -c -o Hello.o -### 2>&1 | \ +// RUN: FileCheck Hello.cppm --check-prefix=CHECK-UNSPECIFIED +// +// RUN: %clang -std=c++20 Hello.cppm \ +// RUN: -fexperimental-modules-reduced-bmi -c -### 2>&1 | \ +// RUN: FileCheck Hello.cppm --check-prefix=CHECK-NO-O +// +// RUN: %clang -std=c++20 Hello.cppm \ +// RUN: -fexperimental-modules-reduced-bmi -c -o AnotherName.o -### 2>&1 | \ +// RUN: FileCheck Hello.cppm --check-prefix=CHECK-ANOTHER-NAME +// +// RUN: %clang -std=c++20 Hello.cppm --precompile -fexperimental-modules-reduced-bmi \ +// RUN: -o Hello.full.pcm -### 2>&1 | FileCheck Hello.cppm \ +// RUN: --check-prefix=CHECK-EMIT-MODULE-INTERFACE +// +// RUN: %clang -std=c++20 Hello.cc -fexperimental-modules-reduced-bmi -Wall -Werror \ +// RUN: -c -o Hello.o -### 2>&1 | FileCheck Hello.cc + +//--- Hello.cppm +export module Hello; + +// Test that we won't generate the emit-module-interface as 2 phase compilation model. +// CHECK-NOT: -emit-module-interface +// CHECK: "-fexperimental-modules-reduced-bmi" + +// CHECK-UNSPECIFIED: -fmodule-output=Hello.pcm + +// CHECK-NO-O: -fmodule-output=Hello.pcm +// CHECK-ANOTHER-NAME: -fmodule-output=AnotherName.pcm + +// With `-emit-module-interface` specified, we should still see the `-emit-module-interface` +// flag. +// CHECK-EMIT-MODULE-INTERFACE: -emit-module-interface + +//--- Hello.cc + +// CHECK-NOT: "-fexperimental-modules-reduced-bmi" diff --git a/clang/test/Modules/modules-reduced-bmi.cppm b/clang/test/Modules/modules-reduced-bmi.cppm new file mode 100644 index 0000000..9b84220 --- /dev/null +++ b/clang/test/Modules/modules-reduced-bmi.cppm @@ -0,0 +1,36 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-reduced-module-interface -o %t/a.reduced.pcm +// RUN: %clang_cc1 -std=c++20 %t/a.cppm -fexperimental-modules-reduced-bmi -fmodule-output=%t/a.pcm \ +// RUN: -S -emit-llvm -o %t/a.ll +// +// Test that the generated BMI from `-fexperimental-modules-reduced-bmi -fmodule-output=` is same with +// `-emit-reduced-module-interface`. +// RUN: diff %t/a.reduced.pcm %t/a.pcm +// +// Test that we can consume the produced BMI correctly. +// RUN: %clang_cc1 -std=c++20 %t/b.cppm -fmodule-file=a=%t/a.pcm -fsyntax-only -verify +// +// RUN: rm -f %t/a.pcm +// RUN: %clang_cc1 -std=c++20 %t/a.cppm -fexperimental-modules-reduced-bmi -fmodule-output=%t/a.pcm \ +// RUN: -emit-module-interface -o %t/a.full.pcm +// RUN: diff %t/a.reduced.pcm %t/a.pcm +// RUN: not diff %t/a.pcm %t/a.full.pcm +// +// RUN: %clang_cc1 -std=c++20 %t/b.cppm -fmodule-file=a=%t/a.pcm -fsyntax-only -verify +// RUN: %clang_cc1 -std=c++20 %t/b.cppm -fmodule-file=a=%t/a.full.pcm -fsyntax-only -verify + +//--- a.cppm +export module a; +export int a() { + return 43; +} + +//--- b.cppm +// Test that we can consume the produced BMI correctly as a smocking test. +// expected-no-diagnostics +export module b; +import a; +export int b() { return a(); } |