Crate melior_next
source ·Expand description
Melior-next is the rustic MLIR bindings for Rust. It aims to provide a simple, safe, and complete API for MLIR with a reasonably sane ownership model represented by the type system in Rust.
This crate is a wrapper of the MLIR C API.
Dependencies
LLVM/MLIR 16 needs to be installed on your system.
Safety
Although Melior aims to be completely safe, some part of the current API is not.
- Access to operations, types, or attributes that belong to dialects not
loaded in contexts can lead to runtime errors or segmentation faults in
the worst case.
- Fix plan: Load all dialects by default on creation of contexts, and provide unsafe constructors of contexts for advanced users.
- IR object references returned from functions that move ownership of
arguments might get invalidated later.
- This is because we need to borrow
&self
rather than&mut self
to return such references. - e.g.
Region::append_block()
- Fix plan: Use dynamic check, such as
RefCell
, for the objects.
- This is because we need to borrow
Examples
Building a function to add integers and executing it using the JIT engine.
use melior_next::{
Context,
dialect::{self, arith},
ir::*,
pass,
utility::*,
ExecutionEngine
};
let registry = dialect::Registry::new();
register_all_dialects(®istry);
let context = Context::new();
context.append_dialect_registry(®istry);
context.get_or_load_dialect("func");
context.get_or_load_dialect("arith");
register_all_llvm_translations(&context);
let location = Location::unknown(&context);
let mut module = Module::new(location);
let integer_type = Type::integer(&context, 64);
let function = {
let region = Region::new();
let block = Block::new(&[(integer_type, location), (integer_type, location)]);
let arg1 = block.argument(0).unwrap().into();
let arg2 = block.argument(1).unwrap().into();
let sum = block.append_operation(
arith::addi(arg1, arg2, integer_type, location)
);
block.append_operation(
operation::Builder::new("func.return", Location::unknown(&context))
.add_operands(&[sum.result(0).unwrap().into()])
.build(),
);
region.append_block(block);
operation::Builder::new("func.func", Location::unknown(&context))
.add_attributes(
&NamedAttribute::new_parsed_vec(&context, &[
("function_type", "(i64, i64) -> i64"),
("sym_name", "\"add\""),
("llvm.emit_c_interface", "unit"),
]).unwrap()
)
.add_regions(vec![region])
.build()
};
module.body().append_operation(function);
assert!(module.as_operation().verify());
let pass_manager = pass::Manager::new(&context);
register_all_passes();
pass_manager.add_pass(pass::conversion::convert_scf_to_cf());
pass_manager.add_pass(pass::conversion::convert_cf_to_llvm());
pass_manager.add_pass(pass::conversion::convert_func_to_llvm());
pass_manager.add_pass(pass::conversion::convert_arithmetic_to_llvm());
pass_manager.enable_verifier(true);
pass_manager.run(&mut module).unwrap();
let engine = ExecutionEngine::new(&module, 2, &[], false);
let mut argument1: i64 = 2;
let mut argument2: i64 = 4;
let mut result: i64 = -1;
unsafe {
engine
.invoke_packed(
"add",
&mut [
&mut argument1 as *mut i64 as *mut (),
&mut argument2 as *mut i64 as *mut (),
&mut result as *mut i64 as *mut ()
])
.unwrap();
};
assert_eq!(result, 6);
Modules
- Dialect handles, instances, and registry.
- IR objects and builders.
- Passes and pass managers.
- Utility functions.
Structs
- A context of IR, dialects, and passes.
- A reference to a context.
- An execution engine.
- A logical result of success or failure.
- A string reference.
Enums
- A Melior error.