diff --git a/nac3core/src/codegen/model/array.rs b/nac3core/src/codegen/model/array.rs index 829c27fe..afd2ae84 100644 --- a/nac3core/src/codegen/model/array.rs +++ b/nac3core/src/codegen/model/array.rs @@ -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; + +/// A dynamically known length. #[derive(Debug, Clone, Copy)] -pub struct Array { +pub struct AnyLen(pub u32); + +impl LenKind for Len { + 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 { /// 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 { +impl<'ctx, Len: LenKind, Item: Model<'ctx>> Model<'ctx> for Array { type Value = ArrayValue<'ctx>; type Type = ArrayType<'ctx>; fn get_type(&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, G: CodeGenerator + ?Sized>( @@ -36,11 +62,11 @@ impl<'ctx, Element: Model<'ctx>> Model<'ctx> for Array { 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 { } } -impl<'ctx, Element: Model<'ctx>> Instance<'ctx, Ptr>> { +impl<'ctx, Len: LenKind, Item: Model<'ctx>> Instance<'ctx, Ptr>> { /// Get the pointer to the `i`-th (0-based) array element. - pub fn at( + pub fn gep( + &self, + ctx: &CodeGenContext<'ctx, '_>, + i: IntValue<'ctx>, + ) -> Instance<'ctx, Ptr> { + 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> { + 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( &self, generator: &mut G, ctx: &CodeGenContext<'ctx, '_>, - i: u32, - name: &str, - ) -> Instance<'ctx, Ptr> { - 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( + &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); } } diff --git a/nac3core/src/codegen/model/core.rs b/nac3core/src/codegen/model/core.rs index f9950e0a..54ada83a 100644 --- a/nac3core/src/codegen/model/core.rs +++ b/nac3core/src/codegen/model/core.rs @@ -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> { + ) -> Instance<'ctx, Array> { 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() } }