#llvm #safe-wrapper #pass #safe #wrapper

llvm-plugin-macros

为 llvm-plugin 实现的进程宏

2 个不稳定版本

0.2.0 2022 年 10 月 1 日
0.1.0 2022 年 9 月 7 日

#62#pass


用于 llvm-plugin

Apache-2.0 许可

14KB
76

llvm-plugin-rs

version doc linux windows macos

此包提供了通过利用 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 工具(例如 optlld)加载时提供 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 库。幸运的是,在 apthomebrew 注册表中分发的工具链都是这样。

如果您的情况不是这样,您必须通过指定 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