From 393ef6098eee59725f15c08ffa9045e50023c169 Mon Sep 17 00:00:00 2001 From: David Mak Date: Tue, 19 Mar 2024 00:20:09 +0800 Subject: [PATCH] core: Add ArrayLikeValue For exposing LLVM values that can be accessed like an array. --- nac3core/src/codegen/classes.rs | 793 +++++++++++++++++++++--------- nac3core/src/codegen/expr.rs | 25 +- nac3core/src/codegen/generator.rs | 6 +- nac3core/src/codegen/irrt/mod.rs | 84 ++-- nac3core/src/codegen/numpy.rs | 34 +- nac3core/src/codegen/stmt.rs | 7 +- 6 files changed, 646 insertions(+), 303 deletions(-) diff --git a/nac3core/src/codegen/classes.rs b/nac3core/src/codegen/classes.rs index 656b13d..d303638 100644 --- a/nac3core/src/codegen/classes.rs +++ b/nac3core/src/codegen/classes.rs @@ -11,6 +11,384 @@ use crate::codegen::{ stmt::gen_for_callback_incrementing, }; +/// An LLVM value that is array-like, i.e. it contains a contiguous, sequenced collection of +/// elements. +pub trait ArrayLikeValue<'ctx> { + /// Returns the element type of this array-like value. + fn element_type( + &self, + ctx: &CodeGenContext<'ctx, '_>, + generator: &G, + ) -> AnyTypeEnum<'ctx>; + + /// Returns the base pointer to the array. + fn base_ptr( + &self, + ctx: &CodeGenContext<'ctx, '_>, + generator: &G, + ) -> PointerValue<'ctx>; + + /// Returns the size of this array-like value. + fn size( + &self, + ctx: &CodeGenContext<'ctx, '_>, + generator: &G, + ) -> IntValue<'ctx>; + + /// Returns a [`ArraySliceValue`] representing this value. + fn as_slice_value( + &self, + ctx: &CodeGenContext<'ctx, '_>, + generator: &G, + ) -> ArraySliceValue<'ctx> { + ArraySliceValue::from_ptr_val( + self.base_ptr(ctx, generator), + self.size(ctx, generator), + None, + ) + } +} + +/// An array-like value that can be indexed by memory offset. +pub trait ArrayLikeIndexer<'ctx, Index = IntValue<'ctx>>: ArrayLikeValue<'ctx> { + /// # Safety + /// + /// This function should be called with a valid index. + unsafe fn ptr_offset_unchecked( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: Index, + name: Option<&str>, + ) -> PointerValue<'ctx>; + + /// Returns the pointer to the data at the `idx`-th index. + fn ptr_offset( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: Index, + name: Option<&str>, + ) -> PointerValue<'ctx>; +} + +/// An array-like value that can have its array elements accessed as a [`BasicValueEnum`]. +pub trait UntypedArrayLikeAccessor<'ctx, Index = IntValue<'ctx>>: ArrayLikeIndexer<'ctx, Index> { + /// # Safety + /// + /// This function should be called with a valid index. + unsafe fn get_unchecked( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: Index, + name: Option<&str>, + ) -> BasicValueEnum<'ctx> { + let ptr = self.ptr_offset_unchecked(ctx, generator, idx, name); + ctx.builder.build_load(ptr, name.unwrap_or_default()).unwrap() + } + + /// Returns the data at the `idx`-th index. + fn get( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: Index, + name: Option<&str>, + ) -> BasicValueEnum<'ctx> { + let ptr = self.ptr_offset(ctx, generator, idx, name); + ctx.builder.build_load(ptr, name.unwrap_or_default()).unwrap() + } +} + +/// An array-like value that can have its array elements mutated as a [`BasicValueEnum`]. +pub trait UntypedArrayLikeMutator<'ctx, Index = IntValue<'ctx>>: ArrayLikeIndexer<'ctx, Index> { + /// # Safety + /// + /// This function should be called with a valid index. + unsafe fn set_unchecked( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: Index, + value: BasicValueEnum<'ctx>, + ) { + let ptr = self.ptr_offset_unchecked(ctx, generator, idx, None); + ctx.builder.build_store(ptr, value).unwrap(); + } + + /// Sets the data at the `idx`-th index. + fn set( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: Index, + value: BasicValueEnum<'ctx>, + ) { + let ptr = self.ptr_offset(ctx, generator, idx, None); + ctx.builder.build_store(ptr, value).unwrap(); + } +} + +/// An array-like value that can have its array elements accessed as an arbitrary type `T`. +pub trait TypedArrayLikeAccessor<'ctx, T, Index = IntValue<'ctx>>: UntypedArrayLikeAccessor<'ctx, Index> { + /// Casts an element from [`BasicValueEnum`] into `T`. + fn downcast_to_type(&self, ctx: &mut CodeGenContext<'ctx, '_>, value: BasicValueEnum<'ctx>) -> T; + + /// # Safety + /// + /// This function should be called with a valid index. + unsafe fn get_typed_unchecked( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: Index, + name: Option<&str>, + ) -> T { + let value = self.get_unchecked(ctx, generator, idx, name); + self.downcast_to_type(ctx, value) + } + + /// Returns the data at the `idx`-th index. + fn get_typed( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: Index, + name: Option<&str>, + ) -> T { + let value = self.get(ctx, generator, idx, name); + self.downcast_to_type(ctx, value) + } +} + +/// An array-like value that can have its array elements mutated as an arbitrary type `T`. +pub trait TypedArrayLikeMutator<'ctx, T, Index = IntValue<'ctx>>: UntypedArrayLikeMutator<'ctx, Index> { + /// Casts an element from T into [`BasicValueEnum`]. + fn upcast_from_type(&self, ctx: &mut CodeGenContext<'ctx, '_>, value: T) -> BasicValueEnum<'ctx>; + + /// # Safety + /// + /// This function should be called with a valid index. + unsafe fn set_typed_unchecked( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: Index, + value: T, + ) { + let value = self.upcast_from_type(ctx, value); + self.set_unchecked(ctx, generator, idx, value); + } + + /// Sets the data at the `idx`-th index. + fn set_typed( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: Index, + value: T, + ) { + let value = self.upcast_from_type(ctx, value); + self.set(ctx, generator, idx, value); + } +} + +/// Type alias for a function that casts a [`BasicValueEnum`] into a `T`. +type ValueDowncastFn<'ctx, T> = Box, BasicValueEnum<'ctx>) -> T>; +/// Type alias for a function that casts a `T` into a [`BasicValueEnum`]. +type ValueUpcastFn<'ctx, T> = Box, T) -> BasicValueEnum<'ctx>>; + +/// An adapter for constraining untyped array values as typed values. +#[allow(clippy::type_complexity)] +pub struct TypedArrayLikeAdapter<'ctx, T, Adapted: ArrayLikeValue<'ctx>> { + adapted: Adapted, + downcast_fn: ValueDowncastFn<'ctx, T>, + upcast_fn: ValueUpcastFn<'ctx, T>, +} + +impl<'ctx, T, Adapted> TypedArrayLikeAdapter<'ctx, T, Adapted> + where Adapted: ArrayLikeValue<'ctx> { + /// Creates a [`TypedArrayLikeAdapter`]. + /// + /// * `adapted` - The value to be adapted. + /// * `downcast_fn` - The function converting a [`BasicValueEnum`] into a `T`. + /// * `upcast_fn` - The function converting a T into a [`BasicValueEnum`]. + pub fn from( + adapted: Adapted, + downcast_fn: ValueDowncastFn<'ctx, T>, + upcast_fn: ValueUpcastFn<'ctx, T>, + ) -> Self { + TypedArrayLikeAdapter { adapted, downcast_fn, upcast_fn } + } +} + +impl<'ctx, T, Adapted> ArrayLikeValue<'ctx> for TypedArrayLikeAdapter<'ctx, T, Adapted> + where Adapted: ArrayLikeValue<'ctx> { + fn element_type( + &self, + ctx: &CodeGenContext<'ctx, '_>, + generator: &G, + ) -> AnyTypeEnum<'ctx> { + self.adapted.element_type(ctx, generator) + } + + fn base_ptr( + &self, + ctx: &CodeGenContext<'ctx, '_>, + generator: &G, + ) -> PointerValue<'ctx> { + self.adapted.base_ptr(ctx, generator) + } + + fn size( + &self, + ctx: &CodeGenContext<'ctx, '_>, + generator: &G, + ) -> IntValue<'ctx> { + self.adapted.size(ctx, generator) + } +} + +impl<'ctx, T, Index, Adapted> ArrayLikeIndexer<'ctx, Index> for TypedArrayLikeAdapter<'ctx, T, Adapted> + where Adapted: ArrayLikeIndexer<'ctx, Index> { + unsafe fn ptr_offset_unchecked( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: Index, + name: Option<&str>, + ) -> PointerValue<'ctx> { + self.adapted.ptr_offset_unchecked(ctx, generator, idx, name) + } + + fn ptr_offset( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: Index, + name: Option<&str>, + ) -> PointerValue<'ctx> { + self.adapted.ptr_offset(ctx, generator, idx, name) + } +} + +impl<'ctx, T, Index, Adapted> UntypedArrayLikeAccessor<'ctx, Index> for TypedArrayLikeAdapter<'ctx, T, Adapted> + where Adapted: UntypedArrayLikeAccessor<'ctx, Index> {} +impl<'ctx, T, Index, Adapted> UntypedArrayLikeMutator<'ctx, Index> for TypedArrayLikeAdapter<'ctx, T, Adapted> + where Adapted: UntypedArrayLikeMutator<'ctx, Index> {} + +impl<'ctx, T, Index, Adapted> TypedArrayLikeAccessor<'ctx, T, Index> for TypedArrayLikeAdapter<'ctx, T, Adapted> + where Adapted: UntypedArrayLikeAccessor<'ctx, Index> { + fn downcast_to_type(&self, ctx: &mut CodeGenContext<'ctx, '_>, value: BasicValueEnum<'ctx>) -> T { + (self.downcast_fn)(ctx, value) + } +} + +impl<'ctx, T, Index, Adapted> TypedArrayLikeMutator<'ctx, T, Index> for TypedArrayLikeAdapter<'ctx, T, Adapted> + where Adapted: UntypedArrayLikeMutator<'ctx, Index> { + fn upcast_from_type(&self, ctx: &mut CodeGenContext<'ctx, '_>, value: T) -> BasicValueEnum<'ctx> { + (self.upcast_fn)(ctx, value) + } +} + +/// An LLVM value representing an array slice, consisting of a pointer to the data and the size of +/// the slice. +#[derive(Copy, Clone)] +pub struct ArraySliceValue<'ctx>(PointerValue<'ctx>, IntValue<'ctx>, Option<&'ctx str>); + +impl<'ctx> ArraySliceValue<'ctx> { + /// Creates an [`ArraySliceValue`] from a [`PointerValue`] and its size. + #[must_use] + pub fn from_ptr_val( + ptr: PointerValue<'ctx>, + size: IntValue<'ctx>, + name: Option<&'ctx str>, + ) -> Self { + ArraySliceValue(ptr, size, name) + } +} + +impl<'ctx> From> for PointerValue<'ctx> { + fn from(value: ArraySliceValue<'ctx>) -> Self { + value.0 + } +} + +impl<'ctx> ArrayLikeValue<'ctx> for ArraySliceValue<'ctx> { + fn element_type( + &self, + _: &CodeGenContext<'ctx, '_>, + _: &G, + ) -> AnyTypeEnum<'ctx> { + self.0.get_type().get_element_type() + } + + fn base_ptr( + &self, + _: &CodeGenContext<'ctx, '_>, + _: &G, + ) -> PointerValue<'ctx> { + self.0 + } + + fn size( + &self, + _: &CodeGenContext<'ctx, '_>, + _: &G, + ) -> IntValue<'ctx> { + self.1 + } +} + +impl<'ctx> ArrayLikeIndexer<'ctx> for ArraySliceValue<'ctx> { + unsafe fn ptr_offset_unchecked( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: IntValue<'ctx>, + name: Option<&str>, + ) -> PointerValue<'ctx> { + let var_name = name + .map(|v| format!("{v}.addr")) + .unwrap_or_default(); + + ctx.builder.build_in_bounds_gep( + self.base_ptr(ctx, generator), + &[idx], + var_name.as_str(), + ).unwrap() + } + + fn ptr_offset( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: IntValue<'ctx>, + name: Option<&str>, + ) -> PointerValue<'ctx> { + debug_assert_eq!(idx.get_type(), generator.get_size_type(ctx.ctx)); + + let size = self.size(ctx, generator); + let in_range = ctx.builder.build_int_compare(IntPredicate::ULT, idx, size, "").unwrap(); + ctx.make_assert( + generator, + in_range, + "0:IndexError", + "list index out of range", + [None, None, None], + ctx.current_loc, + ); + + unsafe { + self.ptr_offset_unchecked(ctx, generator, idx, name) + } + } +} + +impl<'ctx> UntypedArrayLikeAccessor<'ctx> for ArraySliceValue<'ctx> {} +impl<'ctx> UntypedArrayLikeMutator<'ctx> for ArraySliceValue<'ctx> {} + #[cfg(not(debug_assertions))] pub fn assert_is_list<'ctx>(_value: PointerValue<'ctx>, _llvm_usize: IntType<'ctx>) {} @@ -120,8 +498,8 @@ impl<'ctx> ListValue<'ctx> { /// Returns the double-indirection pointer to the `data` array, as if by calling `getelementptr` /// on the field. #[must_use] - pub fn data(&self) -> ListDataProxy<'ctx> { - ListDataProxy(*self) + pub fn data(&self) -> ListDataProxy<'ctx, '_> { + ListDataProxy(self) } /// Stores the `size` of this `list` into this instance. @@ -159,11 +537,22 @@ impl<'ctx> From> for PointerValue<'ctx> { /// Proxy type for accessing the `data` array of an `list` instance in LLVM. #[derive(Copy, Clone)] -pub struct ListDataProxy<'ctx>(ListValue<'ctx>); +pub struct ListDataProxy<'ctx, 'a>(&'a ListValue<'ctx>); -impl<'ctx> ListDataProxy<'ctx> { - /// Returns the single-indirection pointer to the array. - pub fn as_ptr_value(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> { +impl<'ctx> ArrayLikeValue<'ctx> for ListDataProxy<'ctx, '_> { + fn element_type( + &self, + _: &CodeGenContext<'ctx, '_>, + _: &G, + ) -> AnyTypeEnum<'ctx> { + self.0.0.get_type().get_element_type() + } + + fn base_ptr( + &self, + ctx: &CodeGenContext<'ctx, '_>, + _: &G, + ) -> PointerValue<'ctx> { let var_name = self.0.1.map(|v| format!("{v}.data")).unwrap_or_default(); ctx.builder.build_load(self.0.pptr_to_data(ctx), var_name.as_str()) @@ -171,12 +560,20 @@ impl<'ctx> ListDataProxy<'ctx> { .unwrap() } - /// # Safety - /// - /// This function should be called with a valid index. - pub unsafe fn ptr_offset_unchecked( + fn size( &self, ctx: &CodeGenContext<'ctx, '_>, + _: &G, + ) -> IntValue<'ctx> { + self.0.load_size(ctx, None) + } +} + +impl<'ctx> ArrayLikeIndexer<'ctx> for ListDataProxy<'ctx, '_> { + unsafe fn ptr_offset_unchecked( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, idx: IntValue<'ctx>, name: Option<&str>, ) -> PointerValue<'ctx> { @@ -185,14 +582,13 @@ impl<'ctx> ListDataProxy<'ctx> { .unwrap_or_default(); ctx.builder.build_in_bounds_gep( - self.as_ptr_value(ctx), + self.base_ptr(ctx, generator), &[idx], var_name.as_str(), ).unwrap() } - /// Returns the pointer to the data at the `idx`-th index. - pub fn ptr_offset( + fn ptr_offset( &self, ctx: &mut CodeGenContext<'ctx, '_>, generator: &mut G, @@ -201,12 +597,8 @@ impl<'ctx> ListDataProxy<'ctx> { ) -> PointerValue<'ctx> { debug_assert_eq!(idx.get_type(), generator.get_size_type(ctx.ctx)); - let in_range = ctx.builder.build_int_compare( - IntPredicate::ULT, - idx, - self.0.load_size(ctx, None), - "" - ).unwrap(); + let size = self.size(ctx, generator); + let in_range = ctx.builder.build_int_compare(IntPredicate::ULT, idx, size, "").unwrap(); ctx.make_assert( generator, in_range, @@ -217,36 +609,14 @@ impl<'ctx> ListDataProxy<'ctx> { ); unsafe { - self.ptr_offset_unchecked(ctx, idx, name) + self.ptr_offset_unchecked(ctx, generator, idx, name) } } - - /// # Safety - /// - /// This function should be called with a valid index. - pub unsafe fn get_unchecked( - &self, - ctx: &mut CodeGenContext<'ctx, '_>, - idx: IntValue<'ctx>, - name: Option<&str>, - ) -> BasicValueEnum<'ctx> { - let ptr = self.ptr_offset_unchecked(ctx, idx, name); - ctx.builder.build_load(ptr, name.unwrap_or_default()).unwrap() - } - - /// Returns the data at the `idx`-th flattened index. - pub fn get( - &self, - ctx: &mut CodeGenContext<'ctx, '_>, - generator: &mut G, - idx: IntValue<'ctx>, - name: Option<&str>, - ) -> BasicValueEnum<'ctx> { - let ptr = self.ptr_offset(ctx, generator, idx, name); - ctx.builder.build_load(ptr, name.unwrap_or_default()).unwrap() - } } +impl<'ctx> UntypedArrayLikeAccessor<'ctx> for ListDataProxy<'ctx, '_> {} +impl<'ctx> UntypedArrayLikeMutator<'ctx> for ListDataProxy<'ctx, '_> {} + #[cfg(not(debug_assertions))] pub fn assert_is_range(_value: PointerValue) {} @@ -559,8 +929,8 @@ impl<'ctx> NDArrayValue<'ctx> { /// Returns a proxy object to the field storing the size of each dimension of this `NDArray`. #[must_use] - pub fn dim_sizes(&self) -> NDArrayDimsProxy<'ctx> { - NDArrayDimsProxy(*self) + pub fn dim_sizes(&self) -> NDArrayDimsProxy<'ctx, '_> { + NDArrayDimsProxy(self) } /// Returns the double-indirection pointer to the `data` array, as if by calling `getelementptr` @@ -596,8 +966,8 @@ impl<'ctx> NDArrayValue<'ctx> { /// Returns a proxy object to the field storing the data of this `NDArray`. #[must_use] - pub fn data(&self) -> NDArrayDataProxy<'ctx> { - NDArrayDataProxy(*self) + pub fn data(&self) -> NDArrayDataProxy<'ctx, '_> { + NDArrayDataProxy(self) } } @@ -609,24 +979,43 @@ impl<'ctx> From> for PointerValue<'ctx> { /// Proxy type for accessing the `dims` array of an `NDArray` instance in LLVM. #[derive(Copy, Clone)] -pub struct NDArrayDimsProxy<'ctx>(NDArrayValue<'ctx>); +pub struct NDArrayDimsProxy<'ctx, 'a>(&'a NDArrayValue<'ctx>); -impl<'ctx> NDArrayDimsProxy<'ctx> { - /// Returns the single-indirection pointer to the array. - pub fn as_ptr_value(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> { - let var_name = self.0.1.map(|v| format!("{v}.dims")).unwrap_or_default(); +impl<'ctx> ArrayLikeValue<'ctx> for NDArrayDimsProxy<'ctx, '_> { + fn element_type( + &self, + ctx: &CodeGenContext<'ctx, '_>, + generator: &G, + ) -> AnyTypeEnum<'ctx> { + self.0.dim_sizes().base_ptr(ctx, generator).get_type().get_element_type() + } + + fn base_ptr( + &self, + ctx: &CodeGenContext<'ctx, '_>, + _: &G, + ) -> PointerValue<'ctx> { + let var_name = self.0.1.map(|v| format!("{v}.data")).unwrap_or_default(); ctx.builder.build_load(self.0.ptr_to_dims(ctx), var_name.as_str()) .map(BasicValueEnum::into_pointer_value) .unwrap() } - /// # Safety - /// - /// This function should be called with a valid index. - pub unsafe fn ptr_offset_unchecked( + fn size( + &self, + ctx: &CodeGenContext<'ctx, '_>, + _: &G, + ) -> IntValue<'ctx> { + self.0.load_ndims(ctx) + } +} + +impl<'ctx> ArrayLikeIndexer<'ctx, IntValue<'ctx>> for NDArrayDimsProxy<'ctx, '_> { + unsafe fn ptr_offset_unchecked( &self, ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, idx: IntValue<'ctx>, name: Option<&str>, ) -> PointerValue<'ctx> { @@ -635,24 +1024,24 @@ impl<'ctx> NDArrayDimsProxy<'ctx> { .unwrap_or_default(); ctx.builder.build_in_bounds_gep( - self.as_ptr_value(ctx), + self.base_ptr(ctx, generator), &[idx], var_name.as_str(), ).unwrap() } - /// Returns the pointer to the size of the `idx`-th dimension. - pub fn ptr_offset( + fn ptr_offset( &self, ctx: &mut CodeGenContext<'ctx, '_>, generator: &mut G, idx: IntValue<'ctx>, name: Option<&str>, ) -> PointerValue<'ctx> { + let size = self.size(ctx, generator); let in_range = ctx.builder.build_int_compare( IntPredicate::ULT, idx, - self.0.load_ndims(ctx), + size, "" ).unwrap(); ctx.make_assert( @@ -665,47 +1054,52 @@ impl<'ctx> NDArrayDimsProxy<'ctx> { ); unsafe { - self.ptr_offset_unchecked(ctx, idx, name) + self.ptr_offset_unchecked(ctx, generator, idx, name) } } +} - /// # Safety - /// - /// This function should be called with a valid index. - pub unsafe fn get_unchecked( +impl<'ctx> UntypedArrayLikeAccessor<'ctx, IntValue<'ctx>> for NDArrayDimsProxy<'ctx, '_> {} +impl<'ctx> UntypedArrayLikeMutator<'ctx, IntValue<'ctx>> for NDArrayDimsProxy<'ctx, '_> {} + +impl<'ctx> TypedArrayLikeAccessor<'ctx, IntValue<'ctx>> for NDArrayDimsProxy<'ctx, '_> { + fn downcast_to_type( &self, - ctx: &mut CodeGenContext<'ctx, '_>, - idx: IntValue<'ctx>, - name: Option<&str>, + _: &mut CodeGenContext<'ctx, '_>, + value: BasicValueEnum<'ctx>, ) -> IntValue<'ctx> { - let ptr = self.ptr_offset_unchecked(ctx, idx, name); - ctx.builder.build_load(ptr, name.unwrap_or_default()) - .map(BasicValueEnum::into_int_value) - .unwrap() + value.into_int_value() } +} - /// Returns the size of the `idx`-th dimension. - pub fn get( +impl<'ctx> TypedArrayLikeMutator<'ctx, IntValue<'ctx>> for NDArrayDimsProxy<'ctx, '_> { + fn upcast_from_type( &self, - ctx: &mut CodeGenContext<'ctx, '_>, - generator: &mut G, - idx: IntValue<'ctx>, - name: Option<&str>, - ) -> IntValue<'ctx> { - let ptr = self.ptr_offset(ctx, generator, idx, name); - ctx.builder.build_load(ptr, name.unwrap_or_default()) - .map(BasicValueEnum::into_int_value) - .unwrap() + _: &mut CodeGenContext<'ctx, '_>, + value: IntValue<'ctx>, + ) -> BasicValueEnum<'ctx> { + value.into() } } /// Proxy type for accessing the `data` array of an `NDArray` instance in LLVM. #[derive(Copy, Clone)] -pub struct NDArrayDataProxy<'ctx>(NDArrayValue<'ctx>); +pub struct NDArrayDataProxy<'ctx, 'a>(&'a NDArrayValue<'ctx>); -impl<'ctx> NDArrayDataProxy<'ctx> { - /// Returns the single-indirection pointer to the array. - pub fn as_ptr_value(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> { +impl<'ctx> ArrayLikeValue<'ctx> for NDArrayDataProxy<'ctx, '_> { + fn element_type( + &self, + ctx: &CodeGenContext<'ctx, '_>, + generator: &G, + ) -> AnyTypeEnum<'ctx> { + self.0.data().base_ptr(ctx, generator).get_type().get_element_type() + } + + fn base_ptr( + &self, + ctx: &CodeGenContext<'ctx, '_>, + _: &G, + ) -> PointerValue<'ctx> { let var_name = self.0.1.map(|v| format!("{v}.data")).unwrap_or_default(); ctx.builder.build_load(self.0.ptr_to_data(ctx), var_name.as_str()) @@ -713,34 +1107,38 @@ impl<'ctx> NDArrayDataProxy<'ctx> { .unwrap() } - /// # Safety - /// - /// This function should be called with a valid index. - pub unsafe fn ptr_to_data_flattened_unchecked( + fn size( &self, ctx: &CodeGenContext<'ctx, '_>, - idx: IntValue<'ctx>, - name: Option<&str>, - ) -> PointerValue<'ctx> { - ctx.builder.build_in_bounds_gep( - self.as_ptr_value(ctx), - &[idx], - name.unwrap_or_default(), - ).unwrap() + generator: &G, + ) -> IntValue<'ctx> { + call_ndarray_calc_size(generator, ctx, &self.as_slice_value(ctx, generator)) } +} - /// Returns the pointer to the data at the `idx`-th flattened index. - pub fn ptr_to_data_flattened( +impl<'ctx> ArrayLikeIndexer<'ctx> for NDArrayDataProxy<'ctx, '_> { + unsafe fn ptr_offset_unchecked( &self, ctx: &mut CodeGenContext<'ctx, '_>, generator: &mut G, idx: IntValue<'ctx>, name: Option<&str>, ) -> PointerValue<'ctx> { - let ndims = self.0.load_ndims(ctx); - let dims = self.0.dim_sizes().as_ptr_value(ctx); - let data_sz = call_ndarray_calc_size(generator, ctx, ndims, dims); + ctx.builder.build_in_bounds_gep( + self.base_ptr(ctx, generator), + &[idx], + name.unwrap_or_default(), + ).unwrap() + } + fn ptr_offset( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + idx: IntValue<'ctx>, + name: Option<&str>, + ) -> PointerValue<'ctx> { + let data_sz = self.size(ctx, generator); let in_range = ctx.builder.build_int_compare( IntPredicate::ULT, idx, @@ -757,71 +1155,16 @@ impl<'ctx> NDArrayDataProxy<'ctx> { ); unsafe { - self.ptr_to_data_flattened_unchecked(ctx, idx, name) + self.ptr_offset_unchecked(ctx, generator, idx, name) } } +} - /// # Safety - /// - /// This function should be called with a valid index. - pub unsafe fn get_flattened_unchecked( - &self, - ctx: &mut CodeGenContext<'ctx, '_>, - idx: IntValue<'ctx>, - name: Option<&str>, - ) -> BasicValueEnum<'ctx> { - let ptr = self.ptr_to_data_flattened_unchecked(ctx, idx, name); - ctx.builder.build_load(ptr, name.unwrap_or_default()).unwrap() - } +impl<'ctx> UntypedArrayLikeAccessor<'ctx, IntValue<'ctx>> for NDArrayDataProxy<'ctx, '_> {} +impl<'ctx> UntypedArrayLikeMutator<'ctx, IntValue<'ctx>> for NDArrayDataProxy<'ctx, '_> {} - /// Returns the data at the `idx`-th flattened index. - pub fn get_flattened( - &self, - ctx: &mut CodeGenContext<'ctx, '_>, - generator: &mut G, - idx: IntValue<'ctx>, - name: Option<&str>, - ) -> BasicValueEnum<'ctx> { - let ptr = self.ptr_to_data_flattened(ctx, generator, idx, name); - ctx.builder.build_load(ptr, name.unwrap_or_default()).unwrap() - } - - /// # Safety - /// - /// This function should be called with valid indices. - pub unsafe fn ptr_offset_unchecked( - &self, - ctx: &CodeGenContext<'ctx, '_>, - generator: &G, - indices: ListValue<'ctx>, - name: Option<&str>, - ) -> PointerValue<'ctx> { - let indices_elem_ty = indices.data().as_ptr_value(ctx).get_type().get_element_type(); - let Ok(indices_elem_ty) = IntType::try_from(indices_elem_ty) else { - panic!("Expected list[int32] but got {indices_elem_ty}") - }; - assert_eq!(indices_elem_ty.get_bit_width(), 32, "Expected list[int32] but got {indices_elem_ty}"); - - let index = call_ndarray_flatten_index( - generator, - ctx, - self.0, - indices, - ); - - unsafe { - ctx.builder.build_in_bounds_gep( - self.as_ptr_value(ctx), - &[index], - name.unwrap_or_default(), - ).unwrap() - } - } - - /// # Safety - /// - /// This function should be called with valid indices. - pub unsafe fn ptr_offset_unchecked_const( +impl<'ctx> ArrayLikeIndexer<'ctx, ArrayValue<'ctx>> for NDArrayDataProxy<'ctx, '_> { + unsafe fn ptr_offset_unchecked( &self, ctx: &mut CodeGenContext<'ctx, '_>, generator: &mut G, @@ -831,21 +1174,20 @@ impl<'ctx> NDArrayDataProxy<'ctx> { let index = call_ndarray_flatten_index_const( generator, ctx, - self.0, + *self.0, indices, ); unsafe { ctx.builder.build_in_bounds_gep( - self.as_ptr_value(ctx), + self.base_ptr(ctx, generator), &[index], name.unwrap_or_default(), ) }.unwrap() } - /// Returns the pointer to the data at the index specified by `indices`. - pub fn ptr_offset_const( + fn ptr_offset( &self, ctx: &mut CodeGenContext<'ctx, '_>, generator: &mut G, @@ -884,7 +1226,7 @@ impl<'ctx> NDArrayDataProxy<'ctx> { .map(|v| ctx.builder.build_int_z_extend_or_bit_cast(v, llvm_usize, "").unwrap()) .unwrap(); let dim_sz = unsafe { - self.0.dim_sizes().get_unchecked(ctx, i, None) + self.0.dim_sizes().get_typed_unchecked(ctx, generator, i, None) }; let dim_lt = ctx.builder.build_int_compare( @@ -905,23 +1247,59 @@ impl<'ctx> NDArrayDataProxy<'ctx> { } unsafe { - self.ptr_offset_unchecked_const(ctx, generator, indices, name) + self.ptr_offset_unchecked(ctx, generator, indices, name) } } +} - /// Returns the pointer to the data at the index specified by `indices`. - pub fn ptr_offset( +impl<'ctx> UntypedArrayLikeAccessor<'ctx, ArrayValue<'ctx>> for NDArrayDataProxy<'ctx, '_> {} +impl<'ctx> UntypedArrayLikeMutator<'ctx, ArrayValue<'ctx>> for NDArrayDataProxy<'ctx, '_> {} + +impl<'ctx, Index: UntypedArrayLikeAccessor<'ctx>> ArrayLikeIndexer<'ctx, Index> for NDArrayDataProxy<'ctx, '_> { + unsafe fn ptr_offset_unchecked( &self, ctx: &mut CodeGenContext<'ctx, '_>, generator: &mut G, - indices: ListValue<'ctx>, + indices: Index, name: Option<&str>, ) -> PointerValue<'ctx> { let llvm_usize = generator.get_size_type(ctx.ctx); + let indices_elem_ty = indices.ptr_offset(ctx, generator, llvm_usize.const_zero(), None).get_type().get_element_type(); + let Ok(indices_elem_ty) = IntType::try_from(indices_elem_ty) else { + panic!("Expected list[int32] but got {indices_elem_ty}") + }; + assert_eq!(indices_elem_ty.get_bit_width(), 32, "Expected list[int32] but got {indices_elem_ty}"); + + let index = call_ndarray_flatten_index( + generator, + ctx, + *self.0, + &indices, + ); + + unsafe { + ctx.builder.build_in_bounds_gep( + self.base_ptr(ctx, generator), + &[index], + name.unwrap_or_default(), + ).unwrap() + } + } + + fn ptr_offset( + &self, + ctx: &mut CodeGenContext<'ctx, '_>, + generator: &mut G, + indices: Index, + name: Option<&str>, + ) -> PointerValue<'ctx> { + let llvm_usize = generator.get_size_type(ctx.ctx); + + let indices_size = indices.size(ctx, generator); let nidx_leq_ndims = ctx.builder.build_int_compare( IntPredicate::SLE, - indices.load_size(ctx, None), + indices_size, self.0.load_ndims(ctx), "" ).unwrap(); @@ -934,7 +1312,7 @@ impl<'ctx> NDArrayDataProxy<'ctx> { ctx.current_loc, ); - let indices_len = indices.load_size(ctx, None); + let indices_len = indices.size(ctx, generator); let ndarray_len = self.0.load_ndims(ctx); let len = call_int_umin(ctx, indices_len, ndarray_len, None); gen_for_callback_incrementing( @@ -945,8 +1323,8 @@ impl<'ctx> NDArrayDataProxy<'ctx> { |generator, ctx, i| { let (dim_idx, dim_sz) = unsafe { ( - indices.data().get_unchecked(ctx, i, None).into_int_value(), - self.0.dim_sizes().get_unchecked(ctx, i, None), + indices.get_unchecked(ctx, generator, i, None).into_int_value(), + self.0.dim_sizes().get_typed_unchecked(ctx, generator, i, None), ) }; @@ -975,56 +1353,7 @@ impl<'ctx> NDArrayDataProxy<'ctx> { self.ptr_offset_unchecked(ctx, generator, indices, name) } } - - /// # Safety - /// - /// This function should be called with valid indices. - pub unsafe fn get_unchecked_const( - &self, - ctx: &mut CodeGenContext<'ctx, '_>, - generator: &mut G, - indices: ArrayValue<'ctx>, - name: Option<&str>, - ) -> BasicValueEnum<'ctx> { - let ptr = self.ptr_offset_unchecked_const(ctx, generator, indices, name); - ctx.builder.build_load(ptr, name.unwrap_or_default()).unwrap() - } - - /// # Safety - /// - /// This function should be called with valid indices. - pub unsafe fn get_unchecked( - &self, - ctx: &mut CodeGenContext<'ctx, '_>, - generator: &G, - indices: ListValue<'ctx>, - name: Option<&str>, - ) -> BasicValueEnum<'ctx> { - let ptr = self.ptr_offset_unchecked(ctx, generator, indices, name); - ctx.builder.build_load(ptr, name.unwrap_or_default()).unwrap() - } - - /// Returns the data at the index specified by `indices`. - pub fn get_const( - &self, - ctx: &mut CodeGenContext<'ctx, '_>, - generator: &mut G, - indices: ArrayValue<'ctx>, - name: Option<&str>, - ) -> BasicValueEnum<'ctx> { - let ptr = self.ptr_offset_const(ctx, generator, indices, name); - ctx.builder.build_load(ptr, name.unwrap_or_default()).unwrap() - } - - /// Returns the data at the index specified by `indices`. - pub fn get( - &self, - ctx: &mut CodeGenContext<'ctx, '_>, - generator: &mut G, - indices: ListValue<'ctx>, - name: Option<&str>, - ) -> BasicValueEnum<'ctx> { - let ptr = self.ptr_offset(ctx, generator, indices, name); - ctx.builder.build_load(ptr, name.unwrap_or_default()).unwrap() - } } + +impl<'ctx, Index: UntypedArrayLikeAccessor<'ctx>> UntypedArrayLikeAccessor<'ctx, Index> for NDArrayDataProxy<'ctx, '_> {} +impl<'ctx, Index: UntypedArrayLikeAccessor<'ctx>> UntypedArrayLikeMutator<'ctx, Index> for NDArrayDataProxy<'ctx, '_> {} diff --git a/nac3core/src/codegen/expr.rs b/nac3core/src/codegen/expr.rs index faa3ee1..703fe16 100644 --- a/nac3core/src/codegen/expr.rs +++ b/nac3core/src/codegen/expr.rs @@ -2,7 +2,14 @@ use std::{collections::HashMap, convert::TryInto, iter::once, iter::zip}; use crate::{ codegen::{ - classes::{ListValue, NDArrayValue, RangeValue}, + classes::{ + ArrayLikeIndexer, + ArrayLikeValue, + ListValue, + NDArrayValue, + RangeValue, + UntypedArrayLikeAccessor, + }, concrete_type::{ConcreteFuncArg, ConcreteTypeEnum, ConcreteTypeStore}, gen_in_range_check, get_llvm_type, @@ -982,7 +989,7 @@ pub fn gen_comprehension<'ctx, G: CodeGenerator>( list_alloc_size.into_int_value(), Some("listcomp.addr") ); - list_content = list.data().as_ptr_value(ctx); + list_content = list.data().base_ptr(ctx, generator); let i = generator.gen_store_target(ctx, target, Some("i.addr"))?.unwrap(); ctx.builder @@ -1015,7 +1022,7 @@ pub fn gen_comprehension<'ctx, G: CodeGenerator>( ) .into_int_value(); list = allocate_list(generator, ctx, elem_ty, length, Some("listcomp")); - list_content = list.data().as_ptr_value(ctx); + list_content = list.data().base_ptr(ctx, generator); let counter = generator.gen_var_alloc(ctx, size_t.into(), Some("counter.addr"))?; // counter = -1 ctx.builder.build_store(counter, size_t.const_int(u64::MAX, true)).unwrap(); @@ -1260,7 +1267,7 @@ fn gen_ndarray_subscript_expr<'ctx, G: CodeGenerator>( }; Ok(Some(v.data() - .get_const( + .get( ctx, generator, ctx.ctx.i32_type().const_array(&[index]), @@ -1307,13 +1314,14 @@ fn gen_ndarray_subscript_expr<'ctx, G: CodeGenerator>( let v_dims_src_ptr = unsafe { v.dim_sizes().ptr_offset_unchecked( ctx, + generator, llvm_usize.const_int(1, false), None, ) }; call_memcpy_generic( ctx, - ndarray.dim_sizes().as_ptr_value(ctx), + ndarray.dim_sizes().base_ptr(ctx, generator), v_dims_src_ptr, ctx.builder .build_int_mul(ndarray_num_dims, llvm_usize.size_of(), "") @@ -1325,12 +1333,11 @@ fn gen_ndarray_subscript_expr<'ctx, G: CodeGenerator>( let ndarray_num_elems = call_ndarray_calc_size( generator, ctx, - ndarray.load_ndims(ctx), - ndarray.dim_sizes().as_ptr_value(ctx), + &ndarray.dim_sizes().as_slice_value(ctx, generator), ); ndarray.create_data(ctx, llvm_ndarray_data_t, ndarray_num_elems); - let v_data_src_ptr = v.data().ptr_offset_const( + let v_data_src_ptr = v.data().ptr_offset( ctx, generator, ctx.ctx.i32_type().const_array(&[index]), @@ -1338,7 +1345,7 @@ fn gen_ndarray_subscript_expr<'ctx, G: CodeGenerator>( ); call_memcpy_generic( ctx, - ndarray.data().as_ptr_value(ctx), + ndarray.data().base_ptr(ctx, generator), v_data_src_ptr, ctx.builder .build_int_mul(ndarray_num_elems, llvm_ndarray_data_t.size_of().unwrap(), "") diff --git a/nac3core/src/codegen/generator.rs b/nac3core/src/codegen/generator.rs index 595313c..4f7dd0d 100644 --- a/nac3core/src/codegen/generator.rs +++ b/nac3core/src/codegen/generator.rs @@ -1,5 +1,5 @@ use crate::{ - codegen::{expr::*, stmt::*, bool_to_i1, bool_to_i8, CodeGenContext}, + codegen::{classes::ArraySliceValue, expr::*, stmt::*, bool_to_i1, bool_to_i8, CodeGenContext}, symbol_resolver::ValueEnum, toplevel::{DefinitionId, TopLevelDef}, typecheck::typedef::{FunSignature, Type}, @@ -99,8 +99,8 @@ pub trait CodeGenerator { ctx: &mut CodeGenContext<'ctx, '_>, ty: BasicTypeEnum<'ctx>, size: IntValue<'ctx>, - name: Option<&str>, - ) -> Result, String> { + name: Option<&'ctx str>, + ) -> Result, String> { gen_array_var(ctx, ty, size, name) } diff --git a/nac3core/src/codegen/irrt/mod.rs b/nac3core/src/codegen/irrt/mod.rs index bf34044..0008d7b 100644 --- a/nac3core/src/codegen/irrt/mod.rs +++ b/nac3core/src/codegen/irrt/mod.rs @@ -1,7 +1,7 @@ use crate::typecheck::typedef::Type; use super::{ - classes::{ListValue, NDArrayValue}, + classes::{ArrayLikeIndexer, ArrayLikeValue, ListValue, NDArrayValue, UntypedArrayLikeMutator}, CodeGenContext, CodeGenerator, }; @@ -338,7 +338,7 @@ pub fn list_slice_assignment<'ctx, G: CodeGenerator + ?Sized>( let zero = int32.const_zero(); let one = int32.const_int(1, false); - let dest_arr_ptr = dest_arr.data().as_ptr_value(ctx); + let dest_arr_ptr = dest_arr.data().base_ptr(ctx, generator); let dest_arr_ptr = ctx.builder.build_pointer_cast( dest_arr_ptr, elem_ptr_type, @@ -346,7 +346,7 @@ pub fn list_slice_assignment<'ctx, G: CodeGenerator + ?Sized>( ).unwrap(); let dest_len = dest_arr.load_size(ctx, Some("dest.len")); let dest_len = ctx.builder.build_int_truncate_or_bit_cast(dest_len, int32, "srclen32").unwrap(); - let src_arr_ptr = src_arr.data().as_ptr_value(ctx); + let src_arr_ptr = src_arr.data().base_ptr(ctx, generator); let src_arr_ptr = ctx.builder.build_pointer_cast( src_arr_ptr, elem_ptr_type, @@ -574,12 +574,14 @@ pub fn call_j0<'ctx>( /// /// * `num_dims` - An [`IntValue`] containing the number of dimensions. /// * `dims` - A [`PointerValue`] to an array containing the size of each dimension. -pub fn call_ndarray_calc_size<'ctx, G: CodeGenerator + ?Sized>( +pub fn call_ndarray_calc_size<'ctx, G, Dims>( generator: &G, - ctx: &mut CodeGenContext<'ctx, '_>, - num_dims: IntValue<'ctx>, - dims: PointerValue<'ctx>, -) -> IntValue<'ctx> { + ctx: &CodeGenContext<'ctx, '_>, + dims: &Dims, +) -> IntValue<'ctx> + where + G: CodeGenerator + ?Sized, + Dims: ArrayLikeIndexer<'ctx>, { let llvm_i64 = ctx.ctx.i64_type(); let llvm_usize = generator.get_size_type(ctx.ctx); @@ -606,8 +608,8 @@ pub fn call_ndarray_calc_size<'ctx, G: CodeGenerator + ?Sized>( .build_call( ndarray_calc_size_fn, &[ - dims.into(), - num_dims.into(), + dims.base_ptr(ctx, generator).into(), + dims.size(ctx, generator).into(), ], "", ) @@ -666,7 +668,7 @@ pub fn call_ndarray_calc_nd_indices<'ctx, G: CodeGenerator + ?Sized>( ndarray_calc_nd_indices_fn, &[ index.into(), - ndarray_dims.as_ptr_value(ctx).into(), + ndarray_dims.base_ptr(ctx, generator).into(), ndarray_num_dims.into(), indices.into(), ], @@ -677,13 +679,15 @@ pub fn call_ndarray_calc_nd_indices<'ctx, G: CodeGenerator + ?Sized>( indices } -fn call_ndarray_flatten_index_impl<'ctx, G: CodeGenerator + ?Sized>( +fn call_ndarray_flatten_index_impl<'ctx, G, Indices>( generator: &G, ctx: &CodeGenContext<'ctx, '_>, ndarray: NDArrayValue<'ctx>, - indices: PointerValue<'ctx>, - indices_size: IntValue<'ctx>, -) -> IntValue<'ctx> { + indices: &Indices, +) -> IntValue<'ctx> + where + G: CodeGenerator + ?Sized, + Indices: ArrayLikeIndexer<'ctx>, { let llvm_i32 = ctx.ctx.i32_type(); let llvm_usize = generator.get_size_type(ctx.ctx); @@ -691,14 +695,14 @@ fn call_ndarray_flatten_index_impl<'ctx, G: CodeGenerator + ?Sized>( let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default()); debug_assert_eq!( - IntType::try_from(indices.get_type().get_element_type()) + IntType::try_from(indices.element_type(ctx, generator)) .map(IntType::get_bit_width) .unwrap_or_default(), llvm_i32.get_bit_width(), "Expected i32 value for argument `indices` to `call_ndarray_flatten_index_impl`" ); debug_assert_eq!( - indices_size.get_type().get_bit_width(), + indices.size(ctx, generator).get_type().get_bit_width(), llvm_usize.get_bit_width(), "Expected usize integer value for argument `indices_size` to `call_ndarray_flatten_index_impl`" ); @@ -729,10 +733,10 @@ fn call_ndarray_flatten_index_impl<'ctx, G: CodeGenerator + ?Sized>( .build_call( ndarray_flatten_index_fn, &[ - ndarray_dims.as_ptr_value(ctx).into(), + ndarray_dims.base_ptr(ctx, generator).into(), ndarray_num_dims.into(), - indices.into(), - indices_size.into(), + indices.base_ptr(ctx, generator).into(), + indices.size(ctx, generator).into(), ], "", ) @@ -750,21 +754,21 @@ fn call_ndarray_flatten_index_impl<'ctx, G: CodeGenerator + ?Sized>( /// * `ndarray` - LLVM pointer to the `NDArray`. This value must be the LLVM representation of an /// `NDArray`. /// * `indices` - The multidimensional index to compute the flattened index for. -pub fn call_ndarray_flatten_index<'ctx, G: CodeGenerator + ?Sized>( - generator: &G, - ctx: &CodeGenContext<'ctx, '_>, +pub fn call_ndarray_flatten_index<'ctx, G, Index>( + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, ndarray: NDArrayValue<'ctx>, - indices: ListValue<'ctx>, -) -> IntValue<'ctx> { - let indices_size = indices.load_size(ctx, None); - let indices_data = indices.data(); + indices: &Index, +) -> IntValue<'ctx> + where + G: CodeGenerator + ?Sized, + Index: ArrayLikeIndexer<'ctx>, { call_ndarray_flatten_index_impl( generator, ctx, ndarray, - indices_data.as_ptr_value(ctx), - indices_size, + indices, ) } /// Generates a call to `__nac3_ndarray_flatten_index`. Returns the flattened index for the @@ -786,27 +790,27 @@ pub fn call_ndarray_flatten_index_const<'ctx, G: CodeGenerator + ?Sized>( ctx, indices.get_type().get_element_type(), llvm_usize.const_int(indices_size as u64, false), - None + None, ).unwrap(); for i in 0..indices_size { let v = ctx.builder.build_extract_value(indices, i, "") .unwrap() .into_int_value(); - let elem_ptr = unsafe { - ctx.builder.build_in_bounds_gep( - indices_alloca, - &[ctx.ctx.i32_type().const_int(i as u64, false)], - "" - ) - }.unwrap(); - ctx.builder.build_store(elem_ptr, v).unwrap(); + + unsafe { + indices_alloca.set_unchecked( + ctx, + generator, + ctx.ctx.i32_type().const_int(i as u64, false), + v.into(), + ); + } } call_ndarray_flatten_index_impl( generator, ctx, ndarray, - indices_alloca, - llvm_usize.const_int(indices_size as u64, false), + &indices_alloca, ) } \ No newline at end of file diff --git a/nac3core/src/codegen/numpy.rs b/nac3core/src/codegen/numpy.rs index ec06dad..92598eb 100644 --- a/nac3core/src/codegen/numpy.rs +++ b/nac3core/src/codegen/numpy.rs @@ -6,7 +6,14 @@ use inkwell::{ use nac3parser::ast::StrRef; use crate::{ codegen::{ - classes::{ListValue, NDArrayValue}, + classes::{ + ArrayLikeIndexer, + ArrayLikeValue, + ListValue, + NDArrayValue, + TypedArrayLikeAccessor, + UntypedArrayLikeAccessor, + }, CodeGenContext, CodeGenerator, irrt::{ @@ -109,7 +116,7 @@ fn create_ndarray_dyn_shape<'ctx, 'a, G, V, LenFn, DataFn>( .unwrap(); let ndarray_pdim = unsafe { - ndarray.dim_sizes().ptr_offset_unchecked(ctx, i, None) + ndarray.dim_sizes().ptr_offset_unchecked(ctx, generator, i, None) }; ctx.builder.build_store(ndarray_pdim, shape_dim).unwrap(); @@ -122,8 +129,7 @@ fn create_ndarray_dyn_shape<'ctx, 'a, G, V, LenFn, DataFn>( let ndarray_num_elems = call_ndarray_calc_size( generator, ctx, - ndarray.load_ndims(ctx), - ndarray.dim_sizes().as_ptr_value(ctx), + &ndarray.dim_sizes().as_slice_value(ctx, generator), ); ndarray.create_data(ctx, llvm_ndarray_data_t, ndarray_num_elems); @@ -193,12 +199,10 @@ fn create_ndarray_const_shape<'ctx, G: CodeGenerator + ?Sized>( ctx.builder.build_store(ndarray_dim, shape_dim).unwrap(); } - let ndarray_dims = ndarray.dim_sizes().as_ptr_value(ctx); let ndarray_num_elems = call_ndarray_calc_size( generator, ctx, - ndarray.load_ndims(ctx), - ndarray_dims, + &ndarray.dim_sizes().as_slice_value(ctx, generator), ); ndarray.create_data(ctx, llvm_ndarray_data_t, ndarray_num_elems); @@ -288,8 +292,7 @@ fn ndarray_fill_flattened<'ctx, 'a, G, ValueFn>( let ndarray_num_elems = call_ndarray_calc_size( generator, ctx, - ndarray.load_ndims(ctx), - ndarray.dim_sizes().as_ptr_value(ctx), + &ndarray.dim_sizes().as_slice_value(ctx, generator), ); gen_for_callback_incrementing( @@ -299,7 +302,7 @@ fn ndarray_fill_flattened<'ctx, 'a, G, ValueFn>( (ndarray_num_elems, false), |generator, ctx, i| { let elem = unsafe { - ndarray.data().ptr_to_data_flattened_unchecked(ctx, i, None) + ndarray.data().ptr_offset_unchecked(ctx, generator, i, None) }; let value = value_fn(generator, ctx, i)?; @@ -548,16 +551,15 @@ fn ndarray_copy_impl<'ctx, G: CodeGenerator + ?Sized>( |_, ctx, shape| { Ok(shape.load_ndims(ctx)) }, - |_, ctx, shape, idx| { - unsafe { Ok(shape.dim_sizes().get_unchecked(ctx, idx, None)) } + |generator, ctx, shape, idx| { + unsafe { Ok(shape.dim_sizes().get_typed_unchecked(ctx, generator, idx, None)) } }, )?; let len = call_ndarray_calc_size( generator, ctx, - ndarray.load_ndims(ctx), - ndarray.dim_sizes().as_ptr_value(ctx), + &ndarray.dim_sizes().as_slice_value(ctx, generator), ); let sizeof_ty = ctx.get_llvm_type(generator, elem_ty); let len_bytes = ctx.builder @@ -570,8 +572,8 @@ fn ndarray_copy_impl<'ctx, G: CodeGenerator + ?Sized>( call_memcpy_generic( ctx, - ndarray.data().as_ptr_value(ctx), - this.data().as_ptr_value(ctx), + ndarray.data().base_ptr(ctx, generator), + this.data().base_ptr(ctx, generator), len_bytes, llvm_i1.const_zero(), ); diff --git a/nac3core/src/codegen/stmt.rs b/nac3core/src/codegen/stmt.rs index 6ab20be..61018a3 100644 --- a/nac3core/src/codegen/stmt.rs +++ b/nac3core/src/codegen/stmt.rs @@ -6,7 +6,7 @@ use super::{ }; use crate::{ codegen::{ - classes::{ListValue, RangeValue}, + classes::{ArrayLikeIndexer, ArraySliceValue, ListValue, RangeValue}, expr::gen_binop_expr, gen_in_range_check, }, @@ -65,8 +65,8 @@ pub fn gen_array_var<'ctx, 'a, T: BasicType<'ctx>>( ctx: &mut CodeGenContext<'ctx, 'a>, ty: T, size: IntValue<'ctx>, - name: Option<&str>, -) -> Result, String> { + name: Option<&'ctx str>, +) -> Result, String> { // Restore debug location let di_loc = ctx.debug_info.0.create_debug_location( ctx.ctx, @@ -84,6 +84,7 @@ pub fn gen_array_var<'ctx, 'a, T: BasicType<'ctx>>( ctx.builder.set_current_debug_location(di_loc); let ptr = ctx.builder.build_array_alloca(ty, size, name.unwrap_or("")).unwrap(); + let ptr = ArraySliceValue::from_ptr_val(ptr, size, name); ctx.builder.position_at_end(current); ctx.builder.set_current_debug_location(di_loc);