mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 12:41:49 +01:00
Re-land r329273: [Plugins] Add a slim plugin API to work together with the new PM
Fix unittest: Do not link LLVM into the test plugin. Additionally, remove an unrelated change that slipped in in r329273. llvm-svn: 329293
This commit is contained in:
parent
fa2992679a
commit
3d76c2d6f6
@ -503,4 +503,22 @@ void AnnotateIgnoreWritesEnd(const char *file, int line);
|
||||
#define LLVM_ENABLE_EXCEPTIONS 1
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_PLUGIN_IMPORT
|
||||
/// \brief Used to import the well-known entry point for registering loaded pass
|
||||
/// plugins
|
||||
#ifdef WIN32
|
||||
#define LLVM_PLUGIN_IMPORT __declspec(dllimport)
|
||||
#else
|
||||
#define LLVM_PLUGIN_IMPORT
|
||||
#endif
|
||||
|
||||
/// \macro LLVM_PLUGIN_EXPORT
|
||||
/// \brief Used to export the well-known entry point for registering loaded pass
|
||||
/// plugins
|
||||
#ifdef WIN32
|
||||
#define LLVM_PLUGIN_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define LLVM_PLUGIN_EXPORT
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
114
include/llvm/Passes/PassPlugin.h
Normal file
114
include/llvm/Passes/PassPlugin.h
Normal file
@ -0,0 +1,114 @@
|
||||
//===- llvm/Passes/PassPlugin.h - Public Plugin API -----------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This defines the public entry point for new-PM pass plugins.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_PASSES_PASSPLUGIN_H
|
||||
#define LLVM_PASSES_PASSPLUGIN_H
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/DynamicLibrary.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
class PassBuilder;
|
||||
|
||||
/// \macro LLVM_PLUGIN_API_VERSION
|
||||
/// Identifies the API version understood by this plugin.
|
||||
///
|
||||
/// When a plugin is loaded, the driver will check it's supported plugin version
|
||||
/// against that of the plugin. A mismatch is an error. The supported version
|
||||
/// will be incremented for ABI-breaking changes to the \c PassPluginLibraryInfo
|
||||
/// struct, i.e. when callbacks are added, removed, or reordered.
|
||||
#define LLVM_PLUGIN_API_VERSION 1
|
||||
|
||||
extern "C" {
|
||||
/// Information about the plugin required to load its passes
|
||||
///
|
||||
/// This struct defines the core interface for pass plugins and is supposed to
|
||||
/// be filled out by plugin implementors. LLVM-side users of a plugin are
|
||||
/// expected to use the \c PassPlugin class below to interface with it.
|
||||
struct PassPluginLibraryInfo {
|
||||
/// The API version understood by this plugin, usually \c
|
||||
/// LLVM_PLUGIN_API_VERSION
|
||||
uint32_t APIVersion;
|
||||
/// A meaningful name of the plugin.
|
||||
const char *PluginName;
|
||||
/// The version of the plugin.
|
||||
const char *PluginVersion;
|
||||
|
||||
/// The callback for registering plugin passes with a \c PassBuilder
|
||||
/// instance
|
||||
void (*RegisterPassBuilderCallbacks)(PassBuilder &);
|
||||
};
|
||||
}
|
||||
|
||||
/// A loaded pass plugin.
|
||||
///
|
||||
/// An instance of this class wraps a loaded pass plugin and gives access to
|
||||
/// its interface defined by the \c PassPluginLibraryInfo it exposes.
|
||||
class PassPlugin {
|
||||
public:
|
||||
/// Attempts to load a pass plugin from a given file.
|
||||
///
|
||||
/// \returns Returns an error if either the library cannot be found or loaded,
|
||||
/// there is no public entry point, or the plugin implements the wrong API
|
||||
/// version.
|
||||
static Expected<PassPlugin> Load(const std::string &Filename);
|
||||
|
||||
/// Get the filename of the loaded plugin.
|
||||
StringRef getFilename() const { return Filename; }
|
||||
|
||||
/// Get the plugin name
|
||||
StringRef getPluginName() const { return Info.PluginName; }
|
||||
|
||||
/// Get the plugin version
|
||||
StringRef getPluginVersion() const { return Info.PluginVersion; }
|
||||
|
||||
/// Get the plugin API version
|
||||
uint32_t getAPIVersion() const { return Info.APIVersion; }
|
||||
|
||||
/// Invoke the PassBuilder callback registration
|
||||
void registerPassBuilderCallbacks(PassBuilder &PB) const {
|
||||
Info.RegisterPassBuilderCallbacks(PB);
|
||||
}
|
||||
|
||||
private:
|
||||
PassPlugin(const std::string &Filename, const sys::DynamicLibrary &Library)
|
||||
: Filename(Filename), Library(Library), Info() {}
|
||||
|
||||
std::string Filename;
|
||||
sys::DynamicLibrary Library;
|
||||
PassPluginLibraryInfo Info;
|
||||
};
|
||||
}
|
||||
|
||||
/// The public entry point for a pass plugin.
|
||||
///
|
||||
/// When a plugin is loaded by the driver, it will call this entry point to
|
||||
/// obtain information about this plugin and about how to register its passes.
|
||||
/// This function needs to be implemented by the plugin, see the example below:
|
||||
///
|
||||
/// ```
|
||||
/// extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
|
||||
/// LLVM_PLUGIN_EXPORT llvmGetPassPluginInfo() {
|
||||
/// return {
|
||||
/// LLVM_PLUGIN_API_VERSION, "MyPlugin", "v0.1", [](PassBuilder &PB) { ... }
|
||||
/// };
|
||||
/// }
|
||||
/// ```
|
||||
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK LLVM_PLUGIN_IMPORT
|
||||
llvmGetPassPluginInfo();
|
||||
|
||||
#endif /* LLVM_PASSES_PASSPLUGIN_H */
|
@ -1,5 +1,6 @@
|
||||
add_llvm_library(LLVMPasses
|
||||
PassBuilder.cpp
|
||||
PassPlugin.cpp
|
||||
|
||||
ADDITIONAL_HEADER_DIRS
|
||||
${LLVM_MAIN_INCLUDE_DIR}/llvm/Passes
|
||||
|
50
lib/Passes/PassPlugin.cpp
Normal file
50
lib/Passes/PassPlugin.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
//===- lib/Passes/PassPluginLoader.cpp - Load Plugins for New PM Passes ---===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Passes/PassPlugin.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
Expected<PassPlugin> PassPlugin::Load(const std::string &Filename) {
|
||||
std::string Error;
|
||||
auto Library =
|
||||
sys::DynamicLibrary::getPermanentLibrary(Filename.c_str(), &Error);
|
||||
if (!Library.isValid())
|
||||
return make_error<StringError>(Twine("Could not load library '") +
|
||||
Filename + "': " + Error,
|
||||
inconvertibleErrorCode());
|
||||
|
||||
PassPlugin P{Filename, Library};
|
||||
auto *getDetailsFn =
|
||||
Library.SearchForAddressOfSymbol("llvmGetPassPluginInfo");
|
||||
|
||||
if (!getDetailsFn)
|
||||
// If the symbol isn't found, this is probably a legacy plugin, which is an
|
||||
// error
|
||||
return make_error<StringError>(Twine("Plugin entry point not found in '") +
|
||||
Filename + "'. Is this a legacy plugin?",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
P.Info = reinterpret_cast<decltype(llvmGetPassPluginInfo) *>(getDetailsFn)();
|
||||
|
||||
if (P.Info.APIVersion != LLVM_PLUGIN_API_VERSION)
|
||||
return make_error<StringError>(
|
||||
Twine("Wrong API version on plugin '") + Filename + "'. Got version " +
|
||||
Twine(P.Info.APIVersion) + ", supported version is " +
|
||||
Twine(LLVM_PLUGIN_API_VERSION) + ".",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
if (!P.Info.RegisterPassBuilderCallbacks)
|
||||
return make_error<StringError>(Twine("Empty entry callback in plugin '") +
|
||||
Filename + "'.'",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
return P;
|
||||
}
|
@ -27,6 +27,7 @@
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/Passes/PassPlugin.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/ToolOutputFile.h"
|
||||
@ -41,6 +42,10 @@ static cl::opt<bool>
|
||||
DebugPM("debug-pass-manager", cl::Hidden,
|
||||
cl::desc("Print pass management debugging information"));
|
||||
|
||||
static cl::list<std::string>
|
||||
PassPlugins("load-pass-plugin",
|
||||
cl::desc("Load passes from plugin library"));
|
||||
|
||||
// This flag specifies a textual description of the alias analysis pipeline to
|
||||
// use when querying for aliasing information. It only works in concert with
|
||||
// the "passes" flag above.
|
||||
@ -210,6 +215,18 @@ bool llvm::runPassPipeline(StringRef Arg0, Module &M, TargetMachine *TM,
|
||||
PassBuilder PB(TM, P);
|
||||
registerEPCallbacks(PB, VerifyEachPass, DebugPM);
|
||||
|
||||
// Load requested pass plugins and let them register pass builder callbacks
|
||||
for (auto &PluginFN : PassPlugins) {
|
||||
auto PassPlugin = PassPlugin::Load(PluginFN);
|
||||
if (!PassPlugin) {
|
||||
errs() << "Failed to load passes from '" << PluginFN
|
||||
<< "'. Request ignored.\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
PassPlugin->registerPassBuilderCallbacks(PB);
|
||||
}
|
||||
|
||||
// Register a callback that creates the debugify passes as needed.
|
||||
PB.registerPipelineParsingCallback(
|
||||
[](StringRef Name, ModulePassManager &MPM,
|
||||
|
@ -22,6 +22,7 @@ add_subdirectory(Object)
|
||||
add_subdirectory(BinaryFormat)
|
||||
add_subdirectory(ObjectYAML)
|
||||
add_subdirectory(Option)
|
||||
add_subdirectory(Passes)
|
||||
add_subdirectory(ProfileData)
|
||||
add_subdirectory(Support)
|
||||
add_subdirectory(Target)
|
||||
|
18
unittests/Passes/CMakeLists.txt
Normal file
18
unittests/Passes/CMakeLists.txt
Normal file
@ -0,0 +1,18 @@
|
||||
set(LLVM_LINK_COMPONENTS Support Passes Core)
|
||||
|
||||
add_llvm_unittest(PluginsTests PluginsTest.cpp)
|
||||
export_executable_symbols(PluginsTests)
|
||||
|
||||
add_library(TestPlugin MODULE TestPlugin.cxx)
|
||||
|
||||
set_output_directory(TestPlugin
|
||||
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
|
||||
LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
|
||||
)
|
||||
|
||||
set_target_properties(TestPlugin
|
||||
PROPERTIES PREFIX ""
|
||||
SUFFIX ".so"
|
||||
)
|
||||
|
||||
add_dependencies(PluginsTests TestPlugin)
|
53
unittests/Passes/PluginsTest.cpp
Normal file
53
unittests/Passes/PluginsTest.cpp
Normal file
@ -0,0 +1,53 @@
|
||||
//===- unittests/Passes/Plugins/PluginsTest.cpp ---------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Analysis/CGSCCPassManager.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/Passes/PassPlugin.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Transforms/Scalar/LoopPassManager.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "TestPlugin.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
void anchor() {}
|
||||
|
||||
static std::string LibPath(const std::string Name = "TestPlugin") {
|
||||
const std::vector<testing::internal::string> &Argvs =
|
||||
testing::internal::GetArgvs();
|
||||
const char *Argv0 = Argvs.size() > 0 ? Argvs[0].c_str() : "PluginsTests";
|
||||
void *Ptr = (void *)anchor;
|
||||
std::string Path = sys::fs::getMainExecutable(Argv0, Ptr);
|
||||
llvm::SmallString<256> Buf{sys::path::parent_path(Path)};
|
||||
sys::path::append(Buf, (Name + ".so").c_str());
|
||||
return Buf.str();
|
||||
}
|
||||
|
||||
TEST(PluginsTests, LoadPlugin) {
|
||||
auto PluginPath = LibPath();
|
||||
ASSERT_NE("", PluginPath);
|
||||
|
||||
Expected<PassPlugin> Plugin = PassPlugin::Load(PluginPath);
|
||||
ASSERT_TRUE(!!Plugin) << "Plugin path: " << PluginPath;
|
||||
|
||||
ASSERT_EQ(TEST_PLUGIN_NAME, Plugin->getPluginName());
|
||||
ASSERT_EQ(TEST_PLUGIN_VERSION, Plugin->getPluginVersion());
|
||||
|
||||
PassBuilder PB;
|
||||
ModulePassManager PM;
|
||||
ASSERT_FALSE(PB.parsePassPipeline(PM, "plugin-pass"));
|
||||
|
||||
Plugin->registerPassBuilderCallbacks(PB);
|
||||
ASSERT_TRUE(PB.parsePassPipeline(PM, "plugin-pass"));
|
||||
}
|
39
unittests/Passes/TestPlugin.cxx
Normal file
39
unittests/Passes/TestPlugin.cxx
Normal file
@ -0,0 +1,39 @@
|
||||
//===- unittests/Passes/Plugins/Plugin.cxx --------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Passes/PassBuilder.h"
|
||||
#include "llvm/Passes/PassPlugin.h"
|
||||
|
||||
#include "TestPlugin.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
struct TestModulePass : public PassInfoMixin<TestModulePass> {
|
||||
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM) {
|
||||
return PreservedAnalyses::all();
|
||||
}
|
||||
};
|
||||
|
||||
void registerCallbacks(PassBuilder &PB) {
|
||||
PB.registerPipelineParsingCallback(
|
||||
[](StringRef Name, ModulePassManager &PM,
|
||||
ArrayRef<PassBuilder::PipelineElement> InnerPipeline) {
|
||||
if (Name == "plugin-pass") {
|
||||
PM.addPass(TestModulePass());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK LLVM_PLUGIN_EXPORT
|
||||
llvmGetPassPluginInfo() {
|
||||
return {LLVM_PLUGIN_API_VERSION, TEST_PLUGIN_NAME, TEST_PLUGIN_VERSION,
|
||||
registerCallbacks};
|
||||
}
|
2
unittests/Passes/TestPlugin.h
Normal file
2
unittests/Passes/TestPlugin.h
Normal file
@ -0,0 +1,2 @@
|
||||
#define TEST_PLUGIN_NAME "TestPlugin"
|
||||
#define TEST_PLUGIN_VERSION "0.1-unit"
|
Loading…
x
Reference in New Issue
Block a user