12 个版本 (6 个重大更新)
0.6.0 | 2024年8月5日 |
---|---|
0.5.0 | 2024年2月10日 |
0.4.1 | 2023年5月3日 |
0.3.0 | 2023年1月21日 |
0.0.0-保留 | 2022年9月2日 |
#41 in FFI
每月下载 127 次
90KB
1.5K SLoC
llvm-plugin-rs
此 crate 通过利用 Inkwell 提供的强类型接口,使您能够安全地实现针对新 LLVM 插件管理器的 passes。
如果您以前从未开发过 LLVM passes,您可以查看可用的 示例。它们(希望)会给您一个更好的了解如何使用此 crate。
如果您想深入了解围绕新 LLVM 插件管理器的许多概念,您应该阅读官方 LLVM 文档。
用法
当在您的 Cargo.toml
中导入此 crate 时,您需要指定要使用的 LLVM 版本以及相应的功能标志
[dependencies]
llvm-plugin = { version = "0.6", features = ["llvm18-0"] }
支持版本:LLVM 10-18,对应于 cargo 功能标志 llvm*-0
,其中 *
对应于 LLVM 的主要版本。
入门
LLVM 插件只是一个由 LLVM 工具(例如 opt、lld)加载时提供 PassBuilder 的 dylib。因此,您必须在您的 Cargo.toml
中添加以下行
[lib]
crate-type = ["cdylib"]
PassBuilder 允许在 LLVM 工具执行特定操作时注册回调。
例如,opt 命令的 --passes
参数允许指定在给定的 IR 模块上运行的定制 pass 管道。因此,插件可以注册一个回调来解析给定管道的一个元素(例如,pass 名称),以便通过 opt 插入一个自定义的 pass。
以下代码说明了这个想法
use llvm_plugin::inkwell::module::Module;
use llvm_plugin::{
LlvmModulePass, ModuleAnalysisManager, PassBuilder, PipelineParsing, PreservedAnalyses,
};
// A name and version is required.
#[llvm_plugin::plugin(name = "plugin_name", version = "0.1")]
fn plugin_registrar(builder: &mut PassBuilder) {
// Add a callback to parse a name from the textual representation of
// the pipeline to be run.
builder.add_module_pipeline_parsing_callback(|name, manager| {
if name == "custom-pass" {
// the input pipeline contains the name "custom-pass",
// so we add our custom pass to the pass manager
manager.add_pass(CustomPass);
// we notify the caller that we were able to parse
// the given name
PipelineParsing::Parsed
} else {
// in any other cases, we notify the caller that our
// callback wasn't able to parse the given name
PipelineParsing::NotParsed
}
});
}
struct CustomPass;
impl LlvmModulePass for CustomPass {
fn run_pass(
&self,
module: &mut Module,
manager: &ModuleAnalysisManager
) -> PreservedAnalyses {
// transform the IR
todo!()
}
}
现在,执行此命令将在某些输入 module.bc
上运行我们的自定义 pass
opt --load-pass-plugin=libplugin.so --passes=custom-pass module.bc -disable-output
但是,执行此命令不会(custom-pass2 无法被我们的插件解析)
opt --load-pass-plugin=libplugin.so --passes=custom-pass2 module.bc -disable-output
还有更多回调可用,有关更多详细信息,请参阅 文档。
要了解如何顺序应用多个 pass 的更多信息,请参阅此 opt 指南。
Linux & MacOS 要求
您的 LLVM 工具链应该动态链接 LLVM 库。幸运的是,在 apt
和 homebrew
注册表中分发的工具链都是这种情况。
使用 apt 安装 LLVM-14
$ apt install llvm-14
使用 homebrew 安装 LLVM-14
$ brew install llvm@14
如果您不使用这些包管理器中的任何一个,您可以从此 LLVM 分支 下载兼容的 LLVM 工具链。在这种情况下,不要忘记使用您的 LLVM 工具链路径更新您的 PATH
环境变量,或者使用 LLVM_SYS_XXX_PREFIX
环境变量来定位您的工具链。
例如,如果您的 LLVM-14 工具链位于 ~/llvm
,您应该设置以下任一选项
PATH=$PATH;$HOME/llvm/bin
LLVM_SYS_140_PREFIX=$HOME/llvm
Windows 要求
Windows 的官方 LLVM 工具链未启用插件支持。但是,可以在 此处 找到兼容的工具链。
不要忘记使用您的 LLVM 工具链路径更新您的 PATH
环境变量,或者使用 LLVM_SYS_XXX_PREFIX
环境变量来定位您的工具链。
例如,如果您的 LLVM-14 工具链位于 C:\llvm
,您应该设置以下任一选项
PATH=$PATH;C:\llvm\bin
LLVM_SYS_140_PREFIX=C:\llvm
使用自定义 LLVM 插件编译 Rust/C++ 代码
此 LLVM 分支 解释了如何进行操作,并提供了一些将使该过程更简单的 LLVM 工具链。
缺少的功能
- 对循环 pass 的支持(
Inkwell
目前不提供安全的包装器) - 对 CGSCC pass 的支持(
Inkwell
目前不提供安全的包装器) - 在完整的 manager 代理 API 上使用 FFI(仅实现了子集)
- 在完整的分析无效化 API 上使用 FFI(仅实现了子集)
- 在内置的 LLVM 分析上使用 FFI(例如,支配树)
欢迎贡献,请首先查看 贡献指南!
依赖关系
~1.2–2.3MB
~43K SLoC