Addition
Setup
The code is available in calculator/examples/llvm/src/main.rs
. Because my llvm-config --version
shows 14.0.6
so I'm using features = ["llvm14-0"]
in inkwell
inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "master", features = ["llvm14-0"] }
Go to calculator/examples/llvm
sub-crate and cargo run
.
Add Function
We want to define an add function like
add(x: i32, y: i32) -> i32 { x + y }
but using the LLVM language and JIT it. For that, we need to define every bit of what makes up a function through LLVM basic constructs such as context, module, function signature setups, argument types, basic block, etc.
Here is how to stitch our add function in LLVM
- We start by creating a
context
, adding theaddition
module and setting up the data type we want to usei32_type
of typeIntType
let context = Context::create();
let module = context.create_module("addition");
let i32_type = context.i32_type();
- We define the signature of
add(i32, i32) -> i32
, add the function to our module, create a basic block entry point and a builder to add later parts
let fn_type = i32_type.fn_type(&[i32_type.into(), i32_type.into()], false);
let fn_val = module.add_function("add", fn_type, None);
let entry_basic_block = context.append_basic_block(fn_val, "entry");
let builder = context.create_builder();
builder.position_at_end(entry_basic_block);
- We create the arguments
x
andy
and add them to thebuilder
to make up the return instruction
let x = fn_val.get_nth_param(0).unwrap().into_int_value();
let y = fn_val.get_nth_param(1).unwrap().into_int_value();
let ret = builder.build_int_add(x, y, "add").unwrap();
let return_instruction = builder.build_return(Some(&ret)).unwrap();
- Finally, we create a JIT execution engine (with no optimization for now) and let LLVM handle rest of the work for us
let execution_engine = module
.create_jit_execution_engine(OptimizationLevel::None)
.unwrap();
unsafe {
type Addition = unsafe extern "C" fn(i32, i32) -> i32;
let add: JitFunction<Addition> = execution_engine.get_function("add").unwrap();
let x = 1;
let y = 2;
assert_eq!(add.call(x, y), x + y);
}
Yes! all of this just to add two integers.