Skip to content

Instantly share code, notes, and snippets.

@Papierkorb
Created October 31, 2017 15:22
Show Gist options
  • Save Papierkorb/ca61edbd543c4eb13f2aa1284c9cb4bf to your computer and use it in GitHub Desktop.
Save Papierkorb/ca61edbd543c4eb13f2aa1284c9cb4bf to your computer and use it in GitHub Desktop.
LLVM JIT example in Crystal
require "llvm"
# Initialize LLVM. There's also `LLVM.init_arm` if that's what you use.
LLVM.init_x86
# The context of everything we'll do. Main book-keeping structure.
ctx = LLVM::Context.new
# Code can be separated in different modules. A module can't directly interact
# with another module. If you'd do that, you'd have to link them.
mod = ctx.new_module("main_mod") # Names are generally for your eyes
# Build this prototype: `func sum(a : Int32, b : Int32) : Int32`
func = mod.functions.add("sum", [ ctx.int32, ctx.int32 ], ctx.int32)
# And now we have to add the logic of our function:
func.basic_blocks.append("entrypoint") do |b|
l = func.params[0] # Grab first parameter passed to us
r = func.params[1] # Second one too
# Do `l + r`. We call this variable `lr`. Again, this name is for us, LLVM
# doesn't care much about it. Choose something well-readable!
lr = b.add(l, r, "lr")
# And now the return statement
b.ret(lr)
end
# Dump the module to the screen.
mod.dump
# What we've all been waiting for: The actual JIT compiler!
jit = LLVM::JITCompiler.new(mod)
# The JIT will resolve symbols (and compile them) as needed. Just ask it for
# the pointer to our function we just created:
func_ptr = jit.get_pointer_to_global(func)
# And now, turn it into a Proc. For C people, this is like casting to `int(*)(int, int)`.
func_proc = Proc(Int32, Int32, Int32).new(func_ptr, Pointer(Void).null)
# ^ Arguments ^ Return type ^ Context. We don't have one!
# ^ The function pointer
# And now just call it like you'd call any other Proc:
pp func_proc.call(4, 5) # => 9
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment