1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
//! [![github]](https://github.com/jamesmth/llvm-plugin-rs) [![crates-io]](https://crates.io/crates/llvm-plugin)
//!
//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
//!
//! <br>
//!
//! 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, perhaps you should take a look at this
//! [LLVM guide] before carrying on. It will give you a simple overview of the C++ API
//! wrapped by 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/
//! [LLVM guide]: https://llvm.org/docs/WritingAnLLVMNewPMPass.html
//! [official LLVM documentation]: https://llvm.org/docs/NewPassManager.html
//!
//! # Example
//!
//! A simple LLVM plugin which defines two passes, one being a transformation pass that queries
//! the result of a second pass, an analysis one:
//!
//! ```
//! // Define an LLVM plugin (a name and a version is required). Only cdylib crates
//! // should define plugins, and only one definition should be done per crate.
//! #[llvm_plugin::plugin(name = "plugin_name", version = "0.1")]
//! mod plugin {
//! use llvm_plugin::{
//! LlvmModuleAnalysis, LlvmModulePass, ModuleAnalysisManager, PreservedAnalyses,
//! };
//! use llvm_plugin::inkwell::module::Module;
//!
//! // Must implement the `Default` trait.
//! #[derive(Default)]
//! struct Pass1;
//!
//! // Define a transformation pass (a name is required). Such pass is allowed to
//! // mutate the LLVM IR. If it does, it should return `PreservedAnalysis::None`
//! // to notify the pass manager that all analyses are now invalidated.
//! #[pass(name = "pass_name")]
//! impl LlvmModulePass for Pass1 {
//! fn run_pass(
//! &self,
//! module: &mut Module,
//! manager: &ModuleAnalysisManager,
//! ) -> PreservedAnalyses {
//! // Ask the pass manager for the result of the analysis pass `Analysis1`
//! // defined further below. If the result is not in cache, the pass
//! // manager will call `Analysis1::run_analysis`.
//! let result = manager.get_result::<Analysis1>(module);
//!
//! assert_eq!(result, "Hello World!");
//!
//! // no modification was made on the module, so the pass manager doesn't have
//! // to recompute any analysis
//! PreservedAnalyses::All
//! }
//! }
//!
//! // Must implement the `Default` trait.
//! #[derive(Default)]
//! struct Analysis1;
//!
//! // Define an analysis pass. Such pass is not allowed to mutate the LLVM IR. It should
//! // be used only for inspection of the LLVM IR, and can return some result that will be
//! // efficiently cached by the pass manager (to prevent recomputing the same analysis
//! // every time its result is needed).
//! #[analysis]
//! impl LlvmModuleAnalysis for Analysis1 {
//! fn run_analysis(
//! &self,
//! module: &Module,
//! manager: &ModuleAnalysisManager,
//! ) -> String {
//! // .. inspect the LLVM IR of the module ..
//!
//! "Hello World!".to_owned()
//! }
//! }
//! }
//! ```
#![deny(missing_docs)]
mod analysis;
pub use analysis::*;
#[doc(hidden)]
pub mod ffi;
#[doc(hidden)]
pub use ffi::*;
pub use inkwell;
use inkwell::module::Module;
use inkwell::values::FunctionValue;
/// Utilities.
pub mod utils;
/// Enum specifying whether analyses on an IR unit are not preserved due
/// to the modification of such unit by a transformation pass.
#[repr(C)]
#[derive(Clone, Copy)]
pub enum PreservedAnalyses {
/// This variant hints the pass manager that all the analyses are
/// preserved, so there is no need to re-execute analysis passes.
///
/// Use this variant when a transformation pass doesn't modify some
/// IR unit.
All,
/// This variant hints the pass manager that all the analyses are
/// should be re-executed.
///
/// Use this variant when a transformation pass modifies some IR unit.
None,
}
/// Trait to use for implementing a transformation pass on an LLVM module.
///
/// A transformation pass is allowed to mutate the LLVM IR.
pub trait LlvmModulePass: Default {
/// Entrypoint for the pass.
///
/// The given analysis manager allows the pass to query the pass
/// manager for the result of specific analysis passes.
///
/// If this function makes modifications on the given module IR, it
/// should return `PreservedAnalyses::None` to indicate to the
/// pass manager that all analyses are now invalidated.
fn run_pass<'a>(
&self,
module: &mut Module<'a>,
manager: &ModuleAnalysisManager,
) -> PreservedAnalyses;
}
/// Trait to use for implementing a transformation pass on an LLVM function.
///
/// A transformation pass is allowed to mutate the LLVM IR.
pub trait LlvmFunctionPass: Default {
/// Entrypoint for the pass.
///
/// The given analysis manager allows the pass to query the pass
/// manager for the result of specific analysis passes.
///
/// If this function makes modifications on the given function IR, it
/// should return `PreservedAnalyses::None` to indicate to the
/// pass manager that all analyses are now invalidated.
fn run_pass<'a>(
&self,
function: &mut FunctionValue<'a>,
manager: &FunctionAnalysisManager,
) -> PreservedAnalyses;
}
/// Trait to use for implementing an analysis pass on an LLVM module.
///
/// An analysis pass is not allowed to mutate the LLVM IR.
pub trait LlvmModuleAnalysis: Default {
/// Result of the successful execution of this pass by the pass manager.
///
/// This data can be queried by passes through a [`ModuleAnalysisManager`].
type Result;
/// Entrypoint for the pass.
///
/// The given analysis manager allows the pass to query the pass
/// manager for the result of specific analysis passes.
///
/// The returned result will be moved into a [`Box`](`std::boxed::Box`)
/// before being given to the pass manager. This one will then add it to
/// its internal cache, to avoid unnecessary calls to this entrypoint.
fn run_analysis<'a>(
&self,
module: &Module<'a>,
manager: &ModuleAnalysisManager,
) -> Self::Result;
#[doc(hidden)]
fn id() -> AnalysisKey;
}
/// Trait to use for implementing an analysis pass on an LLVM function.
///
/// An analysis pass is not allowed to mutate the LLVM IR.
pub trait LlvmFunctionAnalysis: Default {
/// Result of the successful execution of this pass by the pass manager.
///
/// This data can be queried by passes through a [`FunctionAnalysisManager`].
type Result;
/// Entrypoint for the pass.
///
/// The given analysis manager allows the pass to query the pass
/// manager for the result of specific analysis passes.
///
/// The returned result will be moved into a [`Box`](`std::boxed::Box`)
/// before being given to the pass manager. This one will then add it to
/// its internal cache, to avoid unnecessary calls to this entrypoint.
fn run_analysis<'a>(
&self,
module: &FunctionValue<'a>,
manager: &FunctionAnalysisManager,
) -> Self::Result;
#[doc(hidden)]
fn id() -> AnalysisKey;
}
#[doc(hidden)]
#[repr(C)]
pub struct PassPluginLibraryInfo {
pub api_version: u32,
pub plugin_name: *const u8,
pub plugin_version: *const u8,
pub plugin_registrar: unsafe extern "C" fn(*mut std::ffi::c_void),
}
#[cfg(feature = "macros")]
pub use llvm_plugin_macros::*;
// See https://github.com/jamesmth/llvm-plugin-rs/issues/1
#[cfg(all(target_os = "windows", feature = "llvm10-0"))]
compile_error!("LLVM 10 not supported on Windows");
// Taken from llvm-sys source code.
//
// Since we use `llvm-no-linking`, `llvm-sys` won't trigger that error
// for us, so we need to take care of it ourselves.
#[cfg(all(not(doc), LLVM_NOT_FOUND))]
compile_error!(
"No suitable version of LLVM was found system-wide or pointed
to by LLVM_PLUGIN_PREFIX."
);