Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/jamesmth/llvm-plugin-rs
Out-of-tree LLVM passes in Rust
https://github.com/jamesmth/llvm-plugin-rs
ffi llvm-pass rust safe
Last synced: 1 day ago
JSON representation
Out-of-tree LLVM passes in Rust
- Host: GitHub
- URL: https://github.com/jamesmth/llvm-plugin-rs
- Owner: jamesmth
- License: apache-2.0
- Created: 2022-08-06T21:16:59.000Z (over 2 years ago)
- Default Branch: master
- Last Pushed: 2024-08-05T13:35:22.000Z (3 months ago)
- Last Synced: 2024-11-07T06:19:30.632Z (5 days ago)
- Topics: ffi, llvm-pass, rust, safe
- Language: Rust
- Homepage:
- Size: 141 KB
- Stars: 128
- Watchers: 2
- Forks: 8
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- Contributing: .github/CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
README
llvm-plugin-rs
==============[](https://crates.io/crates/llvm-plugin)
[](https://docs.rs/llvm-plugin)
[](https://github.com/jamesmth/llvm-plugin-rs/actions/workflows/linux.yml?query=branch%3Amaster)
[](https://github.com/jamesmth/llvm-plugin-rs/actions/workflows/windows.yml?query=branch%3Amaster)
[](https://github.com/jamesmth/llvm-plugin-rs/actions/workflows/macos.yml?query=branch%3Amaster)This crate gives the ability to safely implement passes for the [new LLVM pass manager], by leveraging the strongly typed interface
provided by [Inkwell].If you have never developed LLVM passes before, you can take a look at the available [examples]. They will (hopefully) give you a
better idea of how to use this crate.If you want a deeper understanding of the many concepts surrounding the new LLVM pass manager, you should read the [official LLVM
documentation].[Inkwell]: https://github.com/TheDan64/inkwell
[new LLVM pass manager]: https://blog.llvm.org/posts/2021-03-26-the-new-pass-manager/
[examples]: https://github.com/jamesmth/llvm-plugin-rs/tree/master/examples
[official LLVM documentation]: https://llvm.org/docs/NewPassManager.html## Usage
When importing this crate in your `Cargo.toml`, you will need to specify the LLVM version to use with a corresponding feature flag:
```toml
[dependencies]
llvm-plugin = { version = "0.6", features = ["llvm18-0"] }
```Supported versions: LLVM 10-18 mapping to a cargo feature flag `llvm*-0` where `*` corresponds to the LLVM major version.
## Getting Started
An LLVM plugin is merely a dylib that is given a [PassBuilder] by the LLVM tool (e.g. [opt], [lld])
loading it.
Therefore, you must add the following line in your `Cargo.toml`:```toml
[lib]
crate-type = ["cdylib"]
```A [PassBuilder] allows registering callbacks on specific actions being performed by the LLVM tool.
For instance, the `--passes` parameter of [opt] allows specifying a custom pass pipeline to be run on a given IR module. A plugin
could therefore register a callback for parsing an element of the given pipeline (e.g. a pass name), in order to insert a custom
pass to run by [opt].The following code illustrates the idea:
```rust
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!()
}
}
```Now, executing this command would run our custom pass on some input `module.bc`:
```bash
opt --load-pass-plugin=libplugin.so --passes=custom-pass module.bc -disable-output
```However, executing this command would not (`custom-pass2` cannot be parsed by our plugin):
```bash
opt --load-pass-plugin=libplugin.so --passes=custom-pass2 module.bc -disable-output
```More callbacks are available, read the [documentation] for more details.
To learn more about how to sequentially apply more than one pass, read this [opt guide].
[opt]: https://www.llvm.org/docs/CommandGuide/opt.html
[lld]: https://lld.llvm.org/
[PassBuilder]: https://docs.rs/llvm-plugin/latest/llvm_plugin/struct.PassBuilder.html
[documentation]: https://docs.rs/llvm-plugin
[opt guide]: https://llvm.org/docs/NewPassManager.html#invoking-opt## Linux & MacOS Requirements
Your LLVM toolchain should dynamically link the LLVM library. Fortunately, this is the case for toolchains
distributed on `apt` and `homebrew` registeries.Install LLVM-14 with apt
```shell
$ apt install llvm-14
```
Install LLVM-14 with homebrew
```shell
$ brew install llvm@14
```
If you don't use any of these package managers, you can download a compatible LLVM toolchain from
this [LLVM fork] instead. In this case, don't forget to update your `PATH` environment variable with
your LLVM toolchain path, or use the `LLVM_SYS_XXX_PREFIX` environment variable to locate your toolchain.For instance, if your LLVM-14 toolchain is located at `~/llvm`, you should set either of the following:
- `PATH=$PATH;$HOME/llvm/bin`
- `LLVM_SYS_140_PREFIX=$HOME/llvm`## Windows Requirements
The official LLVM toolchain for Windows was not built with plugin support. However, compatible toolchains can be found
[here](https://github.com/jamesmth/llvm-project/releases).Don't forget to update your `PATH` environment variable with your LLVM toolchain path, or use the `LLVM_SYS_XXX_PREFIX`
environment variable to locate your toolchain.For instance, if your LLVM-14 toolchain is located at `C:\llvm`, you should set either of the following:
- `PATH=$PATH;C:\llvm\bin`
- `LLVM_SYS_140_PREFIX=C:\llvm`## Compiling Rust/C++ code with custom LLVM plugins
This [LLVM fork] explains how to do so, and provides LLVM toolchains that will make the process easier.
[LLVM fork]: https://github.com/jamesmth/llvm-project
## Missing Features
- Support for loop passes (`Inkwell` doesn't currently provide safe wrappers)
- Support for CGSCC passes (`Inkwell` doesn't currently provide safe wrappers)
- FFI over the full manager proxy API (only a subset is currently implemented)
- FFI over the full analysis invalidation API (only a subset is currently implemented)
- FFI over builtin LLVM analyses (e.g. dominator tree)Contributions are very welcome, make sure to check out the [Contributing Guide] first!
[Contributing Guide]: ./.github/CONTRIBUTING.md