use codegen::ir::UserFuncName; use cranelift::prelude::*; use cranelift_jit::{JITBuilder, JITModule}; use cranelift_module::{default_libcall_names, Linkage, Module}; use std::mem; fn main() { let mut flag_builder = settings::builder(); flag_builder.set("use_colocated_libcalls", "false").unwrap(); // FIXME set back to true once the x64 backend supports it. flag_builder.set("is_pic", "false").unwrap(); let isa_builder = cranelift_native::builder().unwrap_or_else(|msg| { panic!("host machine is not supported: {msg}"); }); let isa = isa_builder .finish(settings::Flags::new(flag_builder)) .unwrap(); let mut module = JITModule::new(JITBuilder::with_isa(isa, default_libcall_names())); let mut ctx = module.make_context(); let mut func_ctx = FunctionBuilderContext::new(); let mut sig_a = module.make_signature(); sig_a.params.push(AbiParam::new(types::I32)); sig_a.returns.push(AbiParam::new(types::I32)); let mut sig_b = module.make_signature(); sig_b.returns.push(AbiParam::new(types::I32)); let func_a = module .declare_function("a", Linkage::Local, &sig_a) .unwrap(); let func_b = module .declare_function("b", Linkage::Local, &sig_b) .unwrap(); ctx.func.signature = sig_a; ctx.func.name = UserFuncName::user(0, func_a.as_u32()); { let mut bcx: FunctionBuilder = FunctionBuilder::new(&mut ctx.func, &mut func_ctx); let block = bcx.create_block(); bcx.switch_to_block(block); bcx.append_block_params_for_function_params(block); let param = bcx.block_params(block)[0]; let cst = bcx.ins().iconst(types::I32, 37); let add = bcx.ins().iadd(cst, param); bcx.ins().return_(&[add]); bcx.seal_all_blocks(); bcx.finalize(); } module.define_function(func_a, &mut ctx).unwrap(); module.clear_context(&mut ctx); ctx.func.signature = sig_b; ctx.func.name = UserFuncName::user(0, func_b.as_u32()); { let mut bcx: FunctionBuilder = FunctionBuilder::new(&mut ctx.func, &mut func_ctx); let block = bcx.create_block(); bcx.switch_to_block(block); let local_func = module.declare_func_in_func(func_a, &mut bcx.func); let arg = bcx.ins().iconst(types::I32, 5); let call = bcx.ins().call(local_func, &[arg]); let value = { let results = bcx.inst_results(call); assert_eq!(results.len(), 1); results[0] }; bcx.ins().return_(&[value]); bcx.seal_all_blocks(); bcx.finalize(); } module.define_function(func_b, &mut ctx).unwrap(); module.clear_context(&mut ctx); // Perform linking. module.finalize_definitions().unwrap(); // Get a raw pointer to the generated code. let code_b = module.get_finalized_function(func_b); // Cast it to a rust function pointer type. let ptr_b = unsafe { mem::transmute::<_, extern "C" fn() -> u32>(code_b) }; // Call it! let res = ptr_b(); assert_eq!(res, 42); }