Last active
April 18, 2022 14:32
-
-
Save tpisto/a27e1a6447a9534214c2fb71dbe64145 to your computer and use it in GitHub Desktop.
OrcV2CBindingsBasicUsage.c in Rust llvm-sys
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://github.com/tpisto | |
// Nearly 1:1 translation of /llvm/examples/OrcV2Examples/OrcV2CBindingsBasicUsage/OrcV2CBindingsBasicUsage.c | |
// to Rust. In order to keep it even more 1:1 readable, I kept variable names as they are in the C -file. | |
extern crate llvm_sys as llvm; | |
use libc::*; | |
use llvm::core::{ | |
LLVMAddFunction, LLVMAppendBasicBlock, LLVMBuildAdd, LLVMBuildRet, LLVMCreateBuilder, | |
LLVMFunctionType, LLVMGetGlobalPassRegistry, LLVMGetParam, LLVMInt32Type, | |
LLVMModuleCreateWithNameInContext, LLVMPositionBuilderAtEnd, LLVMShutdown, | |
}; | |
use llvm::initialization::LLVMInitializeCore; | |
use llvm::orc2::lljit::{ | |
LLVMOrcCreateLLJIT, LLVMOrcCreateLLJITBuilder, LLVMOrcDisposeLLJIT, | |
LLVMOrcLLJITAddLLVMIRModule, LLVMOrcLLJITGetMainJITDylib, LLVMOrcLLJITLookup, | |
}; | |
use llvm::orc2::{ | |
LLVMOrcCreateNewThreadSafeContext, LLVMOrcCreateNewThreadSafeModule, | |
LLVMOrcDisposeThreadSafeContext, LLVMOrcOpaqueThreadSafeModule, | |
LLVMOrcThreadSafeContextGetContext, | |
}; | |
use llvm::support::LLVMParseCommandLineOptions; | |
use llvm::target::{LLVM_InitializeNativeAsmPrinter, LLVM_InitializeNativeTarget}; | |
use std::ffi::CString; | |
use std::mem::MaybeUninit; | |
macro_rules! cstr { | |
($str: expr) => { | |
concat!($str, "\0").as_ptr() as *const _ | |
}; | |
} | |
macro_rules! llvm_success_or_panic { | |
($e: expr) => { | |
let status: llvm_sys::error::LLVMErrorRef = $e; | |
if !status.is_null() { | |
let error_message = llvm_sys::error::LLVMGetErrorMessage(status); | |
let error_str = std::ffi::CStr::from_ptr(error_message).to_str().unwrap(); | |
panic!("{}", error_str); | |
} | |
}; | |
} | |
macro_rules! llvm_status_guard { | |
($e: expr) => { | |
match $e { | |
1 => panic!("llvm_status_guard fail!"), | |
_ => (), | |
} | |
}; | |
} | |
#[allow(non_snake_case)] | |
fn createDemoModule() -> *mut LLVMOrcOpaqueThreadSafeModule { | |
unsafe { | |
// Create a new ThreadSafeContext and underlying LLVMContext. | |
let TSCtx = LLVMOrcCreateNewThreadSafeContext(); | |
// Get a reference to the underlying LLVMContext. | |
let Ctx = LLVMOrcThreadSafeContextGetContext(TSCtx); | |
// Create a new LLVM module. | |
let M = LLVMModuleCreateWithNameInContext(cstr!("demo"), Ctx); | |
// Add a "sum" function" | |
// - Create the function type and function instance. | |
let mut ParamTypes = [LLVMInt32Type(), LLVMInt32Type()]; | |
let SumFunctionType = LLVMFunctionType(LLVMInt32Type(), ParamTypes.as_mut_ptr(), 2, 0); | |
let SumFunction = LLVMAddFunction(M, cstr!("sum"), SumFunctionType); | |
// - Add a basic block to the function. | |
let EntryBB = LLVMAppendBasicBlock(SumFunction, cstr!("entry")); | |
// - Add an IR builder and point it at the end of the basic block. | |
let Builder = LLVMCreateBuilder(); | |
LLVMPositionBuilderAtEnd(Builder, EntryBB); | |
// - Get the two function arguments and use them co construct an "add" | |
// instruction. | |
let SumArg0 = LLVMGetParam(SumFunction, 0); | |
let SumArg1 = LLVMGetParam(SumFunction, 1); | |
let Result = LLVMBuildAdd(Builder, SumArg0, SumArg1, cstr!("sum")); | |
// - Build the return instruction. | |
LLVMBuildRet(Builder, Result); | |
// Our demo module is now complete. Wrap it and our ThreadSafeContext in a | |
// ThreadSafeModule. | |
let TSM = LLVMOrcCreateNewThreadSafeModule(M, TSCtx); | |
// Dispose of our local ThreadSafeContext value. The underlying LLVMContext | |
// will be kept alive by our ThreadSafeModule, TSM. | |
LLVMOrcDisposeThreadSafeContext(TSCtx); | |
// Return the result. | |
TSM | |
} | |
} | |
#[allow(non_snake_case)] | |
fn main() { | |
// Parse command line arguments and initialize LLVM Core. | |
let args = std::env::args() | |
.map(|arg| CString::new(arg).unwrap()) | |
.collect::<Vec<CString>>(); | |
// convert the strings to raw pointers | |
let c_args = args | |
.iter() | |
.map(|arg| arg.as_ptr()) | |
.collect::<Vec<*const c_char>>(); | |
unsafe { | |
// Parse command line arguments and initialize LLVM Core. | |
LLVMParseCommandLineOptions(c_args.len() as i32, c_args.as_ptr(), cstr!("")); | |
LLVMInitializeCore(LLVMGetGlobalPassRegistry()); | |
// Initialize native target codegen and asm printer. | |
llvm_status_guard!(LLVM_InitializeNativeTarget()); | |
llvm_status_guard!(LLVM_InitializeNativeAsmPrinter()); | |
let mut J = MaybeUninit::uninit().assume_init(); | |
let jit_builder = LLVMOrcCreateLLJITBuilder(); | |
llvm_success_or_panic!(LLVMOrcCreateLLJIT(&mut J, jit_builder)); | |
// Create our demo module. | |
let TSM = createDemoModule(); | |
// Add our demo module to the JIT. | |
let MainJD = LLVMOrcLLJITGetMainJITDylib(J); | |
llvm_success_or_panic!(LLVMOrcLLJITAddLLVMIRModule(J, MainJD, TSM)); | |
// Look up the address of our demo entry point. | |
let mut sum_addr = MaybeUninit::uninit().assume_init(); | |
llvm_success_or_panic!(LLVMOrcLLJITLookup(J, &mut sum_addr, cstr!("sum"))); | |
// If we made it here then everything succeeded. Execute our JIT'd code. | |
let Sum: extern "C" fn(i32, i32) -> i32 = std::mem::transmute(sum_addr); | |
let Result = Sum(1, 2); | |
// Print the result | |
println!("1 + 2 = {}", Result); | |
// jit_cleanup: | |
// Destroy our JIT instance. This will clean up any memory that the JIT has | |
// taken ownership of. This operation is non-trivial (e.g. it may need to | |
// JIT static destructors) and may also fail. In that case we want to render | |
// the error to stderr, but not overwrite any existing return value. | |
llvm_success_or_panic!(LLVMOrcDisposeLLJIT(J)); | |
// llvm_shutdown: | |
LLVMShutdown(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment