Skip to main content

Crate lower_ir_utils

Crate lower_ir_utils 

Source
Expand description

Bridges Rust types to Cranelift Signature values, lowers values at JIT call sites, and trims Module / FunctionBuilder boilerplate while leaving the underlying APIs in your hands.

Cranelift / crate versions. This crate targets Cranelift 0.131 (see dependencies in Cargo.toml). Use matching cranelift-* versions in your project to avoid subtle ABI or API skew.

#[jit_export] is implemented in the companion crate lower-ir-utils-macros and re-exported here; see that crate’s docs for details on the generated <fn>_jit module.

§Platform and ABI notes

JitParam / JitArg model &str and slices as two machine words (data pointer and length), matching how separate (ptr, len) arguments look in Cranelift. That matches common 64-bit C ABIs (e.g. separate scalar args). #[jit_export] injects extern "C" when none is specified and allows improper_ctypes_definitions so you can write &str in Rust signatures on targets that pass fat pointers compatibly with that layout—on platforms where that does not hold, flatten parameters to scalars explicitly.

§Example (end-to-end JIT)

Flow (register host symbol → declare import → wrap with define_jit_fn! → finalize → call), adapted from tests/external_consumer/tests/smoke.rs in this repository. Add cranelift-jit, cranelift-module, cranelift-codegen, and cranelift-native alongside lower-ir-utils for this shape; or import the Cranelift crates through [__reexport] and keep only lower-ir-utils as a normal dependency, as that test crate does.

use cranelift_jit::{JITBuilder, JITModule};
use cranelift_module::{default_libcall_names, Linkage};
use cranelift_codegen::settings::{self, Configurable};
use lower_ir_utils::{define_jit_fn, jit_export};

#[jit_export]
fn add(a: i64, b: i64) -> i64 {
    a + b
}

let mut flag_builder = settings::builder();
flag_builder.set("use_colocated_libcalls", "false").unwrap();
flag_builder.set("is_pic", "false").unwrap();
let isa = cranelift_native::builder()
    .unwrap()
    .finish(settings::Flags::new(flag_builder))
    .unwrap();

let mut jb = JITBuilder::with_isa(isa, default_libcall_names());
add_jit::register(&mut jb);
let mut module = JITModule::new(jb);
let ext_id = add_jit::declare(&mut module);

let wrap_id = define_jit_fn!(
    &mut module, "wrap", Linkage::Export, fn(i64, i64) -> i64,
    |bcx, module, params| add_jit::call(bcx, module, ext_id, params[0], params[1]),
)
.unwrap();

module.finalize_definitions().unwrap();
let f: extern "C" fn(i64, i64) -> i64 =
    unsafe { std::mem::transmute(module.get_finalized_function(wrap_id)) };
assert_eq!(f(2, 3), 5);

§Main items

  • Traits: JitParam (Rust type → AbiParams), JitArg (Rust value → Value results via InstBuilder).
  • Macros: jit_signature!, jit_call!, define_jit_fn! (exported at the crate root).
  • define_function, IntoReturns: declare and define a function in one step.
  • Attribute macro: jit_export (re-export from lower_ir_utils_macros).

The crate README (also on docs.rs) adds another runnable sketch and links to more integration tests.

Re-exports§

pub use abi::JitArg;
pub use abi::JitParam;
pub use builder::define_function;
pub use builder::IntoReturns;

Modules§

abi
Traits describing how Rust types map onto Cranelift’s ABI.
builder
High-level helper to define a Cranelift function: declares the function, creates the FunctionBuilderContext + entry block, runs the user-supplied body closure to populate the IR, emits the return, and finalizes.

Macros§

define_jit_fn
Declare and define a Cranelift function in one call, with the signature expressed as Rust types.
jit_call
Emit a Cranelift call instruction, lowering each Rust argument via JitArg.
jit_signature
Build a Cranelift Signature from Rust types.

Attribute Macros§

jit_export
Annotate a Rust function so it can be called from JIT-compiled Cranelift IR.