forked from M-Labs/nac3
parent
be4b04dbb3
commit
8b0305ab6b
|
@ -1,28 +1,54 @@
|
|||
use std::fmt;
|
||||
|
||||
use inkwell::{
|
||||
context::Context,
|
||||
types::{ArrayType, BasicType, BasicTypeEnum},
|
||||
values::ArrayValue,
|
||||
values::{ArrayValue, IntValue},
|
||||
};
|
||||
|
||||
use crate::codegen::{CodeGenContext, CodeGenerator};
|
||||
|
||||
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)]
|
||||
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.
|
||||
pub len: u32,
|
||||
pub len: Len,
|
||||
/// [`Model`] of an array 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 Type = ArrayType<'ctx>;
|
||||
|
||||
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>(
|
||||
|
@ -36,11 +62,11 @@ impl<'ctx, Element: Model<'ctx>> Model<'ctx> for Array<Element> {
|
|||
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!(
|
||||
"Expecting ArrayType with size {}, but got an ArrayType with size {}",
|
||||
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.
|
||||
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,
|
||||
generator: &mut G,
|
||||
ctx: &CodeGenContext<'ctx, '_>,
|
||||
i: u32,
|
||||
name: &str,
|
||||
) -> Instance<'ctx, Ptr<Element>> {
|
||||
assert!(i < self.model.0.len);
|
||||
i: IntValue<'ctx>,
|
||||
) -> Instance<'ctx, Item> {
|
||||
self.gep(ctx, i).load(generator, ctx)
|
||||
}
|
||||
|
||||
let zero = ctx.ctx.i32_type().const_zero();
|
||||
let i = ctx.ctx.i32_type().const_int(u64::from(i), false);
|
||||
let ptr = unsafe { ctx.builder.build_in_bounds_gep(self.value, &[zero, i], name).unwrap() };
|
||||
/// Like `get` but `i` is a constant.
|
||||
pub fn get_const<G: CodeGenerator + ?Sized>(
|
||||
&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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -117,7 +117,7 @@ pub trait Model<'ctx>: fmt::Debug + Clone + Copy {
|
|||
generator: &mut G,
|
||||
ctx: &'ctx Context,
|
||||
values: &[Instance<'ctx, Self>],
|
||||
) -> Instance<'ctx, Array<Self>> {
|
||||
) -> Instance<'ctx, Array<AnyLen, Self>> {
|
||||
macro_rules! make {
|
||||
($t:expr, $into_value:expr) => {
|
||||
$t.const_array(
|
||||
|
@ -138,7 +138,9 @@ pub trait Model<'ctx>: fmt::Debug + Clone + Copy {
|
|||
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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue