Author: Stuart Ellis Date: 2021-07-01T08:10:40Z New Revision: 788a5d4afe6407e647454a9832a7b4a27fba06bf
URL: https://github.com/llvm/llvm-project/commit/788a5d4afe6407e647454a9832a7b4a27fba06bf DIFF: https://github.com/llvm/llvm-project/commit/788a5d4afe6407e647454a9832a7b4a27fba06bf.diff LOG: PoC for Flang Driver Plugins Added: flang/examples/HelloWorld/CMakeLists.txt flang/examples/HelloWorld/HelloWorldPlugin.cpp flang/include/flang/Frontend/FrontendPluginRegistry.h Modified: clang/include/clang/Driver/Options.td flang/CMakeLists.txt flang/examples/CMakeLists.txt flang/include/flang/Frontend/FrontendActions.h flang/include/flang/Frontend/FrontendOptions.h flang/lib/Frontend/CompilerInvocation.cpp flang/lib/Frontend/FrontendAction.cpp flang/lib/Frontend/FrontendActions.cpp flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp llvm/include/llvm/Support/Registry.h llvm/lib/Support/DynamicLibrary.cpp Removed: ################################################################################ diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 41b7299b02745..1629a74ae62c9 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -5221,10 +5221,6 @@ def enable_noundef_analysis : Flag<["-"], "enable-noundef-analysis">, Group<f_Gr def discard_value_names : Flag<["-"], "discard-value-names">, HelpText<"Discard value names in LLVM IR">, MarshallingInfoFlag<CodeGenOpts<"DiscardValueNames">>; -def load : Separate<["-"], "load">, MetaVarName<"<dsopath>">, - HelpText<"Load the named plugin (dynamic shared object)">; -def plugin : Separate<["-"], "plugin">, MetaVarName<"<name>">, - HelpText<"Use the named plugin action instead of the default action (use \"help\" to list available options)">; def plugin_arg : JoinedAndSeparate<["-"], "plugin-arg-">, MetaVarName<"<name> <arg>">, HelpText<"Pass <arg> to plugin <name>">; @@ -5788,6 +5784,12 @@ def init_only : Flag<["-"], "init-only">, HelpText<"Only execute frontend initialization">; } // let Group = Action_Group + +def load : Separate<["-"], "load">, MetaVarName<"<dsopath>">, + HelpText<"Load the named plugin (dynamic shared object)">; +def plugin : Separate<["-"], "plugin">, MetaVarName<"<name>">, + HelpText<"Use the named plugin action instead of the default action (use \"help\" to list available options)">; + } // let Flags = [CC1Option, FC1Option, NoDriverOption] //===----------------------------------------------------------------------===// diff --git a/flang/CMakeLists.txt b/flang/CMakeLists.txt index adf3dc819dc93..d9495c4748ce5 100644 --- a/flang/CMakeLists.txt +++ b/flang/CMakeLists.txt @@ -390,7 +390,6 @@ endif() include(CMakeParseArguments) include(AddFlang) - add_subdirectory(include) add_subdirectory(lib) add_subdirectory(cmake/modules) diff --git a/flang/examples/CMakeLists.txt b/flang/examples/CMakeLists.txt index 3ca9feddf33e9..f896874f7f89b 100644 --- a/flang/examples/CMakeLists.txt +++ b/flang/examples/CMakeLists.txt @@ -6,3 +6,5 @@ add_executable(external-hello-world target_link_libraries(external-hello-world FortranRuntime ) +#add_subdirectory(HelloEarth) +add_subdirectory(HelloWorld) diff --git a/flang/examples/HelloWorld/CMakeLists.txt b/flang/examples/HelloWorld/CMakeLists.txt new file mode 100644 index 0000000000000..eb716c2f17b49 --- /dev/null +++ b/flang/examples/HelloWorld/CMakeLists.txt @@ -0,0 +1,12 @@ +add_llvm_library( + flangHelloWorldPlugin + MODULE + HelloWorldPlugin.cpp + + DEPENDS + clangBasic + + LINK_COMPONENTS + Option + Support +) diff --git a/flang/examples/HelloWorld/HelloWorldPlugin.cpp b/flang/examples/HelloWorld/HelloWorldPlugin.cpp new file mode 100644 index 0000000000000..30d23ce104227 --- /dev/null +++ b/flang/examples/HelloWorld/HelloWorldPlugin.cpp @@ -0,0 +1,18 @@ +#include "flang/Frontend/FrontendActions.h" +#include "flang/Frontend/FrontendPluginRegistry.h" + +__attribute__((constructor)) +static void printing() { + llvm::outs() << " > Plugin Constructed\n"; +} + +using namespace Fortran::frontend; + +class HelloWorldFlangPlugin : public PluginParseTreeAction +{ + void ExecuteAction() override { + llvm::outs() << "Hello World from your new plugin (Remote plugin)\n"; + } +}; + +static FrontendPluginRegistry::Add<HelloWorldFlangPlugin> X("-hello-w", "Hello World Plugin example"); diff --git a/flang/include/flang/Frontend/FrontendActions.h b/flang/include/flang/Frontend/FrontendActions.h index 72eb44223fe49..d30ae1dbed0ff 100644 --- a/flang/include/flang/Frontend/FrontendActions.h +++ b/flang/include/flang/Frontend/FrontendActions.h @@ -30,6 +30,10 @@ struct MeasurementVisitor { // Custom Consumer Actions //===----------------------------------------------------------------------===// +class PluginParseTreeAction : public FrontendAction { + void ExecuteAction() override; +}; + class InputOutputTestAction : public FrontendAction { void ExecuteAction() override; }; diff --git a/flang/include/flang/Frontend/FrontendOptions.h b/flang/include/flang/Frontend/FrontendOptions.h index 42ce499566e9f..5867b790f6fce 100644 --- a/flang/include/flang/Frontend/FrontendOptions.h +++ b/flang/include/flang/Frontend/FrontendOptions.h @@ -77,7 +77,10 @@ enum ActionKind { GetSymbolsSources, /// Only execute frontend initialization - InitOnly + InitOnly, + + /// Run a plugin action, \see ActionName. + PluginAction /// TODO: RunPreprocessor, EmitLLVM, EmitLLVMOnly, /// EmitCodeGenOnly, EmitAssembly, (...) @@ -249,6 +252,12 @@ class FrontendOptions { // Source file encoding Fortran::parser::Encoding encoding_{Fortran::parser::Encoding::UTF_8}; + /// The list of plugins to load. + std::vector<std::string> plugins; + + /// The name of the action to run when using a plugin action. + std::string ActionName; + public: FrontendOptions() : showHelp_(false), showVersion_(false), instrumentedParse_(false), diff --git a/flang/include/flang/Frontend/FrontendPluginRegistry.h b/flang/include/flang/Frontend/FrontendPluginRegistry.h new file mode 100644 index 0000000000000..d775393afe7f6 --- /dev/null +++ b/flang/include/flang/Frontend/FrontendPluginRegistry.h @@ -0,0 +1,26 @@ +//===- FrontendPluginRegistry.h ---------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Pluggable Frontend Action Interface +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_FLANG_FRONTEND_FRONTENDPLUGINREGISTRY_H +#define LLVM_FLANG_FRONTEND_FRONTENDPLUGINREGISTRY_H + +#include "flang/Frontend/FrontendAction.h" +#include "llvm/Support/Registry.h" + +namespace Fortran::frontend { + +/// The frontend plugin registry. +using FrontendPluginRegistry = llvm::Registry<PluginParseTreeAction>; + +} // namespace flang + +#endif // LLVM_FLANG_FRONTEND_FRONTENDPLUGINREGISTRY_H \ No newline at end of file diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp index 6a2bf1947e350..20d3d2d253a75 100644 --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -199,6 +199,23 @@ static bool ParseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args, } } + printf("--------- (ParseFrontendArgs) ----------\n"); + + if (llvm::opt::Arg *a = args.getLastArg(clang::driver::options::OPT_load)) { + llvm::outs() << " " << a->getOption().getName() << " >>> " << a->getValue() << "\n"; + //opts.plugins = a->getValue(); + opts.plugins.push_back(a->getValue()); + } + + if (const llvm::opt::Arg *a = args.getLastArg(clang::driver::options::OPT_plugin)) { + llvm::outs() << " " << a->getOption().getName() << " >>> " << a->getValue() << "\n"; + //opts.plugins.emplace_back(a->getValue()); + opts.programAction_ = PluginAction; + opts.ActionName = a->getValue(); + } + + printf("-------- (\\ParseFrontendArgs) ----------\n"); + opts.outputFile_ = args.getLastArgValue(clang::driver::options::OPT_o); opts.showHelp_ = args.hasArg(clang::driver::options::OPT_help); opts.showVersion_ = args.hasArg(clang::driver::options::OPT_version); diff --git a/flang/lib/Frontend/FrontendAction.cpp b/flang/lib/Frontend/FrontendAction.cpp index 23e4ca3f33063..62d4bac0df6fa 100644 --- a/flang/lib/Frontend/FrontendAction.cpp +++ b/flang/lib/Frontend/FrontendAction.cpp @@ -10,6 +10,7 @@ #include "flang/Frontend/CompilerInstance.h" #include "flang/Frontend/FrontendActions.h" #include "flang/Frontend/FrontendOptions.h" +#include "flang/Frontend/FrontendPluginRegistry.h" #include "flang/FrontendTool/Utils.h" #include "clang/Basic/DiagnosticFrontend.h" #include "llvm/Support/Errc.h" @@ -17,6 +18,9 @@ using namespace Fortran::frontend; +LLVM_INSTANTIATE_REGISTRY(FrontendPluginRegistry) + + void FrontendAction::set_currentInput(const FrontendInputFile ¤tInput) { this->currentInput_ = currentInput; } diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp index 8ee42d73c6e46..d067ebd141b85 100644 --- a/flang/lib/Frontend/FrontendActions.cpp +++ b/flang/lib/Frontend/FrontendActions.cpp @@ -488,3 +488,7 @@ void InitOnlyAction::ExecuteAction() { "Use `-init-only` for testing purposes only"); ci.diagnostics().Report(DiagID); } + +void PluginParseTreeAction::ExecuteAction() { + +} diff --git a/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index 243e25163dc05..8ef0c93404c10 100644 --- a/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -13,11 +13,14 @@ #include "flang/Frontend/CompilerInstance.h" #include "flang/Frontend/FrontendActions.h" +#include "flang/Frontend/FrontendAction.h" +#include "flang/Frontend/FrontendPluginRegistry.h" #include "clang/Driver/Options.h" #include "llvm/Option/OptTable.h" #include "llvm/Option/Option.h" #include "llvm/Support/BuryPointer.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/DynamicLibrary.h" namespace Fortran::frontend { @@ -79,6 +82,22 @@ static std::unique_ptr<FrontendAction> CreateFrontendBaseAction( case InitOnly: return std::make_unique<InitOnlyAction>(); break; + case PluginAction: { + llvm::outs() << "---------- (case: PluginAction) --------\n"; + llvm::outs() << " Plugin Action: " << ci.frontendOpts().ActionName << "\n"; + for (const FrontendPluginRegistry::entry &plugin : FrontendPluginRegistry::entries()) { + llvm::outs() << " " << plugin.getName() << "\t-- " << plugin.getDesc() << "\n"; + if (plugin.getName() == ci.frontendOpts().ActionName) { + llvm::outs() << "We have found the plugin name!! :-)\n"; + std::unique_ptr<PluginParseTreeAction> P(plugin.instantiate()); + return std::move(P); + } + } + + unsigned diagID = ci.diagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error, "unable to find plugin '%0'"); + ci.diagnostics().Report(diagID) << ci.frontendOpts().ActionName; + return nullptr; + } default: break; // TODO: @@ -92,6 +111,26 @@ static std::unique_ptr<FrontendAction> CreateFrontendBaseAction( return 0; } +/// <<< TEMP Plugin Example + +class HelloWorldFlangPlugin : public PluginParseTreeAction +{ + protected: + void ExecuteAction() override { + llvm::outs() << "Hello World from your new plugin (Hello World)\n"; + } +}; + +class HelloTwoFlangPlugin : public PluginParseTreeAction +{ + protected: + void ExecuteAction() override { + llvm::outs() << "Hello World from your new plugin (Hello Two)\n"; + } +}; + +/// <<<<< TEMP Plugin Example + std::unique_ptr<FrontendAction> CreateFrontendAction(CompilerInstance &ci) { // Create the underlying action. std::unique_ptr<FrontendAction> act = CreateFrontendBaseAction(ci); @@ -100,6 +139,7 @@ std::unique_ptr<FrontendAction> CreateFrontendAction(CompilerInstance &ci) { return act; } + bool ExecuteCompilerInvocation(CompilerInstance *flang) { // Honor -help. if (flang->frontendOpts().showHelp_) { @@ -117,6 +157,33 @@ bool ExecuteCompilerInvocation(CompilerInstance *flang) { return true; } + llvm::outs() << "------ (ExecuteCompilerInvocation) -----\n"; + + // Load any requested plugins. + for (const std::string &Path : flang->frontendOpts().plugins) { + llvm::outs() << " Load :: Path >> " << Path << "\n"; + std::string Error; + if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(Path.c_str(), &Error)) { + unsigned diagID = flang->diagnostics().getCustomDiagID(clang::DiagnosticsEngine::Error, "unable to load plugin '%0': '%1'"); + flang->diagnostics().Report(diagID) << Path << Error; + } + } + + llvm::outs() << " Plugin Registry List >>\n"; + for (const FrontendPluginRegistry::entry &plugin : FrontendPluginRegistry::entries()) { + llvm::outs() << plugin.getName() << " -- " << plugin.getDesc() << "\n"; + } + llvm::outs() << " << Plugin Registry List\n"; + + static FrontendPluginRegistry::Add<HelloWorldFlangPlugin> X("-hello-wor", "simple Plugin example"); + static FrontendPluginRegistry::Add<HelloTwoFlangPlugin> Y("hellotwo", "another print plugin example"); + + llvm::outs() << "----- (\\ExecuteCompilerInvocation) -----\n"; + + // If there were errors in processing arguments, don't do anything else. + if (flang->diagnostics().hasErrorOccurred()) + return false; + // Create and execute the frontend action. std::unique_ptr<FrontendAction> act(CreateFrontendAction(*flang)); if (!act) diff --git a/llvm/include/llvm/Support/Registry.h b/llvm/include/llvm/Support/Registry.h index 5bb6a254a47f4..58b1825a71c06 100644 --- a/llvm/include/llvm/Support/Registry.h +++ b/llvm/include/llvm/Support/Registry.h @@ -18,6 +18,7 @@ #include "llvm/ADT/iterator_range.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/CommandLine.h" #include <memory> namespace llvm { @@ -120,7 +121,10 @@ namespace llvm { public: Add(StringRef Name, StringRef Desc) : Entry(Name, Desc, CtorFn), Node(Entry) { + llvm::outs() << " -------------- (Registry) --------------\n"; + llvm::outs() << " \tAdd :: " << Name << "\n"; add_node(&Node); + llvm::outs() << " ------------- (\\Registry) --------------\n"; } }; }; @@ -145,8 +149,14 @@ namespace llvm { else \ Head = N; \ Tail = N; \ + llvm::outs() << " REGISTRY_CLASS :: list >> \n"; \ + for (const REGISTRY_CLASS::entry &plugin : REGISTRY_CLASS::entries()) { \ + llvm::outs() << " " << plugin.getName() << " \t-- " << plugin.getDesc() << "\n"; \ + } \ } \ template<typename T> typename Registry<T>::iterator Registry<T>::begin() { \ + llvm::outs() << "iterator (head)\n"; \ + llvm::outs() << Head << "\n"; \ return iterator(Head); \ } \ template REGISTRY_CLASS::node *Registry<REGISTRY_CLASS::type>::Head; \ diff --git a/llvm/lib/Support/DynamicLibrary.cpp b/llvm/lib/Support/DynamicLibrary.cpp index 2bcdbdcdb9b0d..ff989da453652 100644 --- a/llvm/lib/Support/DynamicLibrary.cpp +++ b/llvm/lib/Support/DynamicLibrary.cpp @@ -149,12 +149,18 @@ DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *FileName, // ManagedStatic can be added from static constructors in HandleSet::DLOpen. HandleSet& HS = *OpenedHandles; + printf(" -------- (getPermantentLibrary) --------\n"); + printf(" get Lib: %s \n", FileName); + void *Handle = HandleSet::DLOpen(FileName, Err); if (Handle != &Invalid) { + printf(" Handle != Invalid \n"); SmartScopedLock<true> Lock(*SymbolsMutex); HS.AddLibrary(Handle, /*IsProcess*/ FileName == nullptr); } + printf(" ------- (\\getPermantentLibrary) --------\n"); + return DynamicLibrary(Handle); } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits