Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -2719,7 +2719,7 @@ MetaVarName<"-">, HelpText<"Pass to plugin ">; def fpass_plugin_EQ : Joined<["-"], "fpass-plugin=">, - Group, Flags<[CC1Option]>, MetaVarName<"">, + Group, Flags<[CC1Option,FlangOption,FC1Option]>, MetaVarName<"">, HelpText<"Load pass plugin from a dynamic shared object file (only with new pass manager).">, MarshallingInfoStringVector>; defm preserve_as_comments : BoolFOption<"preserve-as-comments", Index: clang/lib/Driver/ToolChains/Flang.h =================================================================== --- clang/lib/Driver/ToolChains/Flang.h +++ clang/lib/Driver/ToolChains/Flang.h @@ -45,15 +45,16 @@ /// /// \param [in] Args The list of input driver arguments /// \param [out] CmdArgs The list of output command arguments - void AddPicOptions(const llvm::opt::ArgList &Args, + void addPicOptions(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; - /// This method will effectively copy options from \a Args into \a CmdArgs. + /// Extract other compilation options from the driver arguments and add them + /// to the command arguments. /// /// \param [in] Args The list of input driver arguments /// \param [out] CmdArgs The list of output command arguments - void forwardOptions(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const; + void addOtherOptions(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; public: Flang(const ToolChain &TC); Index: clang/lib/Driver/ToolChains/Flang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Flang.cpp +++ clang/lib/Driver/ToolChains/Flang.cpp @@ -51,15 +51,15 @@ options::OPT_I, options::OPT_cpp, options::OPT_nocpp}); } -void Flang::forwardOptions(const ArgList &Args, ArgStringList &CmdArgs) const { +void Flang::addOtherOptions(const ArgList &Args, ArgStringList &CmdArgs) const { Args.AddAllArgs(CmdArgs, {options::OPT_module_dir, options::OPT_fdebug_module_writer, options::OPT_fintrinsic_modules_path, options::OPT_pedantic, options::OPT_std_EQ, options::OPT_W_Joined, - options::OPT_fconvert_EQ}); + options::OPT_fconvert_EQ, options::OPT_fpass_plugin_EQ}); } -void Flang::AddPicOptions(const ArgList &Args, ArgStringList &CmdArgs) const { +void Flang::addPicOptions(const ArgList &Args, ArgStringList &CmdArgs) const { // ParsePICArgs parses -fPIC/-fPIE and their variants and returns a tuple of // (RelocationModel, PICLevel, IsPIE). llvm::Reloc::Model RelocationModel; @@ -238,13 +238,13 @@ CmdArgs.push_back("-fcolor-diagnostics"); // -fPIC and related options. - AddPicOptions(Args, CmdArgs); + addPicOptions(Args, CmdArgs); // Floating point related options addFloatingPointOptions(D, Args, CmdArgs); - // Handle options which are simply forwarded to -fc1. - forwardOptions(Args, CmdArgs); + // Add other compile options + addOtherOptions(Args, CmdArgs); // Forward -Xflang arguments to -fc1 Args.AddAllArgValues(CmdArgs, options::OPT_Xflang); Index: flang/docs/FlangDriver.md =================================================================== --- flang/docs/FlangDriver.md +++ flang/docs/FlangDriver.md @@ -507,3 +507,28 @@ to re-analyze expressions and modify scope or symbols. You can check [Semantics.md](Semantics.md) for more details on how `ParseTree` is edited e.g. during the semantic checks. + +# LLVM Pass Plugins + +Pass plugins are dynamic shared objects that consist of one or more LLVM IR +passes. The `-fpass-plugin` option enables these passes to be passed to the +middle-end where they are added to the optimization pass pipeline and run after +lowering to LLVM IR.The exact position of the pass in the pipeline will depend +on how it has been registered with the `llvm::PassBuilder`. See the +documentation for +[`llvm::PassBuilder`](https://llvm.org/doxygen/classllvm_1_1PassBuilder.html) +for details. + +The framework to enable pass plugins in `flang-new` uses the exact same +machinery as that used by `clang` and thus has the same capabilities and +limitations. + +In order to use a pass plugin, the pass(es) must be compiled into a dynamic +shared object which is then loaded using the `-fpass-plugin` option. + +``` +flang-new -fpass-plugin=/path/to/plugin.so +``` + +This option is available in both the compiler driver and the frontend driver. +Note that LLVM plugins are not officially supported on Windows. Index: flang/docs/ReleaseNotes.md =================================================================== --- flang/docs/ReleaseNotes.md +++ flang/docs/ReleaseNotes.md @@ -24,6 +24,10 @@ ## Major New Features +* Flang now supports loading LLVM pass plugins with the `-fpass-plugin` option + which is also available in clang. The option mimics the behavior of the + corresponding option in clang and has the same capabilities and limitations. + ## Bug Fixes ## Non-comprehensive list of changes in this release Index: flang/include/flang/Frontend/CodeGenOptions.h =================================================================== --- flang/include/flang/Frontend/CodeGenOptions.h +++ flang/include/flang/Frontend/CodeGenOptions.h @@ -46,6 +46,9 @@ class CodeGenOptions : public CodeGenOptionsBase { public: + /// The paths to the pass plugins that were registered using -fpass-plugin. + std::vector LLVMPassPlugins; + // Define accessors/mutators for code generation options of enumeration type. #define CODEGENOPT(Name, Bits, Default) #define ENUM_CODEGENOPT(Name, Type, Bits, Default) \ Index: flang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- flang/lib/Frontend/CompilerInvocation.cpp +++ flang/lib/Frontend/CompilerInvocation.cpp @@ -125,6 +125,9 @@ clang::driver::options::OPT_fno_debug_pass_manager, false)) opts.DebugPassManager = 1; + for (auto *a : args.filtered(clang::driver::options::OPT_fpass_plugin_EQ)) + opts.LLVMPassPlugins.push_back(a->getValue()); + // -mrelocation-model option. if (const llvm::opt::Arg *A = args.getLastArg(clang::driver::options::OPT_mrelocation_model)) { Index: flang/lib/Frontend/FrontendActions.cpp =================================================================== --- flang/lib/Frontend/FrontendActions.cpp +++ flang/lib/Frontend/FrontendActions.cpp @@ -48,6 +48,7 @@ #include "llvm/IRReader/IRReader.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Passes/PassBuilder.h" +#include "llvm/Passes/PassPlugin.h" #include "llvm/Passes/StandardInstrumentations.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/SourceMgr.h" @@ -675,6 +676,7 @@ void CodeGenAction::runOptimizationPipeline(llvm::raw_pwrite_stream &os) { auto opts = getInstance().getInvocation().getCodeGenOpts(); + auto &diags = getInstance().getDiagnostics(); llvm::OptimizationLevel level = mapToLevel(opts); // Create the analysis managers. @@ -691,6 +693,17 @@ si.registerCallbacks(pic, &fam); llvm::PassBuilder pb(tm.get(), pto, pgoOpt, &pic); + // Attempt to load pass plugins and register their callbacks with PB. + for (auto &pluginFile : opts.LLVMPassPlugins) { + auto passPlugin = llvm::PassPlugin::Load(pluginFile); + if (passPlugin) { + passPlugin->registerPassBuilderCallbacks(pb); + } else { + diags.Report(clang::diag::err_fe_unable_to_load_plugin) + << pluginFile << passPlugin.takeError(); + } + } + // Register all the basic analyses with the managers. pb.registerModuleAnalyses(mam); pb.registerCGSCCAnalyses(cgam); Index: flang/test/CMakeLists.txt =================================================================== --- flang/test/CMakeLists.txt +++ flang/test/CMakeLists.txt @@ -63,6 +63,9 @@ Fortran_main FortranDecimal ) +if (LLVM_ENABLE_PLUGINS) + list(APPEND FLANG_TEST_DEPENDS Bye) +endif() if (FLANG_INCLUDE_TESTS) if (FLANG_GTEST_AVAIL) Index: flang/test/Driver/driver-help-hidden.f90 =================================================================== --- flang/test/Driver/driver-help-hidden.f90 +++ flang/test/Driver/driver-help-hidden.f90 @@ -48,6 +48,7 @@ ! CHECK-NEXT: -fno-signed-zeros Allow optimizations that ignore the sign of floating point zeros ! CHECK-NEXT: -fopenacc Enable OpenACC ! CHECK-NEXT: -fopenmp Parse OpenMP pragmas and generate parallel code. +! CHECK-NEXT: -fpass-plugin= Load pass plugin from a dynamic shared object file (only with new pass manager). ! CHECK-NEXT: -freciprocal-math Allow division operations to be reassociated ! CHECK-NEXT: -fsyntax-only Run the preprocessor, parser and semantic analysis stages ! CHECK-NEXT: -fxor-operator Enable .XOR. as a synonym of .NEQV. @@ -76,4 +77,3 @@ ! Frontend driver -help-hidden is not supported ! ERROR-FLANG-FC1: error: unknown argument: '{{.*}}' - Index: flang/test/Driver/driver-help.f90 =================================================================== --- flang/test/Driver/driver-help.f90 +++ flang/test/Driver/driver-help.f90 @@ -46,6 +46,7 @@ ! HELP-NEXT: -fno-signed-zeros Allow optimizations that ignore the sign of floating point zeros ! HELP-NEXT: -fopenacc Enable OpenACC ! HELP-NEXT: -fopenmp Parse OpenMP pragmas and generate parallel code. +! HELP-NEXT: -fpass-plugin= Load pass plugin from a dynamic shared object file (only with new pass manager). ! HELP-NEXT: -freciprocal-math Allow division operations to be reassociated ! HELP-NEXT: -fsyntax-only Run the preprocessor, parser and semantic analysis stages ! HELP-NEXT: -fxor-operator Enable .XOR. as a synonym of .NEQV. @@ -129,6 +130,7 @@ ! HELP-FC1-NEXT: -fno-signed-zeros Allow optimizations that ignore the sign of floating point zeros ! HELP-FC1-NEXT: -fopenacc Enable OpenACC ! HELP-FC1-NEXT: -fopenmp Parse OpenMP pragmas and generate parallel code. +! HELP-FC1-NEXT: -fpass-plugin= Load pass plugin from a dynamic shared object file (only with new pass manager). ! HELP-FC1-NEXT: -freciprocal-math Allow division operations to be reassociated ! HELP-FC1-NEXT: -fsyntax-only Run the preprocessor, parser and semantic analysis stages ! HELP-FC1-NEXT: -fxor-operator Enable .XOR. as a synonym of .NEQV. Index: flang/test/Driver/frontend-forwarding.f90 =================================================================== --- flang/test/Driver/frontend-forwarding.f90 +++ flang/test/Driver/frontend-forwarding.f90 @@ -15,6 +15,7 @@ ! RUN: -fno-signed-zeros \ ! RUN: -fassociative-math \ ! RUN: -freciprocal-math \ +! RUN: -fpass-plugin=Bye%pluginext \ ! RUN: -mllvm -print-before-all\ ! RUN: -P \ ! RUN: | FileCheck %s @@ -33,4 +34,5 @@ ! CHECK: "-mreassociate" ! CHECK: "-freciprocal-math" ! CHECK: "-fconvert=little-endian" -! CHECK: "-mllvm" "-print-before-all" +! CHECK: "-fpass-plugin=Bye +! CHECK: "-mllvm" "-print-before-all" Index: flang/test/Driver/pass-plugin-not-found.f90 =================================================================== --- /dev/null +++ flang/test/Driver/pass-plugin-not-found.f90 @@ -0,0 +1,8 @@ +! Check the correct error diagnostic is reported when a pass plugin shared object isn't found + +! REQUIRES: plugins, shell + +! RUN: not %flang -fpass-plugin=X.Y %s 2>&1 | FileCheck %s --check-prefix=ERROR +! RUN: not %flang_fc1 -emit-llvm -o /dev/null -fpass-plugin=X.Y %s 2>&1 | FileCheck %s --check-prefix=ERROR + +! ERROR: error: unable to load plugin 'X.Y': 'Could not load library 'X.Y': X.Y: cannot open shared object file: No such file or directory' Index: flang/test/Driver/pass-plugin.f90 =================================================================== --- /dev/null +++ flang/test/Driver/pass-plugin.f90 @@ -0,0 +1,13 @@ +! Verify that the plugin passed to -fpass-plugin is loaded and run + +! UNSUPPORTED: system-windows + +! REQUIRES: plugins, shell + +! RUN: %flang -S %s -fpass-plugin=%llvmshlibdir/Bye%pluginext -Xflang -fdebug-pass-manager -o /dev/null 2>&1 | FileCheck %s +! RUN: %flang_fc1 -S %s -fpass-plugin=%llvmshlibdir/Bye%pluginext -fdebug-pass-manager -o /dev/null 2>&1 | FileCheck %s + +! CHECK: Running pass: {{.*}}Bye on empty_ + +subroutine empty +end subroutine empty