use cranelift_codegen::ir::{InstBuilder, Signature, UserFuncName, Value};
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
use cranelift_module::{FuncId, Linkage, Module, ModuleResult};
use smallvec::SmallVec;
pub trait IntoReturns {
fn into_returns(self) -> SmallVec<[Value; 4]>;
}
impl IntoReturns for () {
fn into_returns(self) -> SmallVec<[Value; 4]> {
SmallVec::new()
}
}
impl IntoReturns for Value {
fn into_returns(self) -> SmallVec<[Value; 4]> {
let mut s = SmallVec::new();
s.push(self);
s
}
}
impl<const N: usize> IntoReturns for [Value; N] {
fn into_returns(self) -> SmallVec<[Value; 4]> {
SmallVec::from_iter(self)
}
}
impl IntoReturns for Vec<Value> {
fn into_returns(self) -> SmallVec<[Value; 4]> {
SmallVec::from_vec(self)
}
}
impl IntoReturns for SmallVec<[Value; 4]> {
fn into_returns(self) -> SmallVec<[Value; 4]> {
self
}
}
#[allow(clippy::result_large_err)] pub fn define_function<M, F, R>(
module: &mut M,
name: &str,
linkage: Linkage,
signature: Signature,
body: F,
) -> ModuleResult<FuncId>
where
M: Module,
F: FnOnce(&mut FunctionBuilder<'_>, &mut M, &[Value]) -> R,
R: IntoReturns,
{
let func_id = module.declare_function(name, linkage, &signature)?;
let mut ctx = module.make_context();
ctx.func.signature = signature;
ctx.func.name = UserFuncName::user(0, func_id.as_u32());
let mut bcx_ctx = FunctionBuilderContext::new();
{
let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut bcx_ctx);
let entry = bcx.create_block();
bcx.append_block_params_for_function_params(entry);
bcx.switch_to_block(entry);
bcx.seal_block(entry);
let params: SmallVec<[Value; 8]> = bcx.block_params(entry).iter().copied().collect();
let returns = body(&mut bcx, module, ¶ms).into_returns();
bcx.ins().return_(&returns);
bcx.finalize();
}
module.define_function(func_id, &mut ctx)?;
module.clear_context(&mut ctx);
Ok(func_id)
}