2 个不稳定版本
0.2.0 | 2022 年 10 月 1 日 |
---|---|
0.1.0 | 2022 年 9 月 7 日 |
#62 在 #pass
用于 llvm-plugin
14KB
76 行
llvm-plugin-rs
此包提供了通过利用 Inkwell 提供的强类型接口来安全地实现新 LLVM 调用管理器(pass manager)的能力。
如果您之前从未开发过 LLVM 调用管理器,可以查看可用的 示例。它们(希望)会给您一个更好的想法如何使用此包。
如果您想深入了解围绕新 LLVM 调用管理器的许多概念,应阅读 官方 LLVM 文档。
用法
在您的 Cargo.toml
中导入此包时,您需要指定要使用的 LLVM 版本和相应的功能标志
[dependencies]
llvm-plugin = { version = "0.2", features = ["llvm10-0"] }
支持版本
LLVM 版本 | Cargo 功能标志 | Linux | Windows | MacOS |
---|---|---|---|---|
10.0.x | llvm10-0 | ✓ | ✗ | ✓ |
11.0.x | llvm11-0 | ✓ | ✓ | ✓ |
12.0.x | llvm12-0 | ✓ | ✓ | ✓ |
13.0.x | llvm13-0 | ✓ | ✓ | ✓ |
14.0.x | llvm14-0 | ✓ | ✓ | ✓ |
入门
一个 LLVM 插件只是一个由 LLVM 工具(例如 opt、lld)加载时提供 PassBuilder 的 dylib。因此,您必须在您的 Cargo.toml
中添加以下行
[lib]
crate-type = ["cdylib"]
PassBuilder 允许在 LLVM 工具执行特定操作时注册回调。
例如,opt 的 --passes
参数允许指定要在给定的 IR 模块上运行的自定义调用管理器(pass)管道。因此,插件可以注册一个回调来解析给定管道的元素(例如调用管理器名称),以便通过 opt 插入一个自定义调用管理器。
以下代码展示了这一想法
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
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
还有更多回调可用,请参阅 文档 获取更多详细信息。
要了解如何顺序应用多个传递函数的更多内容,请阅读此 opt 指南。
Linux & MacOS 要求
您的 LLVM 工具链应动态链接 LLVM 库。幸运的是,在 apt
和 homebrew
注册表中分发的工具链都是这样。
如果您的情况不是这样,您必须通过指定 LLVM_LINK_LLVM_DYLIB=ON
cmake 标志从源代码编译 LLVM。
编译 LLVM-14
$ wget https://github.com/llvm/llvm-project/releases/download/llvmorg-14.0.0/llvm-14.0.0.src.tar.xz
$ tar xf llvm-14.0.0.src.tar.xz && cd llvm-14.0.0.src
$ mkdir build && cd build
$ cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX="$HOME/llvm" \
-DLLVM_LINK_LLVM_DYLIB=ON \
-G Ninja
$ ninja install
Windows 要求
在任何情况下,您都必须从源代码编译 LLVM,因为您需要在编译之前对 LLVM 代码库应用一些补丁。然后,您需要指定 LLVM_EXPORT_SYMBOLS_FOR_PLUGINS=ON
cmake 标志,同时将 LLVM_TARGETS_TO_BUILD
标志保留为其默认值。
编译 LLVM-14
$ wget https://github.com/llvm/llvm-project/releases/download/llvmorg-14.0.0/llvm-14.0.0.src.tar.xz
$ tar xf llvm-14.0.0.src.tar.xz && cd llvm-14.0.0.src
$ cat ../ci/windows/llvm-14.patch | patch -p1
$ mkdir build && cd build
$ cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX="C:\\llvm" \
-DLLVM_EXPORT_SYMBOLS_FOR_PLUGINS=ON \
-G Ninja
$ ninja install
$ cp lib/opt.lib /c/llvm/lib
别忘了更新您的 PATH
环境变量,使其包含您的 LLVM 安装路径。
缺少的功能
- 支持循环传递(
Inkwell
目前不提供安全包装器) - 支持 CGSCC 传递(
Inkwell
目前不提供安全包装器) - FFI 通过完整管理器代理 API(目前仅实现了一小部分)
- FFI 通过完整分析无效化 API(目前仅实现了一小部分)
- FFI 通过内置的 LLVM 分析(例如,支配树)
贡献受到欢迎,首先检查 贡献指南!
依赖关系
~1.5MB
~34K SLoC