1 //===- unittests/Passes/Plugins/PluginsTest.cpp ---------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/Analysis/CGSCCPassManager.h" 10 #include "llvm/AsmParser/Parser.h" 11 #include "llvm/Config/config.h" 12 #include "llvm/IR/GlobalVariable.h" 13 #include "llvm/IR/PassManager.h" 14 #include "llvm/Passes/PassBuilder.h" 15 #include "llvm/Passes/PassPlugin.h" 16 #include "llvm/Support/FileSystem.h" 17 #include "llvm/Support/Path.h" 18 #include "llvm/Support/SourceMgr.h" 19 #include "llvm/Testing/Support/Error.h" 20 #include "llvm/Transforms/Scalar/LoopPassManager.h" 21 #include "gtest/gtest.h" 22 23 #include "TestPlugin.h" 24 25 #include <cstdint> 26 27 using namespace llvm; 28 29 void anchor() {} 30 31 static std::string LibPath(const std::string Name = "TestPlugin") { 32 const auto &Argvs = testing::internal::GetArgvs(); 33 const char *Argv0 = Argvs.size() > 0 ? Argvs[0].c_str() : "PluginsTests"; 34 void *Ptr = (void *)(intptr_t)anchor; 35 std::string Path = sys::fs::getMainExecutable(Argv0, Ptr); 36 llvm::SmallString<256> Buf{sys::path::parent_path(Path)}; 37 sys::path::append(Buf, (Name + LLVM_PLUGIN_EXT).c_str()); 38 return std::string(Buf.str()); 39 } 40 41 TEST(PluginsTests, LoadPlugin) { 42 #if !defined(LLVM_ENABLE_PLUGINS) 43 // Disable the test if plugins are disabled. 44 return; 45 #endif 46 47 auto PluginPath = LibPath(); 48 ASSERT_NE("", PluginPath); 49 50 Expected<PassPlugin> Plugin = PassPlugin::Load(PluginPath); 51 ASSERT_TRUE(!!Plugin) << "Plugin path: " << PluginPath; 52 53 ASSERT_EQ(TEST_PLUGIN_NAME, Plugin->getPluginName()); 54 ASSERT_EQ(TEST_PLUGIN_VERSION, Plugin->getPluginVersion()); 55 56 PassBuilder PB; 57 ModulePassManager PM; 58 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, "plugin-pass"), Failed()); 59 60 Plugin->registerPassBuilderCallbacks(PB); 61 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, "plugin-pass"), Succeeded()); 62 } 63 64 // Test that llvmGetPassPluginInfo from DoublerPlugin is called twice with 65 // -fpass-plugin=DoublerPlugin -fpass-plugin=TestPlugin 66 // -fpass-plugin=DoublerPlugin. 67 TEST(PluginsTests, LoadMultiplePlugins) { 68 #if !defined(LLVM_ENABLE_PLUGINS) 69 // Disable the test if plugins are disabled. 70 return; 71 #endif 72 73 auto DoublerPluginPath = LibPath("DoublerPlugin"); 74 auto TestPluginPath = LibPath("TestPlugin"); 75 ASSERT_NE("", DoublerPluginPath); 76 ASSERT_NE("", TestPluginPath); 77 78 Expected<PassPlugin> DoublerPlugin1 = PassPlugin::Load(DoublerPluginPath); 79 ASSERT_TRUE(!!DoublerPlugin1) 80 << "Plugin path: " << DoublerPlugin1->getFilename(); 81 82 Expected<PassPlugin> TestPlugin = PassPlugin::Load(TestPluginPath); 83 ASSERT_TRUE(!!TestPlugin) << "Plugin path: " << TestPlugin->getFilename(); 84 85 // If llvmGetPassPluginInfo is resolved as a weak symbol taking into account 86 // all loaded symbols, the second call to PassPlugin::Load will actually 87 // return the llvmGetPassPluginInfo from the most recently loaded plugin, in 88 // this case TestPlugin. 89 Expected<PassPlugin> DoublerPlugin2 = PassPlugin::Load(DoublerPluginPath); 90 ASSERT_TRUE(!!DoublerPlugin2) 91 << "Plugin path: " << DoublerPlugin2->getFilename(); 92 93 ASSERT_EQ("DoublerPlugin", DoublerPlugin1->getPluginName()); 94 ASSERT_EQ("2.2-unit", DoublerPlugin1->getPluginVersion()); 95 ASSERT_EQ(TEST_PLUGIN_NAME, TestPlugin->getPluginName()); 96 ASSERT_EQ(TEST_PLUGIN_VERSION, TestPlugin->getPluginVersion()); 97 // Check that the plugin name/version is set correctly when loaded a second 98 // time 99 ASSERT_EQ("DoublerPlugin", DoublerPlugin2->getPluginName()); 100 ASSERT_EQ("2.2-unit", DoublerPlugin2->getPluginVersion()); 101 102 PassBuilder PB; 103 ModulePassManager PM; 104 const char *PipelineText = "module(doubler-pass,plugin-pass,doubler-pass)"; 105 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Failed()); 106 TestPlugin->registerPassBuilderCallbacks(PB); 107 DoublerPlugin1->registerPassBuilderCallbacks(PB); 108 DoublerPlugin2->registerPassBuilderCallbacks(PB); 109 ASSERT_THAT_ERROR(PB.parsePassPipeline(PM, PipelineText), Succeeded()); 110 111 LLVMContext C; 112 SMDiagnostic Err; 113 std::unique_ptr<Module> M = 114 parseAssemblyString(R"IR(@doubleme = constant i32 7)IR", Err, C); 115 116 // Check that the initial value is 7 117 { 118 auto *GV = M->getNamedValue("doubleme"); 119 auto *Init = cast<GlobalVariable>(GV)->getInitializer(); 120 auto *CI = cast<ConstantInt>(Init); 121 ASSERT_EQ(CI->getSExtValue(), 7); 122 } 123 124 ModuleAnalysisManager MAM; 125 // Register required pass instrumentation analysis. 126 MAM.registerPass([&] { return PassInstrumentationAnalysis(); }); 127 PM.run(*M, MAM); 128 129 // Check that the final value is 28 because DoublerPlugin::run was called 130 // twice, indicating that the llvmGetPassPluginInfo and registerCallbacks 131 // were correctly called. 132 { 133 // Check the value was doubled twice 134 auto *GV = M->getNamedValue("doubleme"); 135 auto *Init = cast<GlobalVariable>(GV)->getInitializer(); 136 auto *CI = cast<ConstantInt>(Init); 137 ASSERT_EQ(CI->getSExtValue(), 28); 138 } 139 } 140