Compare commits

...

15 Commits

8 changed files with 238 additions and 189 deletions

View File

@ -13,7 +13,7 @@ use super::*;
pub struct Any<'ctx>(pub BasicTypeEnum<'ctx>); pub struct Any<'ctx>(pub BasicTypeEnum<'ctx>);
impl<'ctx> ModelBase<'ctx> for Any<'ctx> { impl<'ctx> ModelBase<'ctx> for Any<'ctx> {
fn get_type_impl(&self, _size_t: IntType<'ctx>, _ctx: &'ctx Context) -> BasicTypeEnum<'ctx> { fn llvm_type_impl(&self, _size_t: IntType<'ctx>, _ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
self.0.as_basic_type_enum() self.0.as_basic_type_enum()
} }

View File

@ -1,4 +1,4 @@
use std::fmt; use std::{fmt, marker::PhantomData};
use inkwell::{ use inkwell::{
context::Context, context::Context,
@ -11,8 +11,8 @@ use crate::codegen::{CodeGenContext, CodeGenerator};
use super::*; use super::*;
/// Trait for Rust structs identifying length values for [`Array`]. /// Trait for Rust structs identifying length values for [`Array`].
pub trait LenKind: fmt::Debug + Clone + Copy { pub trait ArrayLen: fmt::Debug + Clone + Copy {
fn get_length(&self) -> u32; fn length(&self) -> u32;
} }
/// A statically known length. /// A statically known length.
@ -23,14 +23,14 @@ pub struct Len<const N: u32>;
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct AnyLen(pub u32); pub struct AnyLen(pub u32);
impl<const N: u32> LenKind for Len<N> { impl<const N: u32> ArrayLen for Len<N> {
fn get_length(&self) -> u32 { fn length(&self) -> u32 {
N N
} }
} }
impl LenKind for AnyLen { impl ArrayLen for AnyLen {
fn get_length(&self) -> u32 { fn length(&self) -> u32 {
self.0 self.0
} }
} }
@ -39,17 +39,24 @@ impl LenKind for AnyLen {
/// ///
/// `Len` should be of a [`LenKind`] and `Item` should be a of [`Model`]. /// `Len` should be of a [`LenKind`] and `Item` should be a of [`Model`].
#[derive(Debug, Clone, Copy, Default)] #[derive(Debug, Clone, Copy, Default)]
pub struct Array<Len, Item> { pub struct Array<'ctx, Len: ArrayLen, Item: ModelBase<'ctx>> {
/// Length of this array. /// Length of this array.
pub len: Len, pub len: Len,
/// [`Model`] of the array items. /// [`Model`] of the array items.
pub item: Item, pub item: Item,
pub _phantom: PhantomData<&'ctx ()>,
} }
impl<'ctx, Len: LenKind, Item: ModelBase<'ctx>> ModelBase<'ctx> for Array<Len, Item> { impl<'ctx, Len: ArrayLen, Item: ModelBase<'ctx>> Array<'ctx, Len, Item> {
fn get_type_impl(&self, size_t: IntType<'ctx>, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> { pub fn new(len: Len, item: Item) -> Self {
let item = self.item.get_type_impl(size_t, ctx); Array { len, item, _phantom: PhantomData }
item.array_type(self.len.get_length()).into() }
}
impl<'ctx, Len: ArrayLen, Item: ModelBase<'ctx>> ModelBase<'ctx> for Array<'ctx, Len, Item> {
fn llvm_type_impl(&self, size_t: IntType<'ctx>, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
let item = self.item.llvm_type_impl(size_t, ctx);
item.array_type(self.len.length()).into()
} }
fn check_type_impl( fn check_type_impl(
@ -62,11 +69,11 @@ impl<'ctx, Len: LenKind, Item: ModelBase<'ctx>> ModelBase<'ctx> for Array<Len, I
return Err(ModelError(format!("Expecting ArrayType, but got {ty:?}"))); return Err(ModelError(format!("Expecting ArrayType, but got {ty:?}")));
}; };
if ty.len() != self.len.get_length() { if ty.len() != self.len.length() {
return Err(ModelError(format!( return Err(ModelError(format!(
"Expecting ArrayType with size {}, but got an ArrayType with size {}", "Expecting ArrayType with size {}, but got an ArrayType with size {}",
ty.len(), ty.len(),
self.len.get_length() self.len.length()
))); )));
} }
@ -78,33 +85,33 @@ impl<'ctx, Len: LenKind, Item: ModelBase<'ctx>> ModelBase<'ctx> for Array<Len, I
} }
} }
impl<'ctx, Len: LenKind, Item: Model<'ctx>> Model<'ctx> for Array<Len, Item> { impl<'ctx, Len: ArrayLen, Item: Model<'ctx>> Model<'ctx> for Array<'ctx, Len, Item> {
type Type = ArrayType<'ctx>; type Type = ArrayType<'ctx>;
type Value = ArrayValue<'ctx>; type Value = ArrayValue<'ctx>;
} }
impl<'ctx, Len: LenKind, Item: Model<'ctx>> Instance<'ctx, Ptr<Array<Len, Item>>> { impl<'ctx, Len: ArrayLen, Item: Model<'ctx>> Instance<'ctx, Ptr<Array<'ctx, Len, Item>>> {
/// Get the pointer to the `i`-th (0-based) array element. /// Get the pointer to the `i`-th (0-based) array element.
pub fn gep( pub fn gep(
&self, &self,
ctx: &CodeGenContext<'ctx, '_>, ctx: &CodeGenContext<'ctx, '_>,
i: IntValue<'ctx>, i: IntValue<'ctx>,
) -> Instance<'ctx, Ptr<Item>> { ) -> Instance<'ctx, Ptr<Item>> {
let zero = ctx.ctx.i32_type().const_zero(); let zero = ctx.ctx.i64_type().const_zero();
let ptr = unsafe { ctx.builder.build_in_bounds_gep(self.value, &[zero, i], "").unwrap() }; let ptr = unsafe { ctx.builder.build_in_bounds_gep(self.value, &[zero, i], "").unwrap() };
Ptr(self.model.0.item).believe_value(ptr) unsafe { Ptr::new(self.model.item.item).believe_value(ptr) }
} }
/// Like `gep` but `i` is a constant. /// Like `gep` but `i` is a constant.
pub fn gep_const(&self, ctx: &CodeGenContext<'ctx, '_>, i: u64) -> Instance<'ctx, Ptr<Item>> { pub fn gep_const(&self, ctx: &CodeGenContext<'ctx, '_>, i: u64) -> Instance<'ctx, Ptr<Item>> {
assert!( assert!(
i < u64::from(self.model.0.len.get_length()), i < u64::from(self.model.item.len.length()),
"Index {i} is out of bounds. Array length = {}", "Index {i} is out of bounds. Array length = {}",
self.model.0.len.get_length() self.model.item.len.length()
); );
let i = ctx.ctx.i32_type().const_int(i, false); let i = ctx.ctx.i64_type().const_int(i, true);
self.gep(ctx, i) self.gep(ctx, i)
} }

View File

@ -11,7 +11,7 @@ use crate::codegen::{CodeGenContext, CodeGenerator};
pub struct ModelError(pub String); pub struct ModelError(pub String);
impl ModelError { impl ModelError {
// Append a context message to the error. /// Append a context message to the error.
pub(super) fn under_context(mut self, context: &str) -> Self { pub(super) fn under_context(mut self, context: &str) -> Self {
self.0.push_str(" ... in "); self.0.push_str(" ... in ");
self.0.push_str(context); self.0.push_str(context);
@ -24,8 +24,8 @@ pub trait ModelBase<'ctx> {
// NOTE: Taking `size_t` here instead of `CodeGenerator` to be object safe. // NOTE: Taking `size_t` here instead of `CodeGenerator` to be object safe.
// In fact, all the entire model abstraction need from the `CodeGenerator` is its `get_size_type()`. // In fact, all the entire model abstraction need from the `CodeGenerator` is its `get_size_type()`.
// NOTE: Model's get_type but object-safe and returns BasicTypeEnum, instead of a known BasicType variant. // NOTE: Model's llvm_type but object-safe and returns BasicTypeEnum, instead of a known BasicType variant.
fn get_type_impl(&self, size_t: IntType<'ctx>, ctx: &'ctx Context) -> BasicTypeEnum<'ctx>; fn llvm_type_impl(&self, size_t: IntType<'ctx>, ctx: &'ctx Context) -> BasicTypeEnum<'ctx>;
// NOTE: Model's check_type but object-safe. // NOTE: Model's check_type but object-safe.
fn check_type_impl( fn check_type_impl(
@ -45,7 +45,7 @@ pub trait ModelBase<'ctx> {
/// - [`Int<AnyInt>`] identifies an [`IntType`] with bit-width of whatever is set in the [`AnyInt`] object. /// - [`Int<AnyInt>`] identifies an [`IntType`] with bit-width of whatever is set in the [`AnyInt`] object.
/// - [`Any`] identifies a [`BasicType`] set in the [`Any`] object itself. /// - [`Any`] identifies a [`BasicType`] set in the [`Any`] object itself.
/// ///
/// You can get the [`BasicType`] out of a model with [`Model::get_type`]. /// You can get the [`BasicType`] out of a model with [`Model::llvm_type`].
/// ///
/// Furthermore, [`Instance<'ctx, M>`] is a simple structure that carries a [`BasicValue`] with [`BasicType`] identified by model `M`. /// Furthermore, [`Instance<'ctx, M>`] is a simple structure that carries a [`BasicValue`] with [`BasicType`] identified by model `M`.
/// ///
@ -85,10 +85,14 @@ pub trait Model<'ctx>: fmt::Debug + Clone + Copy + ModelBase<'ctx> {
/// Return the [`BasicType`] of this model. /// Return the [`BasicType`] of this model.
#[must_use] #[must_use]
fn get_type<G: CodeGenerator + ?Sized>(&self, generator: &G, ctx: &'ctx Context) -> Self::Type { fn llvm_type<G: CodeGenerator + ?Sized>(
&self,
generator: &G,
ctx: &'ctx Context,
) -> Self::Type {
let size_t = generator.get_size_type(ctx); let size_t = generator.get_size_type(ctx);
let ty = self.get_type_impl(size_t, ctx); let ty = self.llvm_type_impl(size_t, ctx);
match Self::Type::try_from(ty) { match Self::Type::try_from(ty) {
Ok(ty) => ty, Ok(ty) => ty,
_ => panic!("Model::Type is inconsistent with what is returned from ModelBase::get_type_impl()! Got {ty:?}."), _ => panic!("Model::Type is inconsistent with what is returned from ModelBase::get_type_impl()! Got {ty:?}."),
@ -96,12 +100,12 @@ pub trait Model<'ctx>: fmt::Debug + Clone + Copy + ModelBase<'ctx> {
} }
/// Get the number of bytes of the [`BasicType`] of this model. /// Get the number of bytes of the [`BasicType`] of this model.
fn sizeof<G: CodeGenerator + ?Sized>( fn size_of<G: CodeGenerator + ?Sized>(
&self, &self,
generator: &mut G, generator: &mut G,
ctx: &'ctx Context, ctx: &'ctx Context,
) -> IntValue<'ctx> { ) -> IntValue<'ctx> {
self.get_type(generator, ctx).size_of().unwrap() self.llvm_type(generator, ctx).size_of().unwrap()
} }
/// Check if a [`BasicType`] matches the [`BasicType`] of this model. /// Check if a [`BasicType`] matches the [`BasicType`] of this model.
@ -117,9 +121,11 @@ pub trait Model<'ctx>: fmt::Debug + Clone + Copy + ModelBase<'ctx> {
/// Create an instance from a value. /// Create an instance from a value.
/// ///
/// # Safety
///
/// Caller must make sure the type of `value` and the type of this `model` are equivalent. /// Caller must make sure the type of `value` and the type of this `model` are equivalent.
#[must_use] #[must_use]
fn believe_value(&self, value: Self::Value) -> Instance<'ctx, Self> { unsafe fn believe_value(&self, value: Self::Value) -> Instance<'ctx, Self> {
Instance { model: *self, value } Instance { model: *self, value }
} }
@ -138,7 +144,7 @@ pub trait Model<'ctx>: fmt::Debug + Clone + Copy + ModelBase<'ctx> {
let Ok(value) = Self::Value::try_from(value) else { let Ok(value) = Self::Value::try_from(value) else {
unreachable!("check_type() has bad implementation") unreachable!("check_type() has bad implementation")
}; };
Ok(self.believe_value(value)) Ok(unsafe { self.believe_value(value) })
} }
// Allocate a value on the stack and return its pointer. // Allocate a value on the stack and return its pointer.
@ -147,8 +153,8 @@ pub trait Model<'ctx>: fmt::Debug + Clone + Copy + ModelBase<'ctx> {
generator: &mut G, generator: &mut G,
ctx: &CodeGenContext<'ctx, '_>, ctx: &CodeGenContext<'ctx, '_>,
) -> Instance<'ctx, Ptr<Self>> { ) -> Instance<'ctx, Ptr<Self>> {
let p = ctx.builder.build_alloca(self.get_type(generator, ctx.ctx), "").unwrap(); let p = ctx.builder.build_alloca(self.llvm_type(generator, ctx.ctx), "").unwrap();
Ptr(*self).believe_value(p) unsafe { Ptr::new(*self).believe_value(p) }
} }
// Allocate an array on the stack and return its pointer. // Allocate an array on the stack and return its pointer.
@ -158,8 +164,9 @@ pub trait Model<'ctx>: fmt::Debug + Clone + Copy + ModelBase<'ctx> {
ctx: &CodeGenContext<'ctx, '_>, ctx: &CodeGenContext<'ctx, '_>,
len: IntValue<'ctx>, len: IntValue<'ctx>,
) -> Instance<'ctx, Ptr<Self>> { ) -> Instance<'ctx, Ptr<Self>> {
let p = ctx.builder.build_array_alloca(self.get_type(generator, ctx.ctx), len, "").unwrap(); let p =
Ptr(*self).believe_value(p) ctx.builder.build_array_alloca(self.llvm_type(generator, ctx.ctx), len, "").unwrap();
unsafe { Ptr::new(*self).believe_value(p) }
} }
fn var_alloca<G: CodeGenerator + ?Sized>( fn var_alloca<G: CodeGenerator + ?Sized>(
@ -168,9 +175,9 @@ pub trait Model<'ctx>: fmt::Debug + Clone + Copy + ModelBase<'ctx> {
ctx: &mut CodeGenContext<'ctx, '_>, ctx: &mut CodeGenContext<'ctx, '_>,
name: Option<&str>, name: Option<&str>,
) -> Result<Instance<'ctx, Ptr<Self>>, String> { ) -> Result<Instance<'ctx, Ptr<Self>>, String> {
let ty = self.get_type(generator, ctx.ctx).as_basic_type_enum(); let ty = self.llvm_type(generator, ctx.ctx).as_basic_type_enum();
let p = generator.gen_var_alloc(ctx, ty, name)?; let p = generator.gen_var_alloc(ctx, ty, name)?;
Ok(Ptr(*self).believe_value(p)) Ok(unsafe { Ptr::new(*self).believe_value(p) })
} }
fn array_var_alloca<G: CodeGenerator + ?Sized>( fn array_var_alloca<G: CodeGenerator + ?Sized>(
@ -181,9 +188,9 @@ pub trait Model<'ctx>: fmt::Debug + Clone + Copy + ModelBase<'ctx> {
name: Option<&'ctx str>, name: Option<&'ctx str>,
) -> Result<Instance<'ctx, Ptr<Self>>, String> { ) -> Result<Instance<'ctx, Ptr<Self>>, String> {
// TODO: Remove ArraySliceValue // TODO: Remove ArraySliceValue
let ty = self.get_type(generator, ctx.ctx).as_basic_type_enum(); let ty = self.llvm_type(generator, ctx.ctx).as_basic_type_enum();
let p = generator.gen_array_var_alloc(ctx, ty, len, name)?; let p = generator.gen_array_var_alloc(ctx, ty, len, name)?;
Ok(Ptr(*self).believe_value(PointerValue::from(p))) Ok(unsafe { Ptr::new(*self).believe_value(PointerValue::from(p)) })
} }
/// Allocate a constant array. /// Allocate a constant array.
@ -192,7 +199,7 @@ pub trait Model<'ctx>: fmt::Debug + Clone + Copy + ModelBase<'ctx> {
generator: &mut G, generator: &mut G,
ctx: &'ctx Context, ctx: &'ctx Context,
values: &[Instance<'ctx, Self>], values: &[Instance<'ctx, Self>],
) -> Instance<'ctx, Array<AnyLen, Self>> { ) -> Instance<'ctx, Array<'ctx, AnyLen, Self>> {
macro_rules! make { macro_rules! make {
($t:expr, $into_value:expr) => { ($t:expr, $into_value:expr) => {
$t.const_array( $t.const_array(
@ -204,7 +211,7 @@ pub trait Model<'ctx>: fmt::Debug + Clone + Copy + ModelBase<'ctx> {
}; };
} }
let value = match self.get_type(generator, ctx).as_basic_type_enum() { let value = match self.llvm_type(generator, ctx).as_basic_type_enum() {
BasicTypeEnum::ArrayType(t) => make!(t, BasicValueEnum::into_array_value), BasicTypeEnum::ArrayType(t) => make!(t, BasicValueEnum::into_array_value),
BasicTypeEnum::IntType(t) => make!(t, BasicValueEnum::into_int_value), BasicTypeEnum::IntType(t) => make!(t, BasicValueEnum::into_int_value),
BasicTypeEnum::FloatType(t) => make!(t, BasicValueEnum::into_float_value), BasicTypeEnum::FloatType(t) => make!(t, BasicValueEnum::into_float_value),
@ -213,9 +220,8 @@ pub trait Model<'ctx>: fmt::Debug + Clone + Copy + ModelBase<'ctx> {
BasicTypeEnum::VectorType(t) => make!(t, BasicValueEnum::into_vector_value), BasicTypeEnum::VectorType(t) => make!(t, BasicValueEnum::into_vector_value),
}; };
Array { len: AnyLen(values.len() as u32), item: *self } let model = Array::new(AnyLen(values.len() as u32), *self);
.check_value(generator, ctx, value) model.check_value(generator, ctx, value).unwrap()
.unwrap()
} }
} }
@ -223,6 +229,7 @@ pub trait Model<'ctx>: fmt::Debug + Clone + Copy + ModelBase<'ctx> {
pub struct Instance<'ctx, M: Model<'ctx>> { pub struct Instance<'ctx, M: Model<'ctx>> {
/// The model of this instance. /// The model of this instance.
pub model: M, pub model: M,
/// The value of this instance. /// The value of this instance.
/// ///
/// It is guaranteed the [`BasicType`] of `value` is consistent with that of `model`. /// It is guaranteed the [`BasicType`] of `value` is consistent with that of `model`.

View File

@ -1,4 +1,4 @@
use std::fmt; use std::{fmt, marker::PhantomData};
use inkwell::{ use inkwell::{
context::Context, context::Context,
@ -9,7 +9,7 @@ use inkwell::{
use super::*; use super::*;
pub trait FloatKind<'ctx>: fmt::Debug + Clone + Copy { pub trait FloatKind<'ctx>: fmt::Debug + Clone + Copy {
fn get_float_type(&self, ctx: &'ctx Context) -> FloatType<'ctx>; fn float_type(&self, ctx: &'ctx Context) -> FloatType<'ctx>;
} }
#[derive(Debug, Clone, Copy, Default)] #[derive(Debug, Clone, Copy, Default)]
@ -18,13 +18,13 @@ pub struct Float32;
pub struct Float64; pub struct Float64;
impl<'ctx> FloatKind<'ctx> for Float32 { impl<'ctx> FloatKind<'ctx> for Float32 {
fn get_float_type(&self, ctx: &'ctx Context) -> FloatType<'ctx> { fn float_type(&self, ctx: &'ctx Context) -> FloatType<'ctx> {
ctx.f32_type() ctx.f32_type()
} }
} }
impl<'ctx> FloatKind<'ctx> for Float64 { impl<'ctx> FloatKind<'ctx> for Float64 {
fn get_float_type(&self, ctx: &'ctx Context) -> FloatType<'ctx> { fn float_type(&self, ctx: &'ctx Context) -> FloatType<'ctx> {
ctx.f64_type() ctx.f64_type()
} }
} }
@ -33,17 +33,26 @@ impl<'ctx> FloatKind<'ctx> for Float64 {
pub struct AnyFloat<'ctx>(FloatType<'ctx>); pub struct AnyFloat<'ctx>(FloatType<'ctx>);
impl<'ctx> FloatKind<'ctx> for AnyFloat<'ctx> { impl<'ctx> FloatKind<'ctx> for AnyFloat<'ctx> {
fn get_float_type(&self, _ctx: &'ctx Context) -> FloatType<'ctx> { fn float_type(&self, _ctx: &'ctx Context) -> FloatType<'ctx> {
self.0 self.0
} }
} }
#[derive(Debug, Clone, Copy, Default)] #[derive(Debug, Clone, Copy, Default)]
pub struct Float<N>(pub N); pub struct Float<'ctx, N: FloatKind<'ctx>> {
kind: N,
_phantom: PhantomData<&'ctx ()>,
}
impl<'ctx, N: FloatKind<'ctx>> ModelBase<'ctx> for Float<N> { impl<'ctx, N: FloatKind<'ctx>> Float<'ctx, N> {
fn get_type_impl(&self, _size_t: IntType<'ctx>, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> { pub fn new(kind: N) -> Self {
self.0.get_float_type(ctx).into() Float { kind, _phantom: PhantomData }
}
}
impl<'ctx, N: FloatKind<'ctx>> ModelBase<'ctx> for Float<'ctx, N> {
fn llvm_type_impl(&self, _size_t: IntType<'ctx>, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
self.kind.float_type(ctx).into()
} }
fn check_type_impl( fn check_type_impl(
@ -56,7 +65,7 @@ impl<'ctx, N: FloatKind<'ctx>> ModelBase<'ctx> for Float<N> {
return Err(ModelError(format!("Expecting FloatType, but got {ty:?}"))); return Err(ModelError(format!("Expecting FloatType, but got {ty:?}")));
}; };
let expected_ty = self.0.get_float_type(ctx); let expected_ty = self.kind.float_type(ctx);
if ty != expected_ty { if ty != expected_ty {
return Err(ModelError(format!("Expecting {expected_ty:?}, but got {ty:?}"))); return Err(ModelError(format!("Expecting {expected_ty:?}, but got {ty:?}")));
} }
@ -65,7 +74,7 @@ impl<'ctx, N: FloatKind<'ctx>> ModelBase<'ctx> for Float<N> {
} }
} }
impl<'ctx, N: FloatKind<'ctx>> Model<'ctx> for Float<N> { impl<'ctx, N: FloatKind<'ctx>> Model<'ctx> for Float<'ctx, N> {
type Value = FloatValue<'ctx>; type Value = FloatValue<'ctx>;
type Type = FloatType<'ctx>; type Type = FloatType<'ctx>;
} }

View File

@ -35,20 +35,20 @@ struct Arg<'ctx> {
/// If `my_function_name` has not been declared in `ctx.module`, once `.returning()` is called, a function /// If `my_function_name` has not been declared in `ctx.module`, once `.returning()` is called, a function
/// declaration of `my_function_name` is added to `ctx.module`, where the [`FunctionType`] is deduced from /// declaration of `my_function_name` is added to `ctx.module`, where the [`FunctionType`] is deduced from
/// the argument types and returning type. /// the argument types and returning type.
pub struct CallFunction<'ctx, 'a, 'b, 'c, 'd, G: CodeGenerator + ?Sized> { pub struct FnCall<'ctx, 'a, 'b, G: CodeGenerator + ?Sized> {
generator: &'d mut G, generator: &'b mut G,
ctx: &'b CodeGenContext<'ctx, 'a>, ctx: &'b CodeGenContext<'ctx, 'a>,
/// Function name /// Function name
name: &'c str, name: &'b str,
/// Call arguments /// Call arguments
args: Vec<Arg<'ctx>>, args: Vec<Arg<'ctx>>,
/// LLVM function Attributes /// LLVM function Attributes
attrs: Vec<&'static str>, attrs: Vec<&'static str>,
} }
impl<'ctx, 'a, 'b, 'c, 'd, G: CodeGenerator + ?Sized> CallFunction<'ctx, 'a, 'b, 'c, 'd, G> { impl<'ctx, 'a, 'b, G: CodeGenerator + ?Sized> FnCall<'ctx, 'a, 'b, G> {
pub fn begin(generator: &'d mut G, ctx: &'b CodeGenContext<'ctx, 'a>, name: &'c str) -> Self { pub fn begin(generator: &'b mut G, ctx: &'b CodeGenContext<'ctx, 'a>, name: &'b str) -> Self {
CallFunction { generator, ctx, name, args: Vec::new(), attrs: Vec::new() } FnCall { generator, ctx, name, args: Vec::new(), attrs: Vec::new() }
} }
/// Push a list of LLVM function attributes to the function declaration. /// Push a list of LLVM function attributes to the function declaration.
@ -63,7 +63,7 @@ impl<'ctx, 'a, 'b, 'c, 'd, G: CodeGenerator + ?Sized> CallFunction<'ctx, 'a, 'b,
#[must_use] #[must_use]
pub fn arg<M: Model<'ctx>>(mut self, arg: Instance<'ctx, M>) -> Self { pub fn arg<M: Model<'ctx>>(mut self, arg: Instance<'ctx, M>) -> Self {
let arg = Arg { let arg = Arg {
ty: arg.model.get_type(self.generator, self.ctx.ctx).as_basic_type_enum().into(), ty: arg.model.llvm_type(self.generator, self.ctx.ctx).as_basic_type_enum().into(),
val: arg.value.as_basic_value_enum().into(), val: arg.value.as_basic_value_enum().into(),
}; };
self.args.push(arg); self.args.push(arg);
@ -73,7 +73,7 @@ impl<'ctx, 'a, 'b, 'c, 'd, G: CodeGenerator + ?Sized> CallFunction<'ctx, 'a, 'b,
/// Call the function and expect the function to return a value of type of `return_model`. /// Call the function and expect the function to return a value of type of `return_model`.
#[must_use] #[must_use]
pub fn returning<M: Model<'ctx>>(self, name: &str, return_model: M) -> Instance<'ctx, M> { pub fn returning<M: Model<'ctx>>(self, name: &str, return_model: M) -> Instance<'ctx, M> {
let ret_ty = return_model.get_type(self.generator, self.ctx.ctx); let ret_ty = return_model.llvm_type(self.generator, self.ctx.ctx);
let ret = self.call(|tys| ret_ty.fn_type(tys, false), name); let ret = self.call(|tys| ret_ty.fn_type(tys, false), name);
let ret = BasicValueEnum::try_from(ret.as_any_value_enum()).unwrap(); // Must work let ret = BasicValueEnum::try_from(ret.as_any_value_enum()).unwrap(); // Must work

View File

@ -1,4 +1,4 @@
use std::{cmp::Ordering, fmt}; use std::{cmp::Ordering, fmt, marker::PhantomData};
use inkwell::{ use inkwell::{
context::Context, context::Context,
@ -12,7 +12,7 @@ use crate::codegen::{CodeGenContext, CodeGenerator};
use super::*; use super::*;
pub trait IntKind<'ctx>: fmt::Debug + Clone + Copy { pub trait IntKind<'ctx>: fmt::Debug + Clone + Copy {
fn get_int_type(&self, size_t: IntType<'ctx>, ctx: &'ctx Context) -> IntType<'ctx>; fn int_type(&self, size_t: IntType<'ctx>, ctx: &'ctx Context) -> IntType<'ctx>;
} }
#[derive(Debug, Clone, Copy, Default)] #[derive(Debug, Clone, Copy, Default)]
@ -27,31 +27,31 @@ pub struct Int64;
pub struct SizeT; pub struct SizeT;
impl<'ctx> IntKind<'ctx> for Bool { impl<'ctx> IntKind<'ctx> for Bool {
fn get_int_type(&self, _size_t: IntType<'ctx>, ctx: &'ctx Context) -> IntType<'ctx> { fn int_type(&self, _size_t: IntType<'ctx>, ctx: &'ctx Context) -> IntType<'ctx> {
ctx.bool_type() ctx.bool_type()
} }
} }
impl<'ctx> IntKind<'ctx> for Byte { impl<'ctx> IntKind<'ctx> for Byte {
fn get_int_type(&self, _size_t: IntType<'ctx>, ctx: &'ctx Context) -> IntType<'ctx> { fn int_type(&self, _size_t: IntType<'ctx>, ctx: &'ctx Context) -> IntType<'ctx> {
ctx.i8_type() ctx.i8_type()
} }
} }
impl<'ctx> IntKind<'ctx> for Int32 { impl<'ctx> IntKind<'ctx> for Int32 {
fn get_int_type(&self, _size_t: IntType<'ctx>, ctx: &'ctx Context) -> IntType<'ctx> { fn int_type(&self, _size_t: IntType<'ctx>, ctx: &'ctx Context) -> IntType<'ctx> {
ctx.i32_type() ctx.i32_type()
} }
} }
impl<'ctx> IntKind<'ctx> for Int64 { impl<'ctx> IntKind<'ctx> for Int64 {
fn get_int_type(&self, _size_t: IntType<'ctx>, ctx: &'ctx Context) -> IntType<'ctx> { fn int_type(&self, _size_t: IntType<'ctx>, ctx: &'ctx Context) -> IntType<'ctx> {
ctx.i64_type() ctx.i64_type()
} }
} }
impl<'ctx> IntKind<'ctx> for SizeT { impl<'ctx> IntKind<'ctx> for SizeT {
fn get_int_type(&self, size_t: IntType<'ctx>, _ctx: &'ctx Context) -> IntType<'ctx> { fn int_type(&self, size_t: IntType<'ctx>, _ctx: &'ctx Context) -> IntType<'ctx> {
size_t size_t
} }
} }
@ -60,17 +60,20 @@ impl<'ctx> IntKind<'ctx> for SizeT {
pub struct AnyInt<'ctx>(pub IntType<'ctx>); pub struct AnyInt<'ctx>(pub IntType<'ctx>);
impl<'ctx> IntKind<'ctx> for AnyInt<'ctx> { impl<'ctx> IntKind<'ctx> for AnyInt<'ctx> {
fn get_int_type(&self, _size_t: IntType<'ctx>, _ctx: &'ctx Context) -> IntType<'ctx> { fn int_type(&self, _size_t: IntType<'ctx>, _ctx: &'ctx Context) -> IntType<'ctx> {
self.0 self.0
} }
} }
#[derive(Debug, Clone, Copy, Default)] #[derive(Debug, Clone, Copy, Default)]
pub struct Int<N>(pub N); pub struct Int<'ctx, N: IntKind<'ctx>> {
kind: N,
_phantom: PhantomData<&'ctx ()>,
}
impl<'ctx, N: IntKind<'ctx>> ModelBase<'ctx> for Int<N> { impl<'ctx, N: IntKind<'ctx>> ModelBase<'ctx> for Int<'ctx, N> {
fn get_type_impl(&self, size_t: IntType<'ctx>, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> { fn llvm_type_impl(&self, size_t: IntType<'ctx>, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
self.0.get_int_type(size_t, ctx).into() self.kind.int_type(size_t, ctx).into()
} }
fn check_type_impl( fn check_type_impl(
@ -83,7 +86,7 @@ impl<'ctx, N: IntKind<'ctx>> ModelBase<'ctx> for Int<N> {
return Err(ModelError(format!("Expecting IntType, but got {ty:?}"))); return Err(ModelError(format!("Expecting IntType, but got {ty:?}")));
}; };
let exp_ty = self.0.get_int_type(size_t, ctx); let exp_ty = self.kind.int_type(size_t, ctx);
if ty.get_bit_width() != exp_ty.get_bit_width() { if ty.get_bit_width() != exp_ty.get_bit_width() {
return Err(ModelError(format!( return Err(ModelError(format!(
"Expecting IntType to have {} bit(s), but got {} bit(s)", "Expecting IntType to have {} bit(s), but got {} bit(s)",
@ -96,20 +99,25 @@ impl<'ctx, N: IntKind<'ctx>> ModelBase<'ctx> for Int<N> {
} }
} }
impl<'ctx, N: IntKind<'ctx>> Model<'ctx> for Int<N> { impl<'ctx, N: IntKind<'ctx>> Model<'ctx> for Int<'ctx, N> {
type Type = IntType<'ctx>; type Type = IntType<'ctx>;
type Value = IntValue<'ctx>; type Value = IntValue<'ctx>;
} }
impl<'ctx, N: IntKind<'ctx>> Int<N> { impl<'ctx, N: IntKind<'ctx>> Int<'ctx, N> {
pub fn new(kind: N) -> Self {
Int { kind, _phantom: PhantomData }
}
pub fn const_int<G: CodeGenerator + ?Sized>( pub fn const_int<G: CodeGenerator + ?Sized>(
&self, &self,
generator: &mut G, generator: &mut G,
ctx: &'ctx Context, ctx: &'ctx Context,
value: u64, value: u64,
sign_extend: bool,
) -> Instance<'ctx, Self> { ) -> Instance<'ctx, Self> {
let value = self.get_type(generator, ctx).const_int(value, false); let value = self.llvm_type(generator, ctx).const_int(value, sign_extend);
self.believe_value(value) unsafe { self.believe_value(value) }
} }
pub fn const_0<G: CodeGenerator + ?Sized>( pub fn const_0<G: CodeGenerator + ?Sized>(
@ -117,8 +125,8 @@ impl<'ctx, N: IntKind<'ctx>> Int<N> {
generator: &mut G, generator: &mut G,
ctx: &'ctx Context, ctx: &'ctx Context,
) -> Instance<'ctx, Self> { ) -> Instance<'ctx, Self> {
let value = self.get_type(generator, ctx).const_zero(); let value = self.llvm_type(generator, ctx).const_zero();
self.believe_value(value) unsafe { self.believe_value(value) }
} }
pub fn const_1<G: CodeGenerator + ?Sized>( pub fn const_1<G: CodeGenerator + ?Sized>(
@ -126,7 +134,7 @@ impl<'ctx, N: IntKind<'ctx>> Int<N> {
generator: &mut G, generator: &mut G,
ctx: &'ctx Context, ctx: &'ctx Context,
) -> Instance<'ctx, Self> { ) -> Instance<'ctx, Self> {
self.const_int(generator, ctx, 1) self.const_int(generator, ctx, 1, false)
} }
pub fn const_all_ones<G: CodeGenerator + ?Sized>( pub fn const_all_ones<G: CodeGenerator + ?Sized>(
@ -134,8 +142,8 @@ impl<'ctx, N: IntKind<'ctx>> Int<N> {
generator: &mut G, generator: &mut G,
ctx: &'ctx Context, ctx: &'ctx Context,
) -> Instance<'ctx, Self> { ) -> Instance<'ctx, Self> {
let value = self.get_type(generator, ctx).const_all_ones(); let value = self.llvm_type(generator, ctx).const_all_ones();
self.believe_value(value) unsafe { self.believe_value(value) }
} }
pub fn s_extend_or_bit_cast<G: CodeGenerator + ?Sized>( pub fn s_extend_or_bit_cast<G: CodeGenerator + ?Sized>(
@ -146,13 +154,13 @@ impl<'ctx, N: IntKind<'ctx>> Int<N> {
) -> Instance<'ctx, Self> { ) -> Instance<'ctx, Self> {
assert!( assert!(
value.get_type().get_bit_width() value.get_type().get_bit_width()
<= self.0.get_int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width() <= self.kind.int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width()
); );
let value = ctx let value = ctx
.builder .builder
.build_int_s_extend_or_bit_cast(value, self.get_type(generator, ctx.ctx), "") .build_int_s_extend_or_bit_cast(value, self.llvm_type(generator, ctx.ctx), "")
.unwrap(); .unwrap();
self.believe_value(value) unsafe { self.believe_value(value) }
} }
pub fn s_extend<G: CodeGenerator + ?Sized>( pub fn s_extend<G: CodeGenerator + ?Sized>(
@ -163,11 +171,11 @@ impl<'ctx, N: IntKind<'ctx>> Int<N> {
) -> Instance<'ctx, Self> { ) -> Instance<'ctx, Self> {
assert!( assert!(
value.get_type().get_bit_width() value.get_type().get_bit_width()
< self.0.get_int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width() < self.kind.int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width()
); );
let value = let value =
ctx.builder.build_int_s_extend(value, self.get_type(generator, ctx.ctx), "").unwrap(); ctx.builder.build_int_s_extend(value, self.llvm_type(generator, ctx.ctx), "").unwrap();
self.believe_value(value) unsafe { self.believe_value(value) }
} }
pub fn z_extend_or_bit_cast<G: CodeGenerator + ?Sized>( pub fn z_extend_or_bit_cast<G: CodeGenerator + ?Sized>(
@ -178,13 +186,13 @@ impl<'ctx, N: IntKind<'ctx>> Int<N> {
) -> Instance<'ctx, Self> { ) -> Instance<'ctx, Self> {
assert!( assert!(
value.get_type().get_bit_width() value.get_type().get_bit_width()
<= self.0.get_int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width() <= self.kind.int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width()
); );
let value = ctx let value = ctx
.builder .builder
.build_int_z_extend_or_bit_cast(value, self.get_type(generator, ctx.ctx), "") .build_int_z_extend_or_bit_cast(value, self.llvm_type(generator, ctx.ctx), "")
.unwrap(); .unwrap();
self.believe_value(value) unsafe { self.believe_value(value) }
} }
pub fn z_extend<G: CodeGenerator + ?Sized>( pub fn z_extend<G: CodeGenerator + ?Sized>(
@ -195,11 +203,11 @@ impl<'ctx, N: IntKind<'ctx>> Int<N> {
) -> Instance<'ctx, Self> { ) -> Instance<'ctx, Self> {
assert!( assert!(
value.get_type().get_bit_width() value.get_type().get_bit_width()
< self.0.get_int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width() < self.kind.int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width()
); );
let value = let value =
ctx.builder.build_int_z_extend(value, self.get_type(generator, ctx.ctx), "").unwrap(); ctx.builder.build_int_z_extend(value, self.llvm_type(generator, ctx.ctx), "").unwrap();
self.believe_value(value) unsafe { self.believe_value(value) }
} }
pub fn truncate_or_bit_cast<G: CodeGenerator + ?Sized>( pub fn truncate_or_bit_cast<G: CodeGenerator + ?Sized>(
@ -210,13 +218,13 @@ impl<'ctx, N: IntKind<'ctx>> Int<N> {
) -> Instance<'ctx, Self> { ) -> Instance<'ctx, Self> {
assert!( assert!(
value.get_type().get_bit_width() value.get_type().get_bit_width()
>= self.0.get_int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width() >= self.kind.int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width()
); );
let value = ctx let value = ctx
.builder .builder
.build_int_truncate_or_bit_cast(value, self.get_type(generator, ctx.ctx), "") .build_int_truncate_or_bit_cast(value, self.llvm_type(generator, ctx.ctx), "")
.unwrap(); .unwrap();
self.believe_value(value) unsafe { self.believe_value(value) }
} }
pub fn truncate<G: CodeGenerator + ?Sized>( pub fn truncate<G: CodeGenerator + ?Sized>(
@ -227,11 +235,11 @@ impl<'ctx, N: IntKind<'ctx>> Int<N> {
) -> Instance<'ctx, Self> { ) -> Instance<'ctx, Self> {
assert!( assert!(
value.get_type().get_bit_width() value.get_type().get_bit_width()
> self.0.get_int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width() > self.kind.int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width()
); );
let value = let value =
ctx.builder.build_int_truncate(value, self.get_type(generator, ctx.ctx), "").unwrap(); ctx.builder.build_int_truncate(value, self.llvm_type(generator, ctx.ctx), "").unwrap();
self.believe_value(value) unsafe { self.believe_value(value) }
} }
/// `sext` or `trunc` an int to this model's int type. Does nothing if equal bit-widths. /// `sext` or `trunc` an int to this model's int type. Does nothing if equal bit-widths.
@ -243,10 +251,10 @@ impl<'ctx, N: IntKind<'ctx>> Int<N> {
) -> Instance<'ctx, Self> { ) -> Instance<'ctx, Self> {
let their_width = value.get_type().get_bit_width(); let their_width = value.get_type().get_bit_width();
let our_width = let our_width =
self.0.get_int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width(); self.kind.int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width();
match their_width.cmp(&our_width) { match their_width.cmp(&our_width) {
Ordering::Less => self.s_extend(generator, ctx, value), Ordering::Less => self.s_extend(generator, ctx, value),
Ordering::Equal => self.believe_value(value), Ordering::Equal => unsafe { self.believe_value(value) },
Ordering::Greater => self.truncate(generator, ctx, value), Ordering::Greater => self.truncate(generator, ctx, value),
} }
} }
@ -260,43 +268,43 @@ impl<'ctx, N: IntKind<'ctx>> Int<N> {
) -> Instance<'ctx, Self> { ) -> Instance<'ctx, Self> {
let their_width = value.get_type().get_bit_width(); let their_width = value.get_type().get_bit_width();
let our_width = let our_width =
self.0.get_int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width(); self.kind.int_type(generator.get_size_type(ctx.ctx), ctx.ctx).get_bit_width();
match their_width.cmp(&our_width) { match their_width.cmp(&our_width) {
Ordering::Less => self.z_extend(generator, ctx, value), Ordering::Less => self.z_extend(generator, ctx, value),
Ordering::Equal => self.believe_value(value), Ordering::Equal => unsafe { self.believe_value(value) },
Ordering::Greater => self.truncate(generator, ctx, value), Ordering::Greater => self.truncate(generator, ctx, value),
} }
} }
} }
impl Int<Bool> { impl<'ctx> Int<'ctx, Bool> {
#[must_use] #[must_use]
pub fn const_false<'ctx, G: CodeGenerator + ?Sized>( pub fn const_false<G: CodeGenerator + ?Sized>(
&self, &self,
generator: &mut G, generator: &mut G,
ctx: &'ctx Context, ctx: &'ctx Context,
) -> Instance<'ctx, Self> { ) -> Instance<'ctx, Self> {
self.const_int(generator, ctx, 0) self.const_int(generator, ctx, 0, false)
} }
#[must_use] #[must_use]
pub fn const_true<'ctx, G: CodeGenerator + ?Sized>( pub fn const_true<G: CodeGenerator + ?Sized>(
&self, &self,
generator: &mut G, generator: &mut G,
ctx: &'ctx Context, ctx: &'ctx Context,
) -> Instance<'ctx, Self> { ) -> Instance<'ctx, Self> {
self.const_int(generator, ctx, 1) self.const_int(generator, ctx, 1, false)
} }
} }
impl<'ctx, N: IntKind<'ctx>> Instance<'ctx, Int<N>> { impl<'ctx, N: IntKind<'ctx>> Instance<'ctx, Int<'ctx, N>> {
pub fn s_extend_or_bit_cast<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>( pub fn s_extend_or_bit_cast<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>(
&self, &self,
generator: &mut G, generator: &mut G,
ctx: &CodeGenContext<'ctx, '_>, ctx: &CodeGenContext<'ctx, '_>,
to_int_kind: NewN, to_int_kind: NewN,
) -> Instance<'ctx, Int<NewN>> { ) -> Instance<'ctx, Int<'ctx, NewN>> {
Int(to_int_kind).s_extend_or_bit_cast(generator, ctx, self.value) Int::new(to_int_kind).s_extend_or_bit_cast(generator, ctx, self.value)
} }
pub fn s_extend<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>( pub fn s_extend<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>(
@ -304,8 +312,8 @@ impl<'ctx, N: IntKind<'ctx>> Instance<'ctx, Int<N>> {
generator: &mut G, generator: &mut G,
ctx: &CodeGenContext<'ctx, '_>, ctx: &CodeGenContext<'ctx, '_>,
to_int_kind: NewN, to_int_kind: NewN,
) -> Instance<'ctx, Int<NewN>> { ) -> Instance<'ctx, Int<'ctx, NewN>> {
Int(to_int_kind).s_extend(generator, ctx, self.value) Int::new(to_int_kind).s_extend(generator, ctx, self.value)
} }
pub fn z_extend_or_bit_cast<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>( pub fn z_extend_or_bit_cast<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>(
@ -313,8 +321,8 @@ impl<'ctx, N: IntKind<'ctx>> Instance<'ctx, Int<N>> {
generator: &mut G, generator: &mut G,
ctx: &CodeGenContext<'ctx, '_>, ctx: &CodeGenContext<'ctx, '_>,
to_int_kind: NewN, to_int_kind: NewN,
) -> Instance<'ctx, Int<NewN>> { ) -> Instance<'ctx, Int<'ctx, NewN>> {
Int(to_int_kind).z_extend_or_bit_cast(generator, ctx, self.value) Int::new(to_int_kind).z_extend_or_bit_cast(generator, ctx, self.value)
} }
pub fn z_extend<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>( pub fn z_extend<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>(
@ -322,8 +330,8 @@ impl<'ctx, N: IntKind<'ctx>> Instance<'ctx, Int<N>> {
generator: &mut G, generator: &mut G,
ctx: &CodeGenContext<'ctx, '_>, ctx: &CodeGenContext<'ctx, '_>,
to_int_kind: NewN, to_int_kind: NewN,
) -> Instance<'ctx, Int<NewN>> { ) -> Instance<'ctx, Int<'ctx, NewN>> {
Int(to_int_kind).z_extend(generator, ctx, self.value) Int::new(to_int_kind).z_extend(generator, ctx, self.value)
} }
pub fn truncate_or_bit_cast<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>( pub fn truncate_or_bit_cast<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>(
@ -331,8 +339,8 @@ impl<'ctx, N: IntKind<'ctx>> Instance<'ctx, Int<N>> {
generator: &mut G, generator: &mut G,
ctx: &CodeGenContext<'ctx, '_>, ctx: &CodeGenContext<'ctx, '_>,
to_int_kind: NewN, to_int_kind: NewN,
) -> Instance<'ctx, Int<NewN>> { ) -> Instance<'ctx, Int<'ctx, NewN>> {
Int(to_int_kind).truncate_or_bit_cast(generator, ctx, self.value) Int::new(to_int_kind).truncate_or_bit_cast(generator, ctx, self.value)
} }
pub fn truncate<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>( pub fn truncate<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>(
@ -340,8 +348,8 @@ impl<'ctx, N: IntKind<'ctx>> Instance<'ctx, Int<N>> {
generator: &mut G, generator: &mut G,
ctx: &CodeGenContext<'ctx, '_>, ctx: &CodeGenContext<'ctx, '_>,
to_int_kind: NewN, to_int_kind: NewN,
) -> Instance<'ctx, Int<NewN>> { ) -> Instance<'ctx, Int<'ctx, NewN>> {
Int(to_int_kind).truncate(generator, ctx, self.value) Int::new(to_int_kind).truncate(generator, ctx, self.value)
} }
pub fn s_extend_or_truncate<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>( pub fn s_extend_or_truncate<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>(
@ -349,8 +357,8 @@ impl<'ctx, N: IntKind<'ctx>> Instance<'ctx, Int<N>> {
generator: &mut G, generator: &mut G,
ctx: &CodeGenContext<'ctx, '_>, ctx: &CodeGenContext<'ctx, '_>,
to_int_kind: NewN, to_int_kind: NewN,
) -> Instance<'ctx, Int<NewN>> { ) -> Instance<'ctx, Int<'ctx, NewN>> {
Int(to_int_kind).s_extend_or_truncate(generator, ctx, self.value) Int::new(to_int_kind).s_extend_or_truncate(generator, ctx, self.value)
} }
pub fn z_extend_or_truncate<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>( pub fn z_extend_or_truncate<NewN: IntKind<'ctx>, G: CodeGenerator + ?Sized>(
@ -358,26 +366,26 @@ impl<'ctx, N: IntKind<'ctx>> Instance<'ctx, Int<N>> {
generator: &mut G, generator: &mut G,
ctx: &CodeGenContext<'ctx, '_>, ctx: &CodeGenContext<'ctx, '_>,
to_int_kind: NewN, to_int_kind: NewN,
) -> Instance<'ctx, Int<NewN>> { ) -> Instance<'ctx, Int<'ctx, NewN>> {
Int(to_int_kind).z_extend_or_truncate(generator, ctx, self.value) Int::new(to_int_kind).z_extend_or_truncate(generator, ctx, self.value)
} }
#[must_use] #[must_use]
pub fn add(&self, ctx: &CodeGenContext<'ctx, '_>, other: Self) -> Self { pub fn add(&self, ctx: &CodeGenContext<'ctx, '_>, other: Self) -> Self {
let value = ctx.builder.build_int_add(self.value, other.value, "").unwrap(); let value = ctx.builder.build_int_add(self.value, other.value, "").unwrap();
self.model.believe_value(value) unsafe { self.model.believe_value(value) }
} }
#[must_use] #[must_use]
pub fn sub(&self, ctx: &CodeGenContext<'ctx, '_>, other: Self) -> Self { pub fn sub(&self, ctx: &CodeGenContext<'ctx, '_>, other: Self) -> Self {
let value = ctx.builder.build_int_sub(self.value, other.value, "").unwrap(); let value = ctx.builder.build_int_sub(self.value, other.value, "").unwrap();
self.model.believe_value(value) unsafe { self.model.believe_value(value) }
} }
#[must_use] #[must_use]
pub fn mul(&self, ctx: &CodeGenContext<'ctx, '_>, other: Self) -> Self { pub fn mul(&self, ctx: &CodeGenContext<'ctx, '_>, other: Self) -> Self {
let value = ctx.builder.build_int_mul(self.value, other.value, "").unwrap(); let value = ctx.builder.build_int_mul(self.value, other.value, "").unwrap();
self.model.believe_value(value) unsafe { self.model.believe_value(value) }
} }
pub fn compare( pub fn compare(
@ -385,8 +393,8 @@ impl<'ctx, N: IntKind<'ctx>> Instance<'ctx, Int<N>> {
ctx: &CodeGenContext<'ctx, '_>, ctx: &CodeGenContext<'ctx, '_>,
op: IntPredicate, op: IntPredicate,
other: Self, other: Self,
) -> Instance<'ctx, Int<Bool>> { ) -> Instance<'ctx, Int<'ctx, Bool>> {
let value = ctx.builder.build_int_compare(op, self.value, other.value, "").unwrap(); let value = ctx.builder.build_int_compare(op, self.value, other.value, "").unwrap();
Int(Bool).believe_value(value) unsafe { Int::new(Bool).believe_value(value) }
} }
} }

View File

@ -15,22 +15,32 @@ use super::*;
/// ///
// TODO: LLVM 15: `Item` is a Rust type-hint for the LLVM type of value the `.store()/.load()` family // TODO: LLVM 15: `Item` is a Rust type-hint for the LLVM type of value the `.store()/.load()` family
// of functions return. If a truly opaque pointer is needed, tell the programmer to use `OpaquePtr`. // of functions return. If a truly opaque pointer is needed, tell the programmer to use `OpaquePtr`.
//
// NOTE: Do not put `Item: ModelBase<'ctx>`. See the LLVM 15 note above.
#[derive(Debug, Clone, Copy, Default)] #[derive(Debug, Clone, Copy, Default)]
pub struct Ptr<Item>(pub Item); pub struct Ptr<Item> {
pub item: Item,
}
/// An opaque pointer. Like [`Ptr`] but without any Rust type-hints about its element type. /// An opaque pointer. Like [`Ptr`] but without any Rust type-hints about its element type.
/// ///
/// `.load()/.store()` is not available for [`Instance`]s of opaque pointers. /// `.load()/.store()` is not available for [`Instance`]s of opaque pointers.
pub type OpaquePtr = Ptr<()>; pub type OpaquePtr = Ptr<()>;
impl<Item> Ptr<Item> {
pub fn new(item: Item) -> Self {
Ptr { item }
}
}
// TODO: LLVM 15: `Item: ModelBase<'ctx>` don't even need to be a model anymore. It will only be // TODO: LLVM 15: `Item: ModelBase<'ctx>` don't even need to be a model anymore. It will only be
// a type-hint for the `.load()/.store()` functions for the `pointee_ty`. // a type-hint for the `.load()/.store()` functions for the `pointee_ty`.
// //
// See https://thedan64.github.io/inkwell/inkwell/builder/struct.Builder.html#method.build_load. // See https://thedan64.github.io/inkwell/inkwell/builder/struct.Builder.html#method.build_load.
impl<'ctx, Item: ModelBase<'ctx>> ModelBase<'ctx> for Ptr<Item> { impl<'ctx, Item: ModelBase<'ctx>> ModelBase<'ctx> for Ptr<Item> {
fn get_type_impl(&self, size_t: IntType<'ctx>, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> { fn llvm_type_impl(&self, size_t: IntType<'ctx>, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
// TODO: LLVM 15: ctx.ptr_type(AddressSpace::default()) // TODO: LLVM 15: ctx.ptr_type(AddressSpace::default())
let item = self.0.get_type_impl(size_t, ctx); let item = self.item.llvm_type_impl(size_t, ctx);
item.ptr_type(AddressSpace::default()).into() item.ptr_type(AddressSpace::default()).into()
} }
@ -53,7 +63,7 @@ impl<'ctx, Item: ModelBase<'ctx>> ModelBase<'ctx> for Ptr<Item> {
// TODO: inkwell `get_element_type()` will be deprecated. // TODO: inkwell `get_element_type()` will be deprecated.
// Remove the check for `get_element_type()` when the time comes. // Remove the check for `get_element_type()` when the time comes.
self.0 self.item
.check_type_impl(size_t, ctx, elem_ty) .check_type_impl(size_t, ctx, elem_ty)
.map_err(|err| err.under_context("a PointerType"))?; .map_err(|err| err.under_context("a PointerType"))?;
@ -74,8 +84,8 @@ impl<'ctx, Item: Model<'ctx>> Ptr<Item> {
ctx: &'ctx Context, ctx: &'ctx Context,
) -> Instance<'ctx, Ptr<Item>> { ) -> Instance<'ctx, Ptr<Item>> {
// TODO: LLVM 15: Write in an impl where `Item` does not have to be `Model<'ctx>`. // TODO: LLVM 15: Write in an impl where `Item` does not have to be `Model<'ctx>`.
let ptr = self.get_type(generator, ctx).const_null(); let ptr = self.llvm_type(generator, ctx).const_null();
self.believe_value(ptr) unsafe { self.believe_value(ptr) }
} }
/// Cast a pointer into this model with [`inkwell::builder::Builder::build_pointer_cast`] /// Cast a pointer into this model with [`inkwell::builder::Builder::build_pointer_cast`]
@ -90,9 +100,9 @@ impl<'ctx, Item: Model<'ctx>> Ptr<Item> {
// ``` // ```
// return self.believe_value(ptr); // return self.believe_value(ptr);
// ``` // ```
let t = self.get_type(generator, ctx.ctx); let t = self.llvm_type(generator, ctx.ctx);
let ptr = ctx.builder.build_pointer_cast(ptr, t, "").unwrap(); let ptr = ctx.builder.build_pointer_cast(ptr, t, "").unwrap();
self.believe_value(ptr) unsafe { self.believe_value(ptr) }
} }
} }
@ -105,7 +115,7 @@ impl<'ctx, Item: Model<'ctx>> Instance<'ctx, Ptr<Item>> {
offset: IntValue<'ctx>, offset: IntValue<'ctx>,
) -> Instance<'ctx, Ptr<Item>> { ) -> Instance<'ctx, Ptr<Item>> {
let p = unsafe { ctx.builder.build_in_bounds_gep(self.value, &[offset], "").unwrap() }; let p = unsafe { ctx.builder.build_in_bounds_gep(self.value, &[offset], "").unwrap() };
self.model.believe_value(p) unsafe { self.model.believe_value(p) }
} }
/// Offset the pointer by [`inkwell::builder::Builder::build_in_bounds_gep`] by a constant offset. /// Offset the pointer by [`inkwell::builder::Builder::build_in_bounds_gep`] by a constant offset.
@ -113,9 +123,9 @@ impl<'ctx, Item: Model<'ctx>> Instance<'ctx, Ptr<Item>> {
pub fn offset_const( pub fn offset_const(
&self, &self,
ctx: &CodeGenContext<'ctx, '_>, ctx: &CodeGenContext<'ctx, '_>,
offset: u64, offset: i64,
) -> Instance<'ctx, Ptr<Item>> { ) -> Instance<'ctx, Ptr<Item>> {
let offset = ctx.ctx.i32_type().const_int(offset, false); let offset = ctx.ctx.i64_type().const_int(offset as u64, true);
self.offset(ctx, offset) self.offset(ctx, offset)
} }
@ -131,7 +141,7 @@ impl<'ctx, Item: Model<'ctx>> Instance<'ctx, Ptr<Item>> {
pub fn set_index_const( pub fn set_index_const(
&self, &self,
ctx: &CodeGenContext<'ctx, '_>, ctx: &CodeGenContext<'ctx, '_>,
index: u64, index: i64,
value: Instance<'ctx, Item>, value: Instance<'ctx, Item>,
) { ) {
self.offset_const(ctx, index).store(ctx, value); self.offset_const(ctx, index).store(ctx, value);
@ -150,7 +160,7 @@ impl<'ctx, Item: Model<'ctx>> Instance<'ctx, Ptr<Item>> {
&self, &self,
generator: &mut G, generator: &mut G,
ctx: &CodeGenContext<'ctx, '_>, ctx: &CodeGenContext<'ctx, '_>,
index: u64, index: i64,
) -> Instance<'ctx, Item> { ) -> Instance<'ctx, Item> {
self.offset_const(ctx, index).load(generator, ctx) self.offset_const(ctx, index).load(generator, ctx)
} }
@ -162,7 +172,7 @@ impl<'ctx, Item: Model<'ctx>> Instance<'ctx, Ptr<Item>> {
ctx: &CodeGenContext<'ctx, '_>, ctx: &CodeGenContext<'ctx, '_>,
) -> Instance<'ctx, Item> { ) -> Instance<'ctx, Item> {
let value = ctx.builder.build_load(self.value, "").unwrap(); let value = ctx.builder.build_load(self.value, "").unwrap();
self.model.0.check_value(generator, ctx.ctx, value).unwrap() // If unwrap() panics, there is a logic error. self.model.item.check_value(generator, ctx.ctx, value).unwrap() // If unwrap() panics, there is a logic error.
} }
/// Store a value with [`inkwell::builder::Builder::build_store`]. /// Store a value with [`inkwell::builder::Builder::build_store`].
@ -178,19 +188,19 @@ impl<'ctx, Item: Model<'ctx>> Instance<'ctx, Ptr<Item>> {
new_item: NewItem, new_item: NewItem,
) -> Instance<'ctx, Ptr<NewItem>> { ) -> Instance<'ctx, Ptr<NewItem>> {
// TODO: LLVM 15: Write in an impl where `Item` does not have to be `Model<'ctx>`. // TODO: LLVM 15: Write in an impl where `Item` does not have to be `Model<'ctx>`.
Ptr(new_item).pointer_cast(generator, ctx, self.value) Ptr::new(new_item).pointer_cast(generator, ctx, self.value)
} }
/// Check if the pointer is null with [`inkwell::builder::Builder::build_is_null`]. /// Check if the pointer is null with [`inkwell::builder::Builder::build_is_null`].
pub fn is_null(&self, ctx: &CodeGenContext<'ctx, '_>) -> Instance<'ctx, Int<Bool>> { pub fn is_null(&self, ctx: &CodeGenContext<'ctx, '_>) -> Instance<'ctx, Int<'ctx, Bool>> {
let value = ctx.builder.build_is_null(self.value, "").unwrap(); let value = ctx.builder.build_is_null(self.value, "").unwrap();
Int(Bool).believe_value(value) unsafe { Int::new(Bool).believe_value(value) }
} }
/// Check if the pointer is not null with [`inkwell::builder::Builder::build_is_not_null`]. /// Check if the pointer is not null with [`inkwell::builder::Builder::build_is_not_null`].
pub fn is_not_null(&self, ctx: &CodeGenContext<'ctx, '_>) -> Instance<'ctx, Int<Bool>> { pub fn is_not_null(&self, ctx: &CodeGenContext<'ctx, '_>) -> Instance<'ctx, Int<'ctx, Bool>> {
let value = ctx.builder.build_is_not_null(self.value, "").unwrap(); let value = ctx.builder.build_is_not_null(self.value, "").unwrap();
Int(Bool).believe_value(value) unsafe { Int::new(Bool).believe_value(value) }
} }
/// `memcpy` from another pointer. /// `memcpy` from another pointer.
@ -202,9 +212,9 @@ impl<'ctx, Item: Model<'ctx>> Instance<'ctx, Ptr<Item>> {
num_items: IntValue<'ctx>, num_items: IntValue<'ctx>,
) { ) {
// Force extend `num_items` and `itemsize` to `i64` so their types would match. // Force extend `num_items` and `itemsize` to `i64` so their types would match.
let itemsize = self.model.sizeof(generator, ctx.ctx); let itemsize = self.model.size_of(generator, ctx.ctx);
let itemsize = Int(Int64).z_extend_or_truncate(generator, ctx, itemsize); let itemsize = Int::new(Int64).z_extend_or_truncate(generator, ctx, itemsize);
let num_items = Int(Int64).z_extend_or_truncate(generator, ctx, num_items); let num_items = Int::new(Int64).z_extend_or_truncate(generator, ctx, num_items);
let totalsize = itemsize.mul(ctx, num_items); let totalsize = itemsize.mul(ctx, num_items);
let is_volatile = ctx.ctx.bool_type().const_zero(); // is_volatile = false let is_volatile = ctx.ctx.bool_type().const_zero(); // is_volatile = false

View File

@ -72,29 +72,21 @@ pub trait StructKind<'ctx>: fmt::Debug + Clone + Copy {
/// Get the LLVM [`StructType`] of this [`StructKind`]. /// Get the LLVM [`StructType`] of this [`StructKind`].
fn get_struct_type(&self, size_t: IntType<'ctx>, ctx: &'ctx Context) -> StructType<'ctx> { fn get_struct_type(&self, size_t: IntType<'ctx>, ctx: &'ctx Context) -> StructType<'ctx> {
let entries = self.entries(); let entries = self.entries();
let entries = entries.into_iter().map(|t| t.model.get_type_impl(size_t, ctx)).collect_vec(); let entries =
entries.into_iter().map(|t| t.model.llvm_type_impl(size_t, ctx)).collect_vec();
ctx.struct_type(&entries, false) ctx.struct_type(&entries, false)
} }
} }
#[derive(Debug, Clone, Copy, Default)] #[derive(Debug, Clone, Copy, Default)]
pub struct Struct<S>(pub S); pub struct Struct<'ctx, S: StructKind<'ctx>> {
pub kind: S,
impl<'ctx, S: StructKind<'ctx>> Struct<S> { _phantom: PhantomData<&'ctx ()>,
pub fn const_struct<G: CodeGenerator + ?Sized>(
&self,
generator: &mut G,
ctx: &'ctx Context,
fields: &[BasicValueEnum<'ctx>],
) -> Instance<'ctx, Self> {
let val = ctx.const_struct(fields, false);
self.check_value(generator, ctx, val).unwrap()
}
} }
impl<'ctx, S: StructKind<'ctx>> ModelBase<'ctx> for Struct<S> { impl<'ctx, S: StructKind<'ctx>> ModelBase<'ctx> for Struct<'ctx, S> {
fn get_type_impl(&self, size_t: IntType<'ctx>, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> { fn llvm_type_impl(&self, size_t: IntType<'ctx>, ctx: &'ctx Context) -> BasicTypeEnum<'ctx> {
self.0.get_struct_type(size_t, ctx).as_basic_type_enum() self.kind.get_struct_type(size_t, ctx).as_basic_type_enum()
} }
fn check_type_impl( fn check_type_impl(
@ -107,7 +99,7 @@ impl<'ctx, S: StructKind<'ctx>> ModelBase<'ctx> for Struct<S> {
return Err(ModelError(format!("Expecting StructType, but got {ty:?}"))); return Err(ModelError(format!("Expecting StructType, but got {ty:?}")));
}; };
let entries = self.0.entries(); let entries = self.kind.entries();
let field_types = ty.get_field_types(); let field_types = ty.get_field_types();
// Check the number of fields. // Check the number of fields.
@ -131,12 +123,28 @@ impl<'ctx, S: StructKind<'ctx>> ModelBase<'ctx> for Struct<S> {
} }
} }
impl<'ctx, S: StructKind<'ctx>> Model<'ctx> for Struct<S> { impl<'ctx, S: StructKind<'ctx>> Model<'ctx> for Struct<'ctx, S> {
type Type = StructType<'ctx>; type Type = StructType<'ctx>;
type Value = StructValue<'ctx>; type Value = StructValue<'ctx>;
} }
impl<'ctx, S: StructKind<'ctx>> Instance<'ctx, Struct<S>> { impl<'ctx, S: StructKind<'ctx>> Struct<'ctx, S> {
pub fn new(kind: S) -> Self {
Struct { kind, _phantom: PhantomData }
}
pub fn const_struct<G: CodeGenerator + ?Sized>(
&self,
generator: &mut G,
ctx: &'ctx Context,
fields: &[BasicValueEnum<'ctx>],
) -> Instance<'ctx, Self> {
let val = ctx.const_struct(fields, false);
self.check_value(generator, ctx, val).unwrap()
}
}
impl<'ctx, S: StructKind<'ctx>> Instance<'ctx, Struct<'ctx, S>> {
/// Get a field with [`StructValue::get_field_at_index`]. /// Get a field with [`StructValue::get_field_at_index`].
pub fn get_field<G: CodeGenerator + ?Sized, M, GetField>( pub fn get_field<G: CodeGenerator + ?Sized, M, GetField>(
&self, &self,
@ -148,13 +156,13 @@ impl<'ctx, S: StructKind<'ctx>> Instance<'ctx, Struct<S>> {
M: Model<'ctx>, M: Model<'ctx>,
GetField: FnOnce(S::Fields) -> Field<M>, GetField: FnOnce(S::Fields) -> Field<M>,
{ {
let field = get_field(self.model.0.fields()); let field = get_field(self.model.kind.fields());
let val = self.value.get_field_at_index(field.gep_index).unwrap(); let val = self.value.get_field_at_index(field.gep_index).unwrap();
field.model.check_value(generator, ctx, val).unwrap() field.model.check_value(generator, ctx, val).unwrap()
} }
} }
impl<'ctx, S: StructKind<'ctx>> Instance<'ctx, Ptr<Struct<S>>> { impl<'ctx, S: StructKind<'ctx>> Instance<'ctx, Ptr<Struct<'ctx, S>>> {
/// Get a pointer to a field with [`Builder::build_in_bounds_gep`]. /// Get a pointer to a field with [`Builder::build_in_bounds_gep`].
pub fn gep<M, GetField>( pub fn gep<M, GetField>(
&self, &self,
@ -165,7 +173,7 @@ impl<'ctx, S: StructKind<'ctx>> Instance<'ctx, Ptr<Struct<S>>> {
M: Model<'ctx>, M: Model<'ctx>,
GetField: FnOnce(S::Fields) -> Field<M>, GetField: FnOnce(S::Fields) -> Field<M>,
{ {
let field = get_field(self.model.0 .0.fields()); let field = get_field(self.model.item.kind.fields());
let llvm_i32 = ctx.ctx.i32_type(); let llvm_i32 = ctx.ctx.i32_type();
let ptr = unsafe { let ptr = unsafe {
@ -178,7 +186,7 @@ impl<'ctx, S: StructKind<'ctx>> Instance<'ctx, Ptr<Struct<S>>> {
.unwrap() .unwrap()
}; };
Ptr(field.model).believe_value(ptr) unsafe { Ptr::new(field.model).believe_value(ptr) }
} }
/// Convenience function equivalent to `.gep(...).load(...)`. /// Convenience function equivalent to `.gep(...).load(...)`.
@ -214,19 +222,19 @@ impl<'ctx, S: StructKind<'ctx>> Instance<'ctx, Ptr<Struct<S>>> {
// Example: NDArray. // Example: NDArray.
// //
// Compared to List, it has no generic models. // Compared to List, it has no generic models.
pub struct NDArrayFields { pub struct NDArrayFields<'ctx> {
data: Field<Ptr<Int<Byte>>>, data: Field<Ptr<Int<'ctx, Byte>>>,
itemsize: Field<Int<SizeT>>, itemsize: Field<Int<'ctx, SizeT>>,
ndims: Field<Int<SizeT>>, ndims: Field<Int<'ctx, SizeT>>,
shape: Field<Ptr<Int<SizeT>>>, shape: Field<Ptr<Int<'ctx, SizeT>>>,
strides: Field<Ptr<Int<SizeT>>>, strides: Field<Ptr<Int<'ctx, SizeT>>>,
} }
#[derive(Debug, Clone, Copy, Default)] #[derive(Debug, Clone, Copy, Default)]
struct NDArray; struct NDArray;
impl<'ctx> StructKind<'ctx> for NDArray { impl<'ctx> StructKind<'ctx> for NDArray {
type Fields = NDArrayFields; type Fields = NDArrayFields<'ctx>;
fn iter_fields(&self, mapper: &mut FieldMapper<'ctx>) -> Self::Fields { fn iter_fields(&self, mapper: &mut FieldMapper<'ctx>) -> Self::Fields {
NDArrayFields { NDArrayFields {
@ -244,7 +252,7 @@ impl<'ctx> StructKind<'ctx> for NDArray {
// Compared to NDArray, it has generic models. // Compared to NDArray, it has generic models.
pub struct ListFields<'ctx, Item: Model<'ctx>> { pub struct ListFields<'ctx, Item: Model<'ctx>> {
items: Field<Ptr<Item>>, items: Field<Ptr<Item>>,
len: Field<Int<SizeT>>, len: Field<Int<'ctx, SizeT>>,
_phantom: PhantomData<&'ctx ()>, _phantom: PhantomData<&'ctx ()>,
} }
@ -259,7 +267,7 @@ impl<'ctx, Item: Model<'ctx> + 'ctx> StructKind<'ctx> for List<'ctx, Item> {
fn iter_fields(&self, mapper: &mut FieldMapper<'ctx>) -> Self::Fields { fn iter_fields(&self, mapper: &mut FieldMapper<'ctx>) -> Self::Fields {
ListFields { ListFields {
items: mapper.add("items", Ptr(self.item)), items: mapper.add("items", Ptr::new(self.item)),
len: mapper.add_auto("len"), len: mapper.add_auto("len"),
_phantom: PhantomData, _phantom: PhantomData,
} }