From b461cdccb68c6e3028a1ffe6a8357fd60da7b68d Mon Sep 17 00:00:00 2001 From: David Mak Date: Thu, 21 Nov 2024 14:25:05 +0800 Subject: [PATCH] WIP --- nac3artiq/src/codegen.rs | 4 +- nac3core/src/codegen/expr.rs | 98 +++++- nac3core/src/codegen/irrt/mod.rs | 21 ++ nac3core/src/codegen/irrt/ndarray/basic.rs | 384 ++++++++++++++------- nac3core/src/codegen/numpy.rs | 4 +- nac3core/src/codegen/types/ndarray.rs | 8 +- nac3core/src/codegen/values/ndarray.rs | 123 ++++++- 7 files changed, 498 insertions(+), 144 deletions(-) diff --git a/nac3artiq/src/codegen.rs b/nac3artiq/src/codegen.rs index ff1aba1..dca6adb 100644 --- a/nac3artiq/src/codegen.rs +++ b/nac3artiq/src/codegen.rs @@ -735,7 +735,9 @@ fn format_rpc_ret<'ctx>( ); } - ndarray.create_data(ctx, llvm_elem_ty, num_elements); + unsafe { + ndarray.create_data(generator, ctx, llvm_elem_ty, num_elements); + } let ndarray_data = ndarray.data().base_ptr(ctx, generator); let ndarray_data_i8 = diff --git a/nac3core/src/codegen/expr.rs b/nac3core/src/codegen/expr.rs index 1f92075..f96693c 100644 --- a/nac3core/src/codegen/expr.rs +++ b/nac3core/src/codegen/expr.rs @@ -2858,7 +2858,9 @@ fn gen_ndarray_subscript_expr<'ctx, G: CodeGenerator>( .builder .build_int_z_extend_or_bit_cast(ndarray_num_elems, sizeof_elem.get_type(), "") .unwrap(); - ndarray.create_data(ctx, llvm_ndarray_data_t, ndarray_num_elems); + unsafe { + ndarray.create_data(generator, ctx, llvm_ndarray_data_t, ndarray_num_elems); + } let v_data_src_ptr = v.data().ptr_offset(ctx, generator, &index_addr, None); call_memcpy_generic( @@ -3604,3 +3606,97 @@ pub fn gen_expr<'ctx, G: CodeGenerator>( _ => unimplemented!(), })) } + +/// Creates a function in the current module and inserts a `call` instruction into the LLVM IR. +pub fn create_fn_and_call<'ctx>( + ctx: &CodeGenContext<'ctx, '_>, + fn_name: &str, + ret_type: Option>, + (params, is_var_args): (&[BasicTypeEnum<'ctx>], bool), + args: &[BasicValueEnum<'ctx>], + call_value_name: Option<&str>, + configure: Option<&dyn Fn(&FunctionValue<'ctx>)>, +) -> Option> { + let intrinsic_fn = ctx.module.get_function(fn_name).unwrap_or_else(|| { + let params = params.iter() + .copied() + .map(BasicTypeEnum::into) + .collect_vec(); + let fn_type = if let Some(ret_type) = ret_type { + ret_type.fn_type(params.as_slice(), is_var_args) + } else { + ctx.ctx.void_type().fn_type(params.as_slice(), is_var_args) + }; + + ctx.module.add_function(fn_name, fn_type, None) + }); + + if let Some(configure) = configure { + configure(&intrinsic_fn); + } + + let args = args.iter() + .copied() + .map(BasicValueEnum::into) + .collect_vec(); + ctx.builder + .build_call(intrinsic_fn, args.as_slice(), call_value_name.unwrap_or_default()) + .map(CallSiteValue::try_as_basic_value) + .map(Either::left) + .unwrap() +} + +/// Creates a function in the current module and inserts a `call` instruction into the LLVM IR. +/// +/// This is a wrapper around [`create_fn_and_call`] for non-vararg function. This function allows +/// parameters and arguments to be specified as tuples to better indicate the expected type and +/// actual value of each parameter-argument pair of the call. +pub fn create_and_call_function<'ctx>( + ctx: &CodeGenContext<'ctx, '_>, + fn_name: &str, + ret_type: Option>, + params: &[(BasicTypeEnum<'ctx>, BasicValueEnum<'ctx>)], + value_name: Option<&str>, + configure: Option<&dyn Fn(&FunctionValue<'ctx>)>, +) -> Option> { + let param_tys = params.iter().map(|(ty, _)| ty).copied().map(BasicTypeEnum::into).collect_vec(); + let arg_values = params.iter().map(|(_, value)| value).copied().map(BasicValueEnum::into).collect_vec(); + + create_fn_and_call( + ctx, + fn_name, + ret_type, + (param_tys.as_slice(), false), + arg_values.as_slice(), + value_name, + configure, + ) +} + +/// Creates a function in the current module and inserts a `call` instruction into the LLVM IR. +/// +/// This is a wrapper around [`create_fn_and_call`] for non-vararg function. This function allows +/// only arguments to be specified and performs inference for the parameter types using +/// [`BasicValueEnum::get_type`]. +pub fn infer_and_call_function<'ctx>( + ctx: &CodeGenContext<'ctx, '_>, + fn_name: &str, + ret_type: Option>, + args: &[BasicValueEnum<'ctx>], + value_name: Option<&str>, + configure: Option<&dyn Fn(&FunctionValue<'ctx>)>, +) -> Option> { + let param_tys = args.iter() + .map(BasicValueEnum::get_type) + .collect_vec(); + + create_fn_and_call( + ctx, + fn_name, + ret_type, + (param_tys.as_slice(), false), + args, + value_name, + configure, + ) +} diff --git a/nac3core/src/codegen/irrt/mod.rs b/nac3core/src/codegen/irrt/mod.rs index f6c4a1e..6361df2 100644 --- a/nac3core/src/codegen/irrt/mod.rs +++ b/nac3core/src/codegen/irrt/mod.rs @@ -60,6 +60,27 @@ pub fn load_irrt<'ctx>(ctx: &'ctx Context, symbol_resolver: &dyn SymbolResolver) irrt_mod } +/// Returns the name of a function which contains variants for 32-bit and 64-bit `size_t`. +/// +/// - When [`TypeContext::size_type`] is 32-bits, the function name is `fn_name}`. +/// - When [`TypeContext::size_type`] is 64-bits, the function name is `{fn_name}64`. +#[must_use] +pub fn get_usize_dependent_function_name( + generator: &mut G, + ctx: &CodeGenContext<'_, '_>, + name: &str, +) -> String { + let mut name = name.to_owned(); + match generator.get_size_type(ctx.ctx).get_bit_width() { + 32 => {} + 64 => name.push_str("64"), + bit_width => { + panic!("Unsupported int type bit width {bit_width}, must be either 32-bits or 64-bits") + } + } + name +} + /// NOTE: the output value of the end index of this function should be compared ***inclusively***, /// because python allows `a[2::-1]`, whose semantic is `[a[2], a[1], a[0]]`, which is equivalent to /// NO numeric slice in python. diff --git a/nac3core/src/codegen/irrt/ndarray/basic.rs b/nac3core/src/codegen/irrt/ndarray/basic.rs index e52031d..23e1afd 100644 --- a/nac3core/src/codegen/irrt/ndarray/basic.rs +++ b/nac3core/src/codegen/irrt/ndarray/basic.rs @@ -1,134 +1,258 @@ -use crate::codegen::{CodeGenContext, CodeGenerator}; +use inkwell::{ + values::{BasicValueEnum, IntValue, PointerValue}, + AddressSpace, +}; -/// Returns the name of a function which contains variants for 32-bit and 64-bit `size_t`. -/// -/// - When [`TypeContext::size_type`] is 32-bits, the function name is `fn_name}`. -/// - When [`TypeContext::size_type`] is 64-bits, the function name is `{fn_name}64`. -#[must_use] -pub fn get_usize_dependent_function_name( +use crate::codegen::{ + expr::create_and_call_function, + irrt::get_usize_dependent_function_name, + types::NDArrayType, + values::{NDArrayValue, ProxyValue}, + CodeGenContext, CodeGenerator, +}; + +pub fn call_nac3_ndarray_util_assert_shape_no_negative<'ctx, G: CodeGenerator + ?Sized>( generator: &mut G, - ctx: &CodeGenContext<'_, '_>, - name: &str, -) -> String { - let mut name = name.to_owned(); - match generator.get_size_type(ctx.ctx).get_bit_width() { - 32 => {} - 64 => name.push_str("64"), - bit_width => { - panic!("Unsupported int type bit width {bit_width}, must be either 32-bits or 64-bits") - } - } - name + ctx: &mut CodeGenContext<'ctx, '_>, + ndims: IntValue<'ctx>, + shape: PointerValue<'ctx>, +) { + let llvm_usize = generator.get_size_type(ctx.ctx); + let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default()); + + let name = get_usize_dependent_function_name( + generator, + ctx, + "__nac3_ndarray_util_assert_shape_no_negative", + ); + + create_and_call_function( + ctx, + &name, + Some(llvm_usize.into()), + &[(llvm_usize.into(), ndims.into()), (llvm_pusize.into(), shape.into())], + None, + None, + ); } -// pub fn call_nac3_ndarray_util_assert_shape_no_negative<'ctx, G: CodeGenerator + ?Sized>( -// generator: &mut G, -// ctx: &mut CodeGenContext<'ctx, '_>, -// ndims: Instance<'ctx, Int>, -// shape: Instance<'ctx, Ptr>>, -// ) { -// let name = get_usize_dependent_function_name( -// generator, -// ctx, -// "__nac3_ndarray_util_assert_shape_no_negative", -// ); -// FnCall::builder(generator, ctx, &name).arg(ndims).arg(shape).returning_void(); -// } -// -// pub fn call_nac3_ndarray_util_assert_output_shape_same<'ctx, G: CodeGenerator + ?Sized>( -// generator: &mut G, -// ctx: &mut CodeGenContext<'ctx, '_>, -// ndarray_ndims: Instance<'ctx, Int>, -// ndarray_shape: Instance<'ctx, Ptr>>, -// output_ndims: Instance<'ctx, Int>, -// output_shape: Instance<'ctx, Ptr>>, -// ) { -// let name = get_usize_dependent_function_name( -// generator, -// ctx, -// "__nac3_ndarray_util_assert_output_shape_same", -// ); -// FnCall::builder(generator, ctx, &name) -// .arg(ndarray_ndims) -// .arg(ndarray_shape) -// .arg(output_ndims) -// .arg(output_shape) -// .returning_void(); -// } -// -// pub fn call_nac3_ndarray_size<'ctx, G: CodeGenerator + ?Sized>( -// generator: &mut G, -// ctx: &mut CodeGenContext<'ctx, '_>, -// ndarray: Instance<'ctx, Ptr>>, -// ) -> Instance<'ctx, Int> { -// let name = get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_size"); -// FnCall::builder(generator, ctx, &name).arg(ndarray).returning_auto("size") -// } -// -// pub fn call_nac3_ndarray_nbytes<'ctx, G: CodeGenerator + ?Sized>( -// generator: &mut G, -// ctx: &mut CodeGenContext<'ctx, '_>, -// ndarray: Instance<'ctx, Ptr>>, -// ) -> Instance<'ctx, Int> { -// let name = get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_nbytes"); -// FnCall::builder(generator, ctx, &name).arg(ndarray).returning_auto("nbytes") -// } -// -// pub fn call_nac3_ndarray_len<'ctx, G: CodeGenerator + ?Sized>( -// generator: &mut G, -// ctx: &mut CodeGenContext<'ctx, '_>, -// ndarray: Instance<'ctx, Ptr>>, -// ) -> Instance<'ctx, Int> { -// let name = get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_len"); -// FnCall::builder(generator, ctx, &name).arg(ndarray).returning_auto("len") -// } -// -// pub fn call_nac3_ndarray_is_c_contiguous<'ctx, G: CodeGenerator + ?Sized>( -// generator: &mut G, -// ctx: &mut CodeGenContext<'ctx, '_>, -// ndarray: Instance<'ctx, Ptr>>, -// ) -> Instance<'ctx, Int> { -// let name = get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_is_c_contiguous"); -// FnCall::builder(generator, ctx, &name).arg(ndarray).returning_auto("is_c_contiguous") -// } -// -// pub fn call_nac3_ndarray_get_nth_pelement<'ctx, G: CodeGenerator + ?Sized>( -// generator: &mut G, -// ctx: &mut CodeGenContext<'ctx, '_>, -// ndarray: Instance<'ctx, Ptr>>, -// index: Instance<'ctx, Int>, -// ) -> Instance<'ctx, Ptr>> { -// let name = get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_get_nth_pelement"); -// FnCall::builder(generator, ctx, &name).arg(ndarray).arg(index).returning_auto("pelement") -// } -// -// pub fn call_nac3_ndarray_get_pelement_by_indices<'ctx, G: CodeGenerator + ?Sized>( -// generator: &mut G, -// ctx: &mut CodeGenContext<'ctx, '_>, -// ndarray: Instance<'ctx, Ptr>>, -// indices: Instance<'ctx, Ptr>>, -// ) -> Instance<'ctx, Ptr>> { -// let name = -// get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_get_pelement_by_indices"); -// FnCall::builder(generator, ctx, &name).arg(ndarray).arg(indices).returning_auto("pelement") -// } -// -// pub fn call_nac3_ndarray_set_strides_by_shape<'ctx, G: CodeGenerator + ?Sized>( -// generator: &mut G, -// ctx: &mut CodeGenContext<'ctx, '_>, -// ndarray: Instance<'ctx, Ptr>>, -// ) { -// let name = -// get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_set_strides_by_shape"); -// FnCall::builder(generator, ctx, &name).arg(ndarray).returning_void(); -// } -// -// pub fn call_nac3_ndarray_copy_data<'ctx, G: CodeGenerator + ?Sized>( -// generator: &mut G, -// ctx: &mut CodeGenContext<'ctx, '_>, -// src_ndarray: Instance<'ctx, Ptr>>, -// dst_ndarray: Instance<'ctx, Ptr>>, -// ) { -// let name = get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_copy_data"); -// FnCall::builder(generator, ctx, &name).arg(src_ndarray).arg(dst_ndarray).returning_void(); -// } +pub fn call_nac3_ndarray_util_assert_output_shape_same<'ctx, G: CodeGenerator + ?Sized>( + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + ndarray_ndims: IntValue<'ctx>, + ndarray_shape: PointerValue<'ctx>, + output_ndims: IntValue<'ctx>, + output_shape: IntValue<'ctx>, +) { + let llvm_usize = generator.get_size_type(ctx.ctx); + let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default()); + + let name = get_usize_dependent_function_name( + generator, + ctx, + "__nac3_ndarray_util_assert_output_shape_same", + ); + + create_and_call_function( + ctx, + &name, + Some(llvm_usize.into()), + &[ + (llvm_usize.into(), ndarray_ndims.into()), + (llvm_pusize.into(), ndarray_shape.into()), + (llvm_usize.into(), output_ndims.into()), + (llvm_pusize.into(), output_shape.into()), + ], + None, + None, + ); +} + +pub fn call_nac3_ndarray_size<'ctx, G: CodeGenerator + ?Sized>( + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + ndarray: NDArrayValue<'ctx>, +) -> IntValue<'ctx> { + let llvm_usize = generator.get_size_type(ctx.ctx); + let llvm_ndarray = NDArrayType::llvm_type(ctx.ctx, llvm_usize); + + let name = get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_size"); + + create_and_call_function( + ctx, + &name, + Some(llvm_usize.into()), + &[(llvm_ndarray.into(), ndarray.as_base_value().into())], + Some("size"), + None, + ) + .map(BasicValueEnum::into_int_value) + .unwrap() +} + +pub fn call_nac3_ndarray_nbytes<'ctx, G: CodeGenerator + ?Sized>( + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + ndarray: NDArrayValue<'ctx>, +) -> IntValue<'ctx> { + let llvm_usize = generator.get_size_type(ctx.ctx); + let llvm_ndarray = NDArrayType::llvm_type(ctx.ctx, llvm_usize); + + let name = get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_nbytes"); + + create_and_call_function( + ctx, + &name, + Some(llvm_usize.into()), + &[(llvm_ndarray.into(), ndarray.as_base_value().into())], + Some("nbytes"), + None, + ) + .map(BasicValueEnum::into_int_value) + .unwrap() +} + +pub fn call_nac3_ndarray_len<'ctx, G: CodeGenerator + ?Sized>( + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + ndarray: NDArrayValue<'ctx>, +) -> IntValue<'ctx> { + let llvm_usize = generator.get_size_type(ctx.ctx); + let llvm_ndarray = NDArrayType::llvm_type(ctx.ctx, llvm_usize); + + let name = get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_len"); + + create_and_call_function( + ctx, + &name, + Some(llvm_usize.into()), + &[(llvm_ndarray.into(), ndarray.as_base_value().into())], + Some("len"), + None, + ) + .map(BasicValueEnum::into_int_value) + .unwrap() +} + +pub fn call_nac3_ndarray_is_c_contiguous<'ctx, G: CodeGenerator + ?Sized>( + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + ndarray: NDArrayValue<'ctx>, +) -> IntValue<'ctx> { + let llvm_i1 = ctx.ctx.bool_type(); + let llvm_usize = generator.get_size_type(ctx.ctx); + let llvm_ndarray = NDArrayType::llvm_type(ctx.ctx, llvm_usize); + + let name = get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_is_c_contiguous"); + + create_and_call_function( + ctx, + &name, + Some(llvm_i1.into()), + &[(llvm_ndarray.into(), ndarray.as_base_value().into())], + Some("is_c_contiguous"), + None, + ) + .map(BasicValueEnum::into_int_value) + .unwrap() +} + +pub fn call_nac3_ndarray_get_nth_pelement<'ctx, G: CodeGenerator + ?Sized>( + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + ndarray: NDArrayValue<'ctx>, + index: IntValue<'ctx>, +) -> PointerValue<'ctx> { + let llvm_i8 = ctx.ctx.i8_type(); + let llvm_pi8 = llvm_i8.ptr_type(AddressSpace::default()); + let llvm_usize = generator.get_size_type(ctx.ctx); + let llvm_ndarray = NDArrayType::llvm_type(ctx.ctx, llvm_usize); + + let name = get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_get_nth_pelement"); + + create_and_call_function( + ctx, + &name, + Some(llvm_pi8.into()), + &[(llvm_ndarray.into(), ndarray.as_base_value().into()), (llvm_usize.into(), index.into())], + Some("pelement"), + None, + ) + .map(BasicValueEnum::into_pointer_value) + .unwrap() +} + +pub fn call_nac3_ndarray_get_pelement_by_indices<'ctx, G: CodeGenerator + ?Sized>( + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + ndarray: NDArrayValue<'ctx>, + indices: PointerValue<'ctx>, +) -> PointerValue<'ctx> { + let llvm_i8 = ctx.ctx.i8_type(); + let llvm_pi8 = llvm_i8.ptr_type(AddressSpace::default()); + let llvm_usize = generator.get_size_type(ctx.ctx); + let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default()); + let llvm_ndarray = NDArrayType::llvm_type(ctx.ctx, llvm_usize); + + let name = + get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_get_pelement_by_indices"); + + create_and_call_function( + ctx, + &name, + Some(llvm_pi8.into()), + &[ + (llvm_ndarray.into(), ndarray.as_base_value().into()), + (llvm_pusize.into(), indices.into()), + ], + Some("pelement"), + None, + ) + .map(BasicValueEnum::into_pointer_value) + .unwrap() +} + +pub fn call_nac3_ndarray_set_strides_by_shape<'ctx, G: CodeGenerator + ?Sized>( + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + ndarray: NDArrayValue<'ctx>, +) { + let llvm_usize = generator.get_size_type(ctx.ctx); + let llvm_ndarray = NDArrayType::llvm_type(ctx.ctx, llvm_usize); + + let name = + get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_set_strides_by_shape"); + + create_and_call_function( + ctx, + &name, + None, + &[(llvm_ndarray.into(), ndarray.as_base_value().into())], + None, + None, + ); +} + +pub fn call_nac3_ndarray_copy_data<'ctx, G: CodeGenerator + ?Sized>( + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + src_ndarray: NDArrayValue<'ctx>, + dst_ndarray: NDArrayValue<'ctx>, +) { + let llvm_usize = generator.get_size_type(ctx.ctx); + let llvm_ndarray = NDArrayType::llvm_type(ctx.ctx, llvm_usize); + + let name = get_usize_dependent_function_name(generator, ctx, "__nac3_ndarray_copy_data"); + + create_and_call_function( + ctx, + &name, + None, + &[ + (llvm_ndarray.into(), src_ndarray.as_base_value().into()), + (llvm_ndarray.into(), dst_ndarray.as_base_value().into()), + ], + None, + None, + ); +} diff --git a/nac3core/src/codegen/numpy.rs b/nac3core/src/codegen/numpy.rs index 92bab80..8f7eaca 100644 --- a/nac3core/src/codegen/numpy.rs +++ b/nac3core/src/codegen/numpy.rs @@ -212,7 +212,9 @@ fn ndarray_init_data<'ctx, G: CodeGenerator + ?Sized>( &ndarray.shape().as_slice_value(ctx, generator), (None, None), ); - ndarray.create_data(ctx, llvm_ndarray_data_t, ndarray_num_elems); + unsafe { + ndarray.create_data(generator, ctx, llvm_ndarray_data_t, ndarray_num_elems); + } ndarray } diff --git a/nac3core/src/codegen/types/ndarray.rs b/nac3core/src/codegen/types/ndarray.rs index 9675313..9f94d0c 100644 --- a/nac3core/src/codegen/types/ndarray.rs +++ b/nac3core/src/codegen/types/ndarray.rs @@ -103,7 +103,7 @@ impl<'ctx> NDArrayType<'ctx> { /// Creates an LLVM type corresponding to the expected structure of an `NDArray`. #[must_use] - fn llvm_type(ctx: &'ctx Context, llvm_usize: IntType<'ctx>) -> PointerType<'ctx> { + pub fn llvm_type(ctx: &'ctx Context, llvm_usize: IntType<'ctx>) -> PointerType<'ctx> { // struct NDArray { data: i8*, itemsize: size_t, ndims: size_t, shape: size_t*, strides: size_t* } // // * data : Pointer to an array containing the array data @@ -142,11 +142,7 @@ impl<'ctx> NDArrayType<'ctx> { let llvm_dtype = ctx.get_llvm_type(generator, dtype); let llvm_usize = generator.get_size_type(ctx.ctx); - NDArrayType { - ty: Self::llvm_type(ctx.ctx, llvm_usize), - dtype: llvm_dtype, - llvm_usize, - } + NDArrayType { ty: Self::llvm_type(ctx.ctx, llvm_usize), dtype: llvm_dtype, llvm_usize } } /// Creates an [`NDArrayType`] from a [`PointerType`] representing an `NDArray`. diff --git a/nac3core/src/codegen/values/ndarray.rs b/nac3core/src/codegen/values/ndarray.rs index 96c03c4..23da965 100644 --- a/nac3core/src/codegen/values/ndarray.rs +++ b/nac3core/src/codegen/values/ndarray.rs @@ -184,8 +184,15 @@ impl<'ctx> NDArrayValue<'ctx> { /// Convenience method for creating a new array storing data elements with the given element /// type `elem_ty` and `size`. - pub fn create_data( + /// + /// The data buffer will be allocated on the stack, and is considered to be owned by this ndarray instance. + /// + /// # Safety + /// + /// `shape` and `itemsize` of the ndarray must be initialized. + pub unsafe fn create_data( &self, + generator: &mut G, ctx: &CodeGenContext<'ctx, '_>, elem_ty: BasicTypeEnum<'ctx>, size: IntValue<'ctx>, @@ -195,10 +202,10 @@ impl<'ctx> NDArrayValue<'ctx> { let nbytes = ctx.builder.build_int_mul(size, itemsize, "").unwrap(); // TODO: What about alignment? - self.store_data( - ctx, - ctx.builder.build_array_alloca(ctx.ctx.i8_type(), nbytes, "").unwrap(), - ); + let data = ctx.builder.build_array_alloca(ctx.ctx.i8_type(), nbytes, "").unwrap(); + self.store_data(ctx, data); + + // self.set_strides_contiguous(generator, ctx); } /// Returns a proxy object to the field storing the data of this `NDArray`. @@ -206,6 +213,112 @@ impl<'ctx> NDArrayValue<'ctx> { pub fn data(&self) -> NDArrayDataProxy<'ctx, '_> { NDArrayDataProxy(self) } + + /// Copy shape dimensions from an array. + pub fn copy_shape_from_array( + &self, + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + shape: PointerValue<'ctx>, + ) { + todo!() + } + + /// Copy shape dimensions from an ndarray. + /// Panics if `ndims` mismatches. + pub fn copy_shape_from_ndarray( + &self, + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + src_ndarray: NDArrayValue<'ctx>, + ) { + todo!() + } + + /// Copy strides dimensions from an array. + pub fn copy_strides_from_array( + &self, + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + strides: PointerValue<'ctx>, + ) { + todo!() + } + + /// Copy strides dimensions from an ndarray. + /// Panics if `ndims` mismatches. + pub fn copy_strides_from_ndarray( + &self, + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + src_ndarray: NDArrayValue<'ctx>, + ) { + todo!() + } + + /// Get the `np.size()` of this ndarray. + pub fn size( + &self, + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + ) -> IntValue<'ctx> { + todo!() + } + + /// Get the `ndarray.nbytes` of this ndarray. + pub fn nbytes( + &self, + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + ) -> IntValue<'ctx> { + todo!() + } + + /// Get the `len()` of this ndarray. + pub fn len( + &self, + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + ) -> IntValue<'ctx> { + todo!() + } + + /// Check if this ndarray is C-contiguous. + /// + /// See NumPy's `flags["C_CONTIGUOUS"]`: + pub fn is_c_contiguous( + &self, + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + ) -> IntValue<'ctx> { + todo!() + } + + /// Call [`call_nac3_ndarray_set_strides_by_shape`] on this ndarray to update `strides`. + /// + /// Update the ndarray's strides to make the ndarray contiguous. + pub fn set_strides_contiguous( + self, + generator: &mut G, + ctx: &CodeGenContext<'ctx, '_>, + ) { + todo!() + } + + /// Copy data from another ndarray. + /// + /// This ndarray and `src` is that their `np.size()` should be the same. Their shapes + /// do not matter. The copying order is determined by how their flattened views look. + /// + /// Panics if the `dtype`s of ndarrays are different. + pub fn copy_data_from( + &self, + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + src: NDArrayValue<'ctx>, + ) { + todo!() + } } impl<'ctx> ProxyValue<'ctx> for NDArrayValue<'ctx> {