#mir #bindings #jit #compiler #api-bindings

mir-rs

FFI bindings to MIR Project (https://github.com/vnmakarov/mir)

2 unstable releases

new 0.3.0 Mar 9, 2025
0.2.0 Mar 7, 2025
0.1.0 Apr 6, 2022

#457 in Programming languages

Download history 20/week @ 2025-02-09 6/week @ 2025-02-16 64/week @ 2025-03-02

90 downloads per month

MIT license

1.5MB
35K SLoC

C 33K SLoC // 0.1% comments Rust 2.5K SLoC // 0.0% comments

mir-rs: MIR project bindings for Rust

crates.io docs.rs CI Status

See documentation for more details.

License

MIT Licensed.


lib.rs:

MIR project bindings for Rust

Quick start

You can also check tests/smoke.rs for more examples.

Construct a function and execute it via MIR interpreter

use mir::{InsnBuilder, MirContext, Ty, Val};

// Initialize a context.
let ctx = MirContext::new();

// Create a module, a function, append instructions, and finally sealing them.
let m = ctx.enter_new_module(c"module_add");
// Note that MIR requires all argument types to be I64.
// extern "C" fn add(a: i64, b: i64) -> i64
let f = m.enter_new_function(c"add", &[Ty::I64], &[(c"a", Ty::I64), (c"b", Ty::I64)]);
let a = f.get_reg(c"a");
let b = f.get_reg(c"b");
let ret = f.new_local_reg(c"ret", Ty::I64);
f.ins().add(ret, a, b);
f.ins().ret(ret);
let func = f.finish();
let module = m.finish();

// Load and link modules.
ctx.load_module(module);
ctx.link_modules_for_interpret();

// Execute our functions.
let mut ret = [Val::default()];
unsafe { ctx.interpret_unchecked(func, &mut ret, &[Val::from(40i64), Val::from(2i64)]) };
assert_eq!(ret[0].as_i64(), 42);

Codegen a function to native code and execute it natively

use mir::{InsnBuilder, MirContext, MirGenContext, Ty};

// Initialize a context and codegen context.
let ctx = MirGenContext::new(MirContext::new());

// Same creation code.
let m = ctx.enter_new_module(c"module_add");
// ...
let module = m.finish();

// Set optimization level and/or other configurables.
ctx.set_opt_level(3);
// Load and link modules, for codegen.
ctx.load_module(module);
ctx.link_modules_for_codegen();

// Codegen and get a pointer to generated function.
let func_ptr = ctx.codegen_func(func);
type AddFunc = extern "C" fn(a: i64, b: i64) -> i64;
let func_ptr = unsafe { std::mem::transmute::<*mut _, AddFunc>(func_ptr) };

// Call it!
assert_eq!(func_ptr(40, 2), 42);

Panics and errors

Unfortunately MIR treats all errors as fatal errors and is likely to continue be like this. In mir-rs, we did a best-effort recovery to unwind in error callback inside C code via "C-unwind" ABI. This is always safe because all intermediate C frames are Plain Old Frames. But it may leave the C states inconsistent, thus it is strongly recommended to drop the MirContext if any modification method panics.

Features

  • default: Implies io, interp, gen.

  • io: De/serialization of MIR memory representation into/from bytes.

  • interp: Enables MIR interpreter.

  • gen: MIR native code generator.

  • gen-debug: Debug logging in MIR native code generator. It implies gen.

Dependencies