llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lld

Author: Stefan Gränitz (weliveindetail)

<details>
<summary>Changes</summary>

Let's discuss implementation details here and concepts on Discourse: 
https://discourse.llvm.org/t/rfc-a-reference-pass-plugin-in-llvm/89073

---

Patch is 39.51 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/171111.diff


23 Files Affected:

- (added) clang/test/Misc/Inputs/pypass-plugin.c (+2) 
- (added) clang/test/Misc/lit.local.cfg (+21) 
- (added) clang/test/Misc/pypass-plugin-entrypoints.py (+127) 
- (added) clang/test/Misc/pypass-plugin-params.py (+30) 
- (added) clang/test/Misc/pypass-plugin-repl.py (+17) 
- (modified) clang/test/lit.cfg.py (+3) 
- (modified) lld/test/CMakeLists.txt (+1) 
- (added) lld/test/ELF/lto/Inputs/pypass-plugin.ll (+7) 
- (added) lld/test/ELF/lto/lit.local.cfg (+23) 
- (added) lld/test/ELF/lto/pypass-plugin-entrypoints.py (+100) 
- (added) lld/test/ELF/lto/pypass-plugin-pipeline-parsing.py (+18) 
- (modified) lld/test/lit.cfg.py (+3) 
- (modified) lld/test/lit.site.cfg.py.in (+1) 
- (modified) llvm/CMakeLists.txt (+4) 
- (modified) llvm/cmake/modules/AddLLVM.cmake (+14-8) 
- (modified) llvm/docs/CMake.rst (+5) 
- (added) llvm/test/tools/plugins-shlib/Inputs/foobar.ll (+2) 
- (added) llvm/test/tools/plugins-shlib/Inputs/mymod.py (+5) 
- (added) llvm/test/tools/plugins-shlib/lit.local.cfg (+21) 
- (added) llvm/test/tools/plugins-shlib/pypass-functions.py (+23) 
- (added) llvm/test/tools/plugins-shlib/pypass.py (+37) 
- (added) llvm/tools/plugins-shlib/CMakeLists.txt (+16) 
- (added) llvm/tools/plugins-shlib/pypass.cpp (+464) 


``````````diff
diff --git a/clang/test/Misc/Inputs/pypass-plugin.c 
b/clang/test/Misc/Inputs/pypass-plugin.c
new file mode 100644
index 0000000000000..90c45543bf62c
--- /dev/null
+++ b/clang/test/Misc/Inputs/pypass-plugin.c
@@ -0,0 +1,2 @@
+void f() {}
+void g() {}
diff --git a/clang/test/Misc/lit.local.cfg b/clang/test/Misc/lit.local.cfg
new file mode 100644
index 0000000000000..9f56f18a5a44a
--- /dev/null
+++ b/clang/test/Misc/lit.local.cfg
@@ -0,0 +1,21 @@
+import os
+import platform
+import sysconfig
+
+# Run end-to-end tests if the reference pass-plugin exists in LLVM
+pypass_plugin = f"pypass-plugin{config.llvm_plugin_ext}"
+pypass_plugin_shlib = os.path.join(config.llvm_libs_dir, pypass_plugin)
+if os.path.exists(pypass_plugin_shlib):
+    config.available_features.add("pypass-plugin")
+
+# Disable ASAN's leak detection for Python tests
+config.environment["ASAN_OPTIONS"] = "detect_leaks=0"
+
+if platform.system() != "Windows":
+    libdir = sysconfig.get_config_var("LIBDIR")
+    dylib = sysconfig.get_config_var("LDLIBRARY")
+    config.substitutions.append(("%libpython", os.path.join(libdir, dylib)))
+
+# FIXME: %llvmshlibdir is broken in standalone builds
+config.substitutions.append(("%plugindir", config.llvm_libs_dir))
+config.suffixes.add(".py")
diff --git a/clang/test/Misc/pypass-plugin-entrypoints.py 
b/clang/test/Misc/pypass-plugin-entrypoints.py
new file mode 100644
index 0000000000000..88d5ad86eb027
--- /dev/null
+++ b/clang/test/Misc/pypass-plugin-entrypoints.py
@@ -0,0 +1,127 @@
+# REQUIRES: native, system-linux, plugins, pypass-plugin
+
+# Entry-points in default and -O0 pipeline
+#
+# RUN: env LLVM_PYPASS_SCRIPT=%s \
+# RUN: env LLVM_PYPASS_DYLIB=%libpython \
+# RUN:   %clang -fpass-plugin=%plugindir/pypass-plugin%pluginext \
+# RUN:          -o /dev/null -S -emit-llvm %S/Inputs/pypass-plugin.c | 
FileCheck --check-prefix=EP %s
+#
+# RUN: env LLVM_PYPASS_SCRIPT=%s \
+# RUN: env LLVM_PYPASS_DYLIB=%libpython \
+# RUN:   %clang -fpass-plugin=%plugindir/pypass-plugin%pluginext -flto=full 
-O0 \
+# RUN:          -o /dev/null -S -emit-llvm %S/Inputs/pypass-plugin.c | 
FileCheck --check-prefix=EP %s
+#
+# RUN: env LLVM_PYPASS_SCRIPT=%s \
+# RUN: env LLVM_PYPASS_DYLIB=%libpython \
+# RUN:   %clang -fpass-plugin=%plugindir/pypass-plugin%pluginext -flto=thin 
-O0 \
+# RUN:          -o /dev/null -S -emit-llvm %S/Inputs/pypass-plugin.c | 
FileCheck --check-prefix=EP %s
+#
+# EP-NOT: PeepholeEPCallback
+# EP-NOT: Optimizer{{.*}}EPCallback
+# EP-NOT: ScalarOptimizer{{.*}}EPCallback
+# EP-NOT: FullLinkTimeOptimization{{.*}}EPCallback
+#
+# EP: PipelineStartEPCallback
+# EP: PipelineEarlySimplificationEPCallback
+# EP: OptimizerEarlyEPCallback
+# EP: OptimizerLastEPCallback
+
+# Entry-points in optimizer pipeline
+#
+# RUN: env LLVM_PYPASS_SCRIPT=%s \
+# RUN: env LLVM_PYPASS_DYLIB=%libpython \
+# RUN:   %clang -fpass-plugin=%plugindir/pypass-plugin%pluginext -O2 \
+# RUN:          -o /dev/null -S -emit-llvm %S/Inputs/pypass-plugin.c | 
FileCheck --check-prefix=EP-OPT %s
+#
+# RUN: env LLVM_PYPASS_SCRIPT=%s \
+# RUN: env LLVM_PYPASS_DYLIB=%libpython \
+# RUN:   %clang -fpass-plugin=%plugindir/pypass-plugin%pluginext -O2 
-flto=full \
+# RUN:          -o /dev/null -S -emit-llvm %S/Inputs/pypass-plugin.c | 
FileCheck --check-prefix=EP-OPT %s
+#
+# RUN: env LLVM_PYPASS_SCRIPT=%s \
+# RUN: env LLVM_PYPASS_DYLIB=%libpython \
+# RUN:   %clang -fpass-plugin=%plugindir/pypass-plugin%pluginext -O2 
-ffat-lto-objects \
+# RUN:          -o /dev/null -S -emit-llvm %S/Inputs/pypass-plugin.c | 
FileCheck --check-prefix=EP-OPT %s
+#
+# EP-OPT:     PipelineStartEPCallback
+# EP-OPT:     PipelineEarlySimplificationEPCallback
+# EP-OPT:     PeepholeEPCallback
+# EP-OPT:     ScalarOptimizerLateEPCallback
+# EP-OPT:     PeepholeEPCallback
+# EP-OPT:     OptimizerEarlyEPCallback
+# EP-OPT:     VectorizerStartEPCallback
+# EP-OPT:     VectorizerEndEPCallback
+# EP-OPT:     OptimizerLastEPCallback
+
+# FIXME: Thin-LTO does not invoke vectorizer callbacks
+#
+# RUN: env LLVM_PYPASS_SCRIPT=%s \
+# RUN: env LLVM_PYPASS_DYLIB=%libpython \
+# RUN:   %clang -fpass-plugin=%plugindir/pypass-plugin%pluginext -O2 
-flto=thin \
+# RUN:          -o /dev/null -S -emit-llvm %S/Inputs/pypass-plugin.c | 
FileCheck --check-prefix=EP-LTO-THIN %s
+#
+# EP-LTO-THIN:     PipelineStartEPCallback
+# EP-LTO-THIN:     PipelineEarlySimplificationEPCallback
+# EP-LTO-THIN:     PeepholeEPCallback
+# EP-LTO-THIN:     ScalarOptimizerLateEPCallback
+# EP-LTO-THIN:     OptimizerEarlyEPCallback
+# EP-LTO-THIN-NOT: Vectorizer{{.*}}EPCallback
+# EP-LTO-THIN:     OptimizerLastEPCallback
+
+
+def registerPipelineStartEPCallback():
+    """Module pass at the start of the pipeline"""
+    return True
+
+
+def registerPipelineEarlySimplificationEPCallback():
+    """Module pass after basic simplification of input IR"""
+    return True
+
+
+def registerOptimizerEarlyEPCallback():
+    """Module pass before the function optimization pipeline"""
+    return True
+
+
+def registerOptimizerLastEPCallback():
+    """Module pass after the function optimization pipeline"""
+    return True
+
+
+def registerPeepholeEPCallback():
+    """Function pass after each instance of the instruction combiner pass"""
+    return True
+
+
+def registerScalarOptimizerLateEPCallback():
+    """Function pass after most of the main optimizations, but before the last
+    cleanup-ish optimizations"""
+    return True
+
+
+def registerVectorizerStartEPCallback():
+    """Function pass before the vectorizer and other highly target specific
+    optimization passes are executed"""
+    return True
+
+
+def registerVectorizerEndEPCallback():
+    """Function pass after the vectorizer and other highly target specific
+    optimization passes are executed"""
+    return True
+
+
+def registerFullLinkTimeOptimizationEarlyEPCallback():
+    """Module pass at the start of the full LTO pipeline"""
+    return True
+
+
+def registerFullLinkTimeOptimizationLastEPCallback():
+    """Module pass at the end of the full LTO pipeline"""
+    return True
+
+
+def run(input, ctx, stage):
+    print(f"0x{input:016x} {stage}")
diff --git a/clang/test/Misc/pypass-plugin-params.py 
b/clang/test/Misc/pypass-plugin-params.py
new file mode 100644
index 0000000000000..a2c43ddb22040
--- /dev/null
+++ b/clang/test/Misc/pypass-plugin-params.py
@@ -0,0 +1,30 @@
+# REQUIRES: native, system-linux, llvm-dylib, plugins, pypass-plugin
+
+# XFAIL: *
+#
+# RUN: %clang -fpass-plugin=%plugindir/pypass-plugin%pluginext -S -emit-llvm \
+# RUN:        -mllvm -pypass-script=%s \
+# RUN:        -mllvm -pypass-dylib=%libpython \
+# RUN:        -Xclang -fdebug-pass-manager \
+# RUN:        -o /dev/null -S -emit-llvm %S/Inputs/pypass-plugin.c 2>&1 | 
FileCheck %s
+#
+# CHECK: Unknown command line argument
+
+# Plugin parameters only work with the extra `-Xclang -load -Xclang <path>`
+# RUN: %clang -fpass-plugin=%plugindir/pypass-plugin%pluginext -S -emit-llvm \
+# RUN:        -Xclang -load -Xclang %plugindir/pypass-plugin%pluginext \
+# RUN:        -mllvm -pypass-script=%s \
+# RUN:        -mllvm -pypass-dylib=%libpython \
+# RUN:        -Xclang -fdebug-pass-manager \
+# RUN:        -o /dev/null -S -emit-llvm %S/Inputs/pypass-plugin.c 2>&1 | 
FileCheck %s
+#
+# CHECK: Running pass: PyPass
+
+
+def registerPipelineEarlySimplificationEPCallback():
+    """Module pass after basic simplification of input IR"""
+    return True
+
+
+def run(input, ctx, stage):
+    print(f"0x{input:016x} {stage}")
diff --git a/clang/test/Misc/pypass-plugin-repl.py 
b/clang/test/Misc/pypass-plugin-repl.py
new file mode 100644
index 0000000000000..741cb81dead71
--- /dev/null
+++ b/clang/test/Misc/pypass-plugin-repl.py
@@ -0,0 +1,17 @@
+# REQUIRES: native, system-linux, llvm-dylib, plugins, pypass-plugin
+
+# RUN: echo "int a = 1;" | \
+# RUN:   env LLVM_PYPASS_SCRIPT=%s \
+# RUN:   env LLVM_PYPASS_DYLIB=%libpython \
+# RUN:     clang-repl -Xcc -fpass-plugin=%plugindir/pypass-plugin%pluginext | 
FileCheck %s
+#
+# CHECK: PipelineEarlySimplificationEPCallback
+
+
+def registerPipelineEarlySimplificationEPCallback():
+    """Module pass after basic simplification of input IR"""
+    return True
+
+
+def run(input, ctx, stage):
+    print(f"0x{input:016x} {stage}")
diff --git a/clang/test/lit.cfg.py b/clang/test/lit.cfg.py
index 52b275c095475..c3d070e566042 100644
--- a/clang/test/lit.cfg.py
+++ b/clang/test/lit.cfg.py
@@ -279,6 +279,9 @@ def have_host_clang_repl_cuda():
 if not (config.build_shared_libs or config.link_llvm_dylib or 
config.link_clang_dylib):
     config.available_features.add("static-libs")
 
+if config.link_llvm_dylib:
+    config.available_features.add("llvm-dylib")
+
 # Plugins (loadable modules)
 if config.has_plugins and config.llvm_plugin_ext:
     config.available_features.add("plugins")
diff --git a/lld/test/CMakeLists.txt b/lld/test/CMakeLists.txt
index 1bd3ad7e1765b..e19bccae38fc5 100644
--- a/lld/test/CMakeLists.txt
+++ b/lld/test/CMakeLists.txt
@@ -5,6 +5,7 @@ llvm_canonicalize_cmake_booleans(
   LLVM_ENABLE_ZSTD
   LLVM_ENABLE_LIBXML2
   LLD_DEFAULT_LD_LLD_IS_MINGW
+  LLVM_LINK_LLVM_DYLIB
   LLVM_BUILD_EXAMPLES
   LLVM_ENABLE_PLUGINS
   LLVM_BYE_LINK_INTO_TOOLS
diff --git a/lld/test/ELF/lto/Inputs/pypass-plugin.ll 
b/lld/test/ELF/lto/Inputs/pypass-plugin.ll
new file mode 100644
index 0000000000000..c73e881a3e38d
--- /dev/null
+++ b/lld/test/ELF/lto/Inputs/pypass-plugin.ll
@@ -0,0 +1,7 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define i32 @main() {
+entry:
+  ret i32 0
+}
diff --git a/lld/test/ELF/lto/lit.local.cfg b/lld/test/ELF/lto/lit.local.cfg
new file mode 100644
index 0000000000000..65339be397824
--- /dev/null
+++ b/lld/test/ELF/lto/lit.local.cfg
@@ -0,0 +1,23 @@
+import os
+import platform
+import sysconfig
+
+pypass_plugin = f"pypass-plugin{config.llvm_shlib_ext}"
+pypass_plugin_shlib = os.path.join(config.llvm_shlib_dir, pypass_plugin)
+
+# Run end-to-end tests if the reference pass-plugin exists in LLVM
+if os.path.exists(pypass_plugin_shlib):
+    config.available_features.add("pypass-plugin")
+
+# Disable ASAN's leak detection for Python tests
+config.environment["ASAN_OPTIONS"] = "detect_leaks=0"
+
+if platform.system() != "Windows":
+    libdir = sysconfig.get_config_var("LIBDIR")
+    dylib = sysconfig.get_config_var("LDLIBRARY")
+    config.substitutions.append(("%libpython", os.path.join(libdir, dylib)))
+
+# FIXME: %llvmshlibdir is broken in standalone builds
+config.substitutions.append(("%plugindir", config.llvm_libs_dir))
+config.substitutions.append(("%pluginext", config.llvm_shlib_ext))
+config.suffixes.add(".py")
diff --git a/lld/test/ELF/lto/pypass-plugin-entrypoints.py 
b/lld/test/ELF/lto/pypass-plugin-entrypoints.py
new file mode 100644
index 0000000000000..ba69daa651c05
--- /dev/null
+++ b/lld/test/ELF/lto/pypass-plugin-entrypoints.py
@@ -0,0 +1,100 @@
+# REQUIRES: native, system-linux, llvm-dylib, plugins, pypass-plugin
+
+# Entry-points in pipeline for regular/monolithic LTO
+#
+# RUN: opt %S/Inputs/pypass-plugin.ll -o %t.o
+#
+# RUN: env LLVM_PYPASS_SCRIPT=%s \
+# RUN: env LLVM_PYPASS_DYLIB=%libpython \
+# RUN:   ld.lld --load-pass-plugin=%plugindir/pypass-plugin%pluginext %t.o \
+# RUN:           -shared -o /dev/null | FileCheck --check-prefix=REGULAR %s
+#
+# REGULAR-NOT: PipelineStartEPCallback
+# REGULAR-NOT: PipelineEarlySimplificationEPCallback
+# REGULAR-NOT: PeepholeEPCallback
+# REGULAR-NOT: ScalarOptimizerLateEPCallback
+# REGULAR-NOT: Vectorizer{{.*}}EPCallback
+# REGULAR-NOT: Optimizer{{.*}}EPCallback
+#
+# REGULAR: FullLinkTimeOptimizationEarlyEPCallback
+# REGULAR: FullLinkTimeOptimizationLastEPCallback
+
+# Entry-points in Thin-LTO pipeline
+#
+# RUN: opt --thinlto-bc %S/Inputs/pypass-plugin.ll -o %t_thin1.o
+# RUN: opt -module-summary %S/Inputs/pypass-plugin.ll -o %t_thin2.bc
+#
+# RUN: env LLVM_PYPASS_SCRIPT=%s \
+# RUN: env LLVM_PYPASS_DYLIB=%libpython \
+# RUN:   ld.lld --load-pass-plugin=%plugindir/pypass-plugin%pluginext 
%t_thin2.bc \
+# RUN:           -shared -o /dev/null | FileCheck --check-prefix=THIN %s
+#
+# THIN-NOT: FullLinkTimeOptimizationEarlyEPCallback
+# THIN-NOT: FullLinkTimeOptimizationLastEPCallback
+# THIN-NOT: PipelineStartEPCallback
+#
+# THIN: PipelineEarlySimplificationEPCallback
+# THIN: PeepholeEPCallback
+# THIN: ScalarOptimizerLateEPCallback
+# THIN: PeepholeEPCallback
+# THIN: OptimizerEarlyEPCallback
+# THIN: VectorizerStartEPCallback
+# THIN: VectorizerEndEPCallback
+# THIN: OptimizerLastEPCallback
+
+
+def registerPipelineStartEPCallback():
+    """Module pass at the start of the pipeline"""
+    return True
+
+
+def registerPipelineEarlySimplificationEPCallback():
+    """Module pass after basic simplification of input IR"""
+    return True
+
+
+def registerOptimizerEarlyEPCallback():
+    """Module pass before the function optimization pipeline"""
+    return True
+
+
+def registerOptimizerLastEPCallback():
+    """Module pass after the function optimization pipeline"""
+    return True
+
+
+def registerPeepholeEPCallback():
+    """Function pass after each instance of the instruction combiner pass"""
+    return True
+
+
+def registerScalarOptimizerLateEPCallback():
+    """Function pass after most of the main optimizations, but before the last
+    cleanup-ish optimizations"""
+    return True
+
+
+def registerVectorizerStartEPCallback():
+    """Function pass before the vectorizer and other highly target specific
+    optimization passes are executed"""
+    return True
+
+
+def registerVectorizerEndEPCallback():
+    """Function pass after the vectorizer and other highly target specific
+    optimization passes are executed"""
+    return True
+
+
+def registerFullLinkTimeOptimizationEarlyEPCallback():
+    """Module pass at the start of the full LTO pipeline"""
+    return True
+
+
+def registerFullLinkTimeOptimizationLastEPCallback():
+    """Module pass at the end of the full LTO pipeline"""
+    return True
+
+
+def run(input, ctx, stage):
+    print(f"0x{input:016x} {stage}")
diff --git a/lld/test/ELF/lto/pypass-plugin-pipeline-parsing.py 
b/lld/test/ELF/lto/pypass-plugin-pipeline-parsing.py
new file mode 100644
index 0000000000000..56c2554fac371
--- /dev/null
+++ b/lld/test/ELF/lto/pypass-plugin-pipeline-parsing.py
@@ -0,0 +1,18 @@
+# REQUIRES: native, system-linux, llvm-dylib, plugins, pypass-plugin
+#
+# RUN: opt %S/Inputs/pypass-plugin.ll -o %t.o
+#
+# RUN: env LLVM_PYPASS_SCRIPT=%s \
+# RUN: env LLVM_PYPASS_DYLIB=%libpython \
+# RUN:   ld.lld --load-pass-plugin=%plugindir/pypass-plugin%pluginext \
+# RUN:          --lto-newpm-passes=pypass %t.o -o /dev/null | FileCheck %s
+#
+# CHECK: 0x{{[0-9a-f]+}} Module
+
+
+def registerModulePipelineParsingCallback():
+    return True
+
+
+def run(input, ctx, stage):
+    print(f"0x{input:016x} {stage}")
diff --git a/lld/test/lit.cfg.py b/lld/test/lit.cfg.py
index 39c3d0aa36bfb..162672b3fc157 100644
--- a/lld/test/lit.cfg.py
+++ b/lld/test/lit.cfg.py
@@ -143,6 +143,9 @@
 if config.has_plugins:
     config.available_features.add("plugins")
 
+if config.link_llvm_dylib:
+    config.available_features.add("llvm-dylib")
+
 if config.build_examples:
     config.available_features.add("examples")
 
diff --git a/lld/test/lit.site.cfg.py.in b/lld/test/lit.site.cfg.py.in
index 703d3b1fd5337..127018166a6ee 100644
--- a/lld/test/lit.site.cfg.py.in
+++ b/lld/test/lit.site.cfg.py.in
@@ -26,6 +26,7 @@ config.ld_lld_default_mingw = @LLD_DEFAULT_LD_LLD_IS_MINGW@
 config.build_examples = @LLVM_BUILD_EXAMPLES@
 config.has_plugins = @LLVM_ENABLE_PLUGINS@
 config.linked_bye_extension = @LLVM_BYE_LINK_INTO_TOOLS@
+config.link_llvm_dylib = @LLVM_LINK_LLVM_DYLIB@
 config.enable_threads = @LLVM_ENABLE_THREADS@
 
 import lit.llvm
diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt
index 908580f791f36..29da2235add96 100644
--- a/llvm/CMakeLists.txt
+++ b/llvm/CMakeLists.txt
@@ -503,6 +503,10 @@ set(LLVM_EXAMPLES_INSTALL_DIR "examples" CACHE STRING
     "Path for examples subdirectory (enabled by LLVM_BUILD_EXAMPLES=ON) 
(defaults to 'examples')")
 mark_as_advanced(LLVM_EXAMPLES_INSTALL_DIR)
 
+set(LLVM_PLUGINS_INSTALL_DIR "plugins" CACHE STRING
+    "Path for plugins subdirectory (defaults to 'plugins')")
+mark_as_advanced(LLVM_PLUGINS_INSTALL_DIR)
+
 # They are used as destination of target generators.
 set(LLVM_RUNTIME_OUTPUT_INTDIR 
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin)
 set(LLVM_LIBRARY_OUTPUT_INTDIR 
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX})
diff --git a/llvm/cmake/modules/AddLLVM.cmake b/llvm/cmake/modules/AddLLVM.cmake
index 2480d7373d1a3..06916b4a520aa 100644
--- a/llvm/cmake/modules/AddLLVM.cmake
+++ b/llvm/cmake/modules/AddLLVM.cmake
@@ -932,7 +932,7 @@ endfunction()
 
 macro(add_llvm_library name)
   cmake_parse_arguments(ARG
-    "SHARED;BUILDTREE_ONLY;MODULE;INSTALL_WITH_TOOLCHAIN;NO_EXPORT"
+    
"SHARED;BUILDTREE_ONLY;MODULE;INSTALL_WITH_TOOLCHAIN;INSTALL_AS_PLUGIN;NO_EXPORT"
     ""
     ""
     ${ARGN})
@@ -972,11 +972,17 @@ macro(add_llvm_library name)
       else()
         get_target_export_arg(${name} LLVM export_to_llvmexports ${umbrella})
       endif()
-      install(TARGETS ${name}
-              ${export_to_llvmexports}
-              LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX} COMPONENT ${name}
-              ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX} COMPONENT ${name}
-              RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT ${name})
+      if(ARG_INSTALL_AS_PLUGIN)
+        install(TARGETS ${name}
+                ${export_to_llvmexports}
+                LIBRARY DESTINATION ${LLVM_PLUGINS_INSTALL_DIR} COMPONENT 
${name})
+      else()
+        install(TARGETS ${name}
+                ${export_to_llvmexports}
+                LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX} COMPONENT ${name}
+                ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX} COMPONENT ${name}
+                RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT 
${name})
+      endif()
 
       if (NOT LLVM_ENABLE_IDE)
         add_llvm_install_targets(install-${name}
@@ -1220,9 +1226,9 @@ function(add_llvm_pass_plugin name)
     endif()
     set_property(GLOBAL APPEND PROPERTY LLVM_STATIC_EXTENSIONS ${name})
   elseif(NOT ARG_NO_MODULE)
-    add_llvm_library(${name} MODULE NO_EXPORT ${ARG_UNPARSED_ARGUMENTS})
+    add_llvm_library(${name} MODULE NO_EXPORT INSTALL_AS_PLUGIN 
${ARG_UNPARSED_ARGUMENTS})
   else()
-    add_llvm_library(${name} OBJECT NO_EXPORT ${ARG_UNPARSED_ARGUMENTS})
+    add_llvm_library(${name} OBJECT NO_EXPORT INSTALL_AS_PLUGIN 
${ARG_UNPARSED_ARGUMENTS})
   endif()
   message(STATUS "Registering ${name} as a pass plugin (static build: 
${LLVM_${name_upper}_LINK_INTO_TOOLS})")
 
diff --git a/llvm/docs/CMake.rst b/llvm/docs/CMake.rst
index 7e95545425f2d..3a69ae42b75b2 100644
--- a/llvm/docs/CMake.rst
+++ b/llvm/docs/CMake.rst
@@ -951,6 +951,11 @@ things to go wrong.  They are also unstable across LLVM 
versions.
   Only matters if *LLVM_INSTALL_UTILS* is enabled.
   Defaults to *LLVM_TOOLS_INSTALL_DIR*.
 
+**LLVM_PLUGINS_INSTALL_DIR**:STRING
+  The path to install LLVM pass-plugins, relative to the 
*CMAKE_INSTALL_PREFIX*.
+  Defaults to *plugins*. Third-party vendors may install out-of-tree plugins
+  here for easy access and implicit version match.
+
 CMake Caches
 ============
 
diff --git a/llvm/test/tools/plugins-shlib/Inputs/foobar.ll 
b/llvm/test/tools/plugins-shlib/Inputs/foobar.ll
new file mode 100644
index 0000000000000..280014f623448
--- /dev/null
+++ b/llvm/test/tools/plugins-shlib/Inputs/foobar.ll
@@ -0,0 +1,2 @@
+define void @foo() { ret void }
+define void @bar() { ret void }
diff --git a/llvm/test/tools/plugins-shlib/Inputs/mymod.py 
b/llvm/test/tools/plugins-shlib/Inputs/mymod.py
new file mode 100644
index 0000000000000..fb1ede37b9000
--- /dev/null
+++ b/llvm/test/tools/plugins-shlib/Inputs/mymod.py
@@ -0,0 +1,5 @@
+import sys
+
+
+def pyversion():
+    print(f"Python version: {sys.version}")
diff --git a/llvm/test/tools/plugins-shlib/lit.local.cfg 
b/llvm/test/tools/plugins-shlib/lit.local.cfg
new file mode 100644
index 0000000000000..5d2f37e9490ab
--- /dev/null
+++ b/llvm/test/tools/plugins-shlib/lit.local.cfg
@@ -0,0 +1,21 @@
+import os
+import platform
+import sysconfig
+
+# Run end-to-end tests if the reference pass-plugin exists
+pypass_plugin = f"pypass-plugin{config.llvm_shlib_ext}"
+pypass_plugin_shlib = os.path.join(config.llvm_shlib_dir, pypass_plugin)
+if os.path.exists(p...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/171111
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to