forked from M-Labs/nac3
core/model: introduce `Model<'ctx>` abstraction
This commit is contained in:
parent
f6a554d3c9
commit
1be59d8fca
|
@ -0,0 +1,62 @@
|
||||||
|
use inkwell::{
|
||||||
|
types::{BasicMetadataTypeEnum, BasicType},
|
||||||
|
values::{AnyValue, BasicMetadataValueEnum, BasicValueEnum},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::codegen::{model::*, CodeGenContext};
|
||||||
|
|
||||||
|
// TODO: Variadic argument?
|
||||||
|
pub struct FunctionBuilder<'ctx, 'a> {
|
||||||
|
ctx: &'a CodeGenContext<'ctx, 'a>,
|
||||||
|
fn_name: &'a str,
|
||||||
|
arguments: Vec<(BasicMetadataTypeEnum<'ctx>, BasicMetadataValueEnum<'ctx>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx, 'a> FunctionBuilder<'ctx, 'a> {
|
||||||
|
pub fn begin(ctx: &'a CodeGenContext<'ctx, 'a>, fn_name: &'a str) -> Self {
|
||||||
|
FunctionBuilder { ctx, fn_name, arguments: Vec::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: `_name` is for self-documentation
|
||||||
|
#[must_use]
|
||||||
|
pub fn arg<M: Model<'ctx>>(mut self, _name: &'static str, model: M, value: M::Value) -> Self {
|
||||||
|
model.check_value(self.ctx.ctx, value).unwrap(); // Panics if the passed `value` has the incorrect type.
|
||||||
|
|
||||||
|
self.arguments
|
||||||
|
.push((model.get_llvm_type(self.ctx.ctx).into(), value.get_llvm_value().into()));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn returning<M: Model<'ctx>>(self, name: &'static str, return_model: M) -> M::Value {
|
||||||
|
let (param_tys, param_vals): (Vec<_>, Vec<_>) = self.arguments.into_iter().unzip();
|
||||||
|
|
||||||
|
// Get the LLVM function, create (by declaring) the function if it doesn't exist in `ctx.module`.
|
||||||
|
let function = self.ctx.module.get_function(self.fn_name).unwrap_or_else(|| {
|
||||||
|
let return_type = return_model.get_llvm_type(self.ctx.ctx);
|
||||||
|
let fn_type = return_type.fn_type(¶m_tys, false);
|
||||||
|
self.ctx.module.add_function(self.fn_name, fn_type, None)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Build call
|
||||||
|
let ret = self.ctx.builder.build_call(function, ¶m_vals, name).unwrap();
|
||||||
|
|
||||||
|
// Check the return value/type
|
||||||
|
let Ok(ret) = BasicValueEnum::try_from(ret.as_any_value_enum()) else {
|
||||||
|
panic!("Return type is not a BasicValue");
|
||||||
|
};
|
||||||
|
return_model.review_value(self.ctx.ctx, ret).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Code duplication, but otherwise returning<S: Optic<'ctx>> cannot resolve S if return_optic = None
|
||||||
|
pub fn returning_void(self) {
|
||||||
|
let (param_tys, param_vals): (Vec<_>, Vec<_>) = self.arguments.into_iter().unzip();
|
||||||
|
|
||||||
|
let function = self.ctx.module.get_function(self.fn_name).unwrap_or_else(|| {
|
||||||
|
let return_type = self.ctx.ctx.void_type();
|
||||||
|
let fn_type = return_type.fn_type(¶m_tys, false);
|
||||||
|
self.ctx.module.add_function(self.fn_name, fn_type, None)
|
||||||
|
});
|
||||||
|
|
||||||
|
self.ctx.builder.build_call(function, ¶m_vals, "").unwrap();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
pub mod core;
|
pub mod core;
|
||||||
pub mod fixed_int;
|
pub mod fixed_int;
|
||||||
|
pub mod function_builder;
|
||||||
pub mod int;
|
pub mod int;
|
||||||
mod int_util;
|
mod int_util;
|
||||||
pub mod opaque;
|
pub mod opaque;
|
||||||
|
|
Loading…
Reference in New Issue