forked from M-Labs/nac3
1
0
Fork 0

fixup! core/model: introduce models

general array
This commit is contained in:
lyken 2024-08-22 20:56:25 +08:00
parent be4b04dbb3
commit 8b0305ab6b
No known key found for this signature in database
GPG Key ID: 3BD5FC6AC8325DD8
2 changed files with 90 additions and 20 deletions

View File

@ -1,28 +1,54 @@
use std::fmt;
use inkwell::{ use inkwell::{
context::Context, context::Context,
types::{ArrayType, BasicType, BasicTypeEnum}, types::{ArrayType, BasicType, BasicTypeEnum},
values::ArrayValue, values::{ArrayValue, IntValue},
}; };
use crate::codegen::{CodeGenContext, CodeGenerator}; use crate::codegen::{CodeGenContext, CodeGenerator};
use super::*; use super::*;
/// A Model for an [`ArrayType`]. pub trait LenKind: fmt::Debug + Clone + Copy {
fn get_length(&self) -> u32;
}
/// A statically known length.
#[derive(Debug, Clone, Copy, Default)]
pub struct Len<const N: u32>;
/// A dynamically known length.
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct Array<Item> { pub struct AnyLen(pub u32);
impl<const N: u32> LenKind for Len<N> {
fn get_length(&self) -> u32 {
N
}
}
impl LenKind for AnyLen {
fn get_length(&self) -> u32 {
self.0
}
}
/// A Model for an [`ArrayType`].
#[derive(Debug, Clone, Copy, Default)]
pub struct Array<Len, Item> {
/// Length of this array. /// Length of this array.
pub len: u32, pub len: Len,
/// [`Model`] of an array item. /// [`Model`] of an array item.
pub item: Item, pub item: Item,
} }
impl<'ctx, Element: Model<'ctx>> Model<'ctx> for Array<Element> { impl<'ctx, Len: LenKind, Item: Model<'ctx>> Model<'ctx> for Array<Len, Item> {
type Value = ArrayValue<'ctx>; type Value = ArrayValue<'ctx>;
type Type = ArrayType<'ctx>; type Type = ArrayType<'ctx>;
fn get_type<G: CodeGenerator + ?Sized>(&self, generator: &G, ctx: &'ctx Context) -> Self::Type { fn get_type<G: CodeGenerator + ?Sized>(&self, generator: &G, ctx: &'ctx Context) -> Self::Type {
self.item.get_type(generator, ctx).array_type(self.len) self.item.get_type(generator, ctx).array_type(self.len.get_length())
} }
fn check_type<T: BasicType<'ctx>, G: CodeGenerator + ?Sized>( fn check_type<T: BasicType<'ctx>, G: CodeGenerator + ?Sized>(
@ -36,11 +62,11 @@ impl<'ctx, Element: Model<'ctx>> Model<'ctx> for Array<Element> {
return Err(ModelError(format!("Expecting ArrayType, but got {ty:?}"))); return Err(ModelError(format!("Expecting ArrayType, but got {ty:?}")));
}; };
if ty.len() != self.len { if ty.len() != self.len.get_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 self.len.get_length()
))); )));
} }
@ -52,21 +78,63 @@ impl<'ctx, Element: Model<'ctx>> Model<'ctx> for Array<Element> {
} }
} }
impl<'ctx, Element: Model<'ctx>> Instance<'ctx, Ptr<Array<Element>>> { impl<'ctx, Len: LenKind, Item: Model<'ctx>> Instance<'ctx, Ptr<Array<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 at<G: CodeGenerator + ?Sized>( pub fn gep(
&self,
ctx: &CodeGenContext<'ctx, '_>,
i: IntValue<'ctx>,
) -> Instance<'ctx, Ptr<Item>> {
let zero = ctx.ctx.i32_type().const_zero();
let ptr = unsafe { ctx.builder.build_in_bounds_gep(self.value, &[zero, i], "").unwrap() };
Ptr(self.model.0.item).believe_value(ptr)
}
/// Like `gep` but `i` is a constant.
pub fn gep_const(&self, ctx: &CodeGenContext<'ctx, '_>, i: u64) -> Instance<'ctx, Ptr<Item>> {
assert!(
i < u64::from(self.model.0.len.get_length()),
"Index {i} is out of bounds. Array length = {}",
self.model.0.len.get_length()
);
let i = ctx.ctx.i32_type().const_int(i, false);
self.gep(ctx, i)
}
/// Convenience function equivalent to `.gep(...).load(...)`.
pub fn get<G: CodeGenerator + ?Sized>(
&self, &self,
generator: &mut G, generator: &mut G,
ctx: &CodeGenContext<'ctx, '_>, ctx: &CodeGenContext<'ctx, '_>,
i: u32, i: IntValue<'ctx>,
name: &str, ) -> Instance<'ctx, Item> {
) -> Instance<'ctx, Ptr<Element>> { self.gep(ctx, i).load(generator, ctx)
assert!(i < self.model.0.len); }
let zero = ctx.ctx.i32_type().const_zero(); /// Like `get` but `i` is a constant.
let i = ctx.ctx.i32_type().const_int(u64::from(i), false); pub fn get_const<G: CodeGenerator + ?Sized>(
let ptr = unsafe { ctx.builder.build_in_bounds_gep(self.value, &[zero, i], name).unwrap() }; &self,
generator: &mut G,
ctx: &CodeGenContext<'ctx, '_>,
i: u64,
) -> Instance<'ctx, Item> {
self.gep_const(ctx, i).load(generator, ctx)
}
Ptr(self.model.0.item).check_value(generator, ctx.ctx, ptr).unwrap() /// Convenience function equivalent to `.gep(...).store(...)`.
pub fn set(
&self,
ctx: &CodeGenContext<'ctx, '_>,
i: IntValue<'ctx>,
value: Instance<'ctx, Item>,
) {
self.gep(ctx, i).store(ctx, value);
}
/// Like `set` but `i` is a constant.
pub fn set_const(&self, ctx: &CodeGenContext<'ctx, '_>, i: u64, value: Instance<'ctx, Item>) {
self.gep_const(ctx, i).store(ctx, value);
} }
} }

View File

@ -117,7 +117,7 @@ pub trait Model<'ctx>: fmt::Debug + Clone + Copy {
generator: &mut G, generator: &mut G,
ctx: &'ctx Context, ctx: &'ctx Context,
values: &[Instance<'ctx, Self>], values: &[Instance<'ctx, Self>],
) -> Instance<'ctx, Array<Self>> { ) -> Instance<'ctx, Array<AnyLen, Self>> {
macro_rules! make { macro_rules! make {
($t:expr, $into_value:expr) => { ($t:expr, $into_value:expr) => {
$t.const_array( $t.const_array(
@ -138,7 +138,9 @@ pub trait Model<'ctx>: fmt::Debug + Clone + Copy {
BasicTypeEnum::VectorType(t) => make!(t, BasicValueEnum::into_vector_value), BasicTypeEnum::VectorType(t) => make!(t, BasicValueEnum::into_vector_value),
}; };
Array { len: values.len() as u32, item: *self }.check_value(generator, ctx, value).unwrap() Array { len: AnyLen(values.len() as u32), item: *self }
.check_value(generator, ctx, value)
.unwrap()
} }
} }