forked from M-Labs/nac3
1
0
Fork 0

Compare commits

..

9 Commits

Author SHA1 Message Date
lyken 87d2a4ed59 WIP 2024-07-10 17:27:10 +08:00
lyken 9aae290727 core: irrt general numpy broadcasting 2024-07-10 17:05:01 +08:00
lyken d18c769cdc core: irrt general numpy slicing 2024-07-10 14:05:08 +08:00
lyken f41f06aec7 core: more irrt 2024-07-10 11:56:31 +08:00
lyken 1303265785 core: build.rs rewrite regex to capture `= type` 2024-07-10 10:17:45 +08:00
lyken e9cf6ce1e5 core: move irrt c++ sources to /nac3core/irrt 2024-07-10 10:17:45 +08:00
lyken bc91ab9b13 core: IRRT -Werror=return-type 2024-07-10 10:17:43 +08:00
lyken 1e06a3d199 core: add irrt_test 2024-07-10 10:11:07 +08:00
lyken 87511ac749 core: comment out numpy 2024-07-10 10:05:07 +08:00
12 changed files with 566 additions and 989 deletions

View File

@ -212,11 +212,11 @@ namespace {
return this->size() * itemsize; return this->size() * itemsize;
} }
void set_pelement_value(uint8_t* pelement, const uint8_t* pvalue) { void set_value_at_pelement(uint8_t* pelement, const uint8_t* pvalue) {
__builtin_memcpy(pelement, pvalue, itemsize); __builtin_memcpy(pelement, pvalue, itemsize);
} }
uint8_t* get_pelement_by_indices(const SizeT *indices) { uint8_t* get_pelement(const SizeT *indices) {
uint8_t* element = data; uint8_t* element = data;
for (SizeT dim_i = 0; dim_i < ndims; dim_i++) for (SizeT dim_i = 0; dim_i < ndims; dim_i++)
element += indices[dim_i] * strides[dim_i]; element += indices[dim_i] * strides[dim_i];
@ -229,7 +229,7 @@ namespace {
SizeT* indices = (SizeT*) __builtin_alloca(sizeof(SizeT) * this->ndims); SizeT* indices = (SizeT*) __builtin_alloca(sizeof(SizeT) * this->ndims);
ndarray_util::set_indices_by_nth(this->ndims, this->shape, indices, nth); ndarray_util::set_indices_by_nth(this->ndims, this->shape, indices, nth);
return get_pelement_by_indices(indices); return get_pelement(indices);
} }
// Get pointer to the first element of this ndarray, assuming // Get pointer to the first element of this ndarray, assuming
@ -259,8 +259,8 @@ namespace {
iter.set_indices_zero(); iter.set_indices_zero();
for (SizeT i = 0; i < this->size(); i++, iter.next()) { for (SizeT i = 0; i < this->size(); i++, iter.next()) {
uint8_t* pelement = get_pelement_by_indices(iter.indices); uint8_t* pelement = get_pelement(iter.indices);
set_pelement_value(pelement, pvalue); set_value_at_pelement(pelement, pvalue);
} }
} }
@ -283,8 +283,8 @@ namespace {
if (!in_bounds(indices)) continue; if (!in_bounds(indices)) continue;
uint8_t* pelement = get_pelement_by_indices(indices); uint8_t* pelement = get_pelement(indices);
set_pelement_value(pelement, one_pvalue); set_value_at_pelement(pelement, one_pvalue);
} }
} }
@ -435,9 +435,9 @@ namespace {
}; };
const SizeT this_size = this->size(); const SizeT this_size = this->size();
for (SizeT i = 0; i < this_size; i++, iter.next()) { for (SizeT i = 0; i < this_size; i++, iter.next()) {
uint8_t* src_pelement = broadcasted_src_ndarray_strides->get_pelement_by_indices(indices); uint8_t* src_pelement = broadcasted_src_ndarray_strides->get_pelement(indices);
uint8_t* this_pelement = this->get_pelement_by_indices(indices); uint8_t* this_pelement = this->get_pelement(indices);
this->set_pelement_value(src_pelement, src_pelement); this->set_value_at_pelement(src_pelement, src_pelement);
} }
} }
}; };

View File

@ -81,7 +81,7 @@ void __print_ndarray_aux(const char *format, bool first, bool last, SizeT* curso
SizeT* indices = (SizeT*) __builtin_alloca(sizeof(SizeT) * ndarray->ndims); SizeT* indices = (SizeT*) __builtin_alloca(sizeof(SizeT) * ndarray->ndims);
for (SizeT i = 0; i < dim; i++) { for (SizeT i = 0; i < dim; i++) {
ndarray_util::set_indices_by_nth(ndarray->ndims, ndarray->shape, indices, *cursor); ndarray_util::set_indices_by_nth(ndarray->ndims, ndarray->shape, indices, *cursor);
ElementT* pelement = (ElementT*) ndarray->get_pelement_by_indices(indices); ElementT* pelement = (ElementT*) ndarray->get_pelement(indices);
ElementT element = *pelement; ElementT element = *pelement;
if (i != 0) printf(", "); // List delimiter if (i != 0) printf(", "); // List delimiter
@ -394,10 +394,10 @@ void test_ndslice_1() {
assert_arrays_match("shape", "%d", dst_ndims, expected_shape, dst_ndarray.shape); assert_arrays_match("shape", "%d", dst_ndims, expected_shape, dst_ndarray.shape);
assert_arrays_match("strides", "%d", dst_ndims, expected_strides, dst_ndarray.strides); assert_arrays_match("strides", "%d", dst_ndims, expected_strides, dst_ndarray.strides);
assert_values_match("dst_ndarray[0, 0]", "%f", 5.0, *((double *) dst_ndarray.get_pelement_by_indices((int32_t[dst_ndims]) { 0, 0 }))); assert_values_match("dst_ndarray[0, 0]", "%f", 5.0, *((double *) dst_ndarray.get_pelement((int32_t[dst_ndims]) { 0, 0 })));
assert_values_match("dst_ndarray[0, 1]", "%f", 7.0, *((double *) dst_ndarray.get_pelement_by_indices((int32_t[dst_ndims]) { 0, 1 }))); assert_values_match("dst_ndarray[0, 1]", "%f", 7.0, *((double *) dst_ndarray.get_pelement((int32_t[dst_ndims]) { 0, 1 })));
assert_values_match("dst_ndarray[1, 0]", "%f", 9.0, *((double *) dst_ndarray.get_pelement_by_indices((int32_t[dst_ndims]) { 1, 0 }))); assert_values_match("dst_ndarray[1, 0]", "%f", 9.0, *((double *) dst_ndarray.get_pelement((int32_t[dst_ndims]) { 1, 0 })));
assert_values_match("dst_ndarray[1, 1]", "%f", 11.0, *((double *) dst_ndarray.get_pelement_by_indices((int32_t[dst_ndims]) { 1, 1 }))); assert_values_match("dst_ndarray[1, 1]", "%f", 11.0, *((double *) dst_ndarray.get_pelement((int32_t[dst_ndims]) { 1, 1 })));
} }
void test_ndslice_2() { void test_ndslice_2() {
@ -471,8 +471,8 @@ void test_ndslice_2() {
assert_arrays_match("strides", "%d", dst_ndims, expected_strides, dst_ndarray.strides); assert_arrays_match("strides", "%d", dst_ndims, expected_strides, dst_ndarray.strides);
// [5.0, 3.0] // [5.0, 3.0]
assert_values_match("dst_ndarray[0]", "%f", 11.0, *((double *) dst_ndarray.get_pelement_by_indices((int32_t[dst_ndims]) { 0 }))); assert_values_match("dst_ndarray[0]", "%f", 11.0, *((double *) dst_ndarray.get_pelement((int32_t[dst_ndims]) { 0 })));
assert_values_match("dst_ndarray[1]", "%f", 9.0, *((double *) dst_ndarray.get_pelement_by_indices((int32_t[dst_ndims]) { 1 }))); assert_values_match("dst_ndarray[1]", "%f", 9.0, *((double *) dst_ndarray.get_pelement((int32_t[dst_ndims]) { 1 })));
} }
void test_can_broadcast_shape() { void test_can_broadcast_shape() {
@ -618,15 +618,24 @@ void test_ndarray_broadcast_1() {
assert_arrays_match("dst_ndarray->strides", "%d", dst_ndims, (int32_t[]) { 0, 0, 8 }, dst_ndarray.strides); assert_arrays_match("dst_ndarray->strides", "%d", dst_ndims, (int32_t[]) { 0, 0, 8 }, dst_ndarray.strides);
assert_values_match("dst_ndarray[0, 0, 0]", "%f", 19.9, *((double*) dst_ndarray.get_pelement_by_indices((int32_t[]) {0, 0, 0}))); assert_values_match("dst_ndarray[0, 0, 0]", "%f", 19.9, *((double*) dst_ndarray.get_pelement((int32_t[]) {0, 0, 0})));
assert_values_match("dst_ndarray[0, 0, 1]", "%f", 29.9, *((double*) dst_ndarray.get_pelement_by_indices((int32_t[]) {0, 0, 1}))); assert_values_match("dst_ndarray[0, 0, 1]", "%f", 29.9, *((double*) dst_ndarray.get_pelement((int32_t[]) {0, 0, 1})));
assert_values_match("dst_ndarray[0, 0, 2]", "%f", 39.9, *((double*) dst_ndarray.get_pelement_by_indices((int32_t[]) {0, 0, 2}))); assert_values_match("dst_ndarray[0, 0, 2]", "%f", 39.9, *((double*) dst_ndarray.get_pelement((int32_t[]) {0, 0, 2})));
assert_values_match("dst_ndarray[0, 0, 3]", "%f", 49.9, *((double*) dst_ndarray.get_pelement_by_indices((int32_t[]) {0, 0, 3}))); assert_values_match("dst_ndarray[0, 0, 3]", "%f", 49.9, *((double*) dst_ndarray.get_pelement((int32_t[]) {0, 0, 3})));
assert_values_match("dst_ndarray[0, 1, 0]", "%f", 19.9, *((double*) dst_ndarray.get_pelement_by_indices((int32_t[]) {0, 1, 0}))); assert_values_match("dst_ndarray[0, 1, 0]", "%f", 19.9, *((double*) dst_ndarray.get_pelement((int32_t[]) {0, 1, 0})));
assert_values_match("dst_ndarray[0, 1, 1]", "%f", 29.9, *((double*) dst_ndarray.get_pelement_by_indices((int32_t[]) {0, 1, 1}))); assert_values_match("dst_ndarray[0, 1, 1]", "%f", 29.9, *((double*) dst_ndarray.get_pelement((int32_t[]) {0, 1, 1})));
assert_values_match("dst_ndarray[0, 1, 2]", "%f", 39.9, *((double*) dst_ndarray.get_pelement_by_indices((int32_t[]) {0, 1, 2}))); assert_values_match("dst_ndarray[0, 1, 2]", "%f", 39.9, *((double*) dst_ndarray.get_pelement((int32_t[]) {0, 1, 2})));
assert_values_match("dst_ndarray[0, 1, 3]", "%f", 49.9, *((double*) dst_ndarray.get_pelement_by_indices((int32_t[]) {0, 1, 3}))); assert_values_match("dst_ndarray[0, 1, 3]", "%f", 49.9, *((double*) dst_ndarray.get_pelement((int32_t[]) {0, 1, 3})));
assert_values_match("dst_ndarray[1, 2, 3]", "%f", 49.9, *((double*) dst_ndarray.get_pelement_by_indices((int32_t[]) {1, 2, 3}))); assert_values_match("dst_ndarray[1, 2, 3]", "%f", 49.9, *((double*) dst_ndarray.get_pelement((int32_t[]) {1, 2, 3})));
}
void test_assign_with() {
/*
```
xs = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]], dtype=np.float64)
ys = xs.shape
```
*/
} }
int main() { int main() {
@ -644,5 +653,6 @@ int main() {
test_ndslice_2(); test_ndslice_2();
test_can_broadcast_shape(); test_can_broadcast_shape();
test_ndarray_broadcast_1(); test_ndarray_broadcast_1();
test_assign_with();
return 0; return 0;
} }

View File

@ -702,54 +702,53 @@ pub fn call_numpy_min<'ctx, G: CodeGenerator + ?Sized>(
BasicValueEnum::PointerValue(n) BasicValueEnum::PointerValue(n)
if a_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id()) => if a_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id()) =>
{ {
todo!() let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, a_ty);
// let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, a_ty); let llvm_ndarray_ty = ctx.get_llvm_type(generator, elem_ty);
// let llvm_ndarray_ty = ctx.get_llvm_type(generator, elem_ty);
// let n = NDArrayValue::from_ptr_val(n, llvm_usize, None); let n = NDArrayValue::from_ptr_val(n, llvm_usize, None);
// let n_sz = irrt::call_ndarray_calc_size(generator, ctx, &n.dim_sizes(), (None, None)); let n_sz = irrt::call_ndarray_calc_size(generator, ctx, &n.dim_sizes(), (None, None));
// if ctx.registry.llvm_options.opt_level == OptimizationLevel::None { if ctx.registry.llvm_options.opt_level == OptimizationLevel::None {
// let n_sz_eqz = ctx let n_sz_eqz = ctx
// .builder .builder
// .build_int_compare(IntPredicate::NE, n_sz, n_sz.get_type().const_zero(), "") .build_int_compare(IntPredicate::NE, n_sz, n_sz.get_type().const_zero(), "")
// .unwrap(); .unwrap();
// ctx.make_assert( ctx.make_assert(
// generator, generator,
// n_sz_eqz, n_sz_eqz,
// "0:ValueError", "0:ValueError",
// "zero-size array to reduction operation minimum which has no identity", "zero-size array to reduction operation minimum which has no identity",
// [None, None, None], [None, None, None],
// ctx.current_loc, ctx.current_loc,
// ); );
// } }
// let accumulator_addr = generator.gen_var_alloc(ctx, llvm_ndarray_ty, None)?; let accumulator_addr = generator.gen_var_alloc(ctx, llvm_ndarray_ty, None)?;
// unsafe { unsafe {
// let identity = let identity =
// n.data().get_unchecked(ctx, generator, &llvm_usize.const_zero(), None); n.data().get_unchecked(ctx, generator, &llvm_usize.const_zero(), None);
// ctx.builder.build_store(accumulator_addr, identity).unwrap(); ctx.builder.build_store(accumulator_addr, identity).unwrap();
// } }
// gen_for_callback_incrementing( gen_for_callback_incrementing(
// generator, generator,
// ctx, ctx,
// llvm_usize.const_int(1, false), llvm_usize.const_int(1, false),
// (n_sz, false), (n_sz, false),
// |generator, ctx, _, idx| { |generator, ctx, _, idx| {
// let elem = unsafe { n.data().get_unchecked(ctx, generator, &idx, None) }; let elem = unsafe { n.data().get_unchecked(ctx, generator, &idx, None) };
// let accumulator = ctx.builder.build_load(accumulator_addr, "").unwrap(); let accumulator = ctx.builder.build_load(accumulator_addr, "").unwrap();
// let result = call_min(ctx, (elem_ty, accumulator), (elem_ty, elem)); let result = call_min(ctx, (elem_ty, accumulator), (elem_ty, elem));
// ctx.builder.build_store(accumulator_addr, result).unwrap(); ctx.builder.build_store(accumulator_addr, result).unwrap();
// Ok(()) Ok(())
// }, },
// llvm_usize.const_int(1, false), llvm_usize.const_int(1, false),
// )?; )?;
// let accumulator = ctx.builder.build_load(accumulator_addr, "").unwrap(); let accumulator = ctx.builder.build_load(accumulator_addr, "").unwrap();
// accumulator accumulator
} }
_ => unsupported_type(ctx, FN_NAME, &[a_ty]), _ => unsupported_type(ctx, FN_NAME, &[a_ty]),
@ -921,54 +920,53 @@ pub fn call_numpy_max<'ctx, G: CodeGenerator + ?Sized>(
BasicValueEnum::PointerValue(n) BasicValueEnum::PointerValue(n)
if a_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id()) => if a_ty.obj_id(&ctx.unifier).is_some_and(|id| id == PrimDef::NDArray.id()) =>
{ {
todo!() let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, a_ty);
// let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, a_ty); let llvm_ndarray_ty = ctx.get_llvm_type(generator, elem_ty);
// let llvm_ndarray_ty = ctx.get_llvm_type(generator, elem_ty);
// let n = NDArrayValue::from_ptr_val(n, llvm_usize, None); let n = NDArrayValue::from_ptr_val(n, llvm_usize, None);
// let n_sz = irrt::call_ndarray_calc_size(generator, ctx, &n.dim_sizes(), (None, None)); let n_sz = irrt::call_ndarray_calc_size(generator, ctx, &n.dim_sizes(), (None, None));
// if ctx.registry.llvm_options.opt_level == OptimizationLevel::None { if ctx.registry.llvm_options.opt_level == OptimizationLevel::None {
// let n_sz_eqz = ctx let n_sz_eqz = ctx
// .builder .builder
// .build_int_compare(IntPredicate::NE, n_sz, n_sz.get_type().const_zero(), "") .build_int_compare(IntPredicate::NE, n_sz, n_sz.get_type().const_zero(), "")
// .unwrap(); .unwrap();
// ctx.make_assert( ctx.make_assert(
// generator, generator,
// n_sz_eqz, n_sz_eqz,
// "0:ValueError", "0:ValueError",
// "zero-size array to reduction operation minimum which has no identity", "zero-size array to reduction operation minimum which has no identity",
// [None, None, None], [None, None, None],
// ctx.current_loc, ctx.current_loc,
// ); );
// } }
// let accumulator_addr = generator.gen_var_alloc(ctx, llvm_ndarray_ty, None)?; let accumulator_addr = generator.gen_var_alloc(ctx, llvm_ndarray_ty, None)?;
// unsafe { unsafe {
// let identity = let identity =
// n.data().get_unchecked(ctx, generator, &llvm_usize.const_zero(), None); n.data().get_unchecked(ctx, generator, &llvm_usize.const_zero(), None);
// ctx.builder.build_store(accumulator_addr, identity).unwrap(); ctx.builder.build_store(accumulator_addr, identity).unwrap();
// } }
// gen_for_callback_incrementing( gen_for_callback_incrementing(
// generator, generator,
// ctx, ctx,
// llvm_usize.const_int(1, false), llvm_usize.const_int(1, false),
// (n_sz, false), (n_sz, false),
// |generator, ctx, _, idx| { |generator, ctx, _, idx| {
// let elem = unsafe { n.data().get_unchecked(ctx, generator, &idx, None) }; let elem = unsafe { n.data().get_unchecked(ctx, generator, &idx, None) };
// let accumulator = ctx.builder.build_load(accumulator_addr, "").unwrap(); let accumulator = ctx.builder.build_load(accumulator_addr, "").unwrap();
// let result = call_max(ctx, (elem_ty, accumulator), (elem_ty, elem)); let result = call_max(ctx, (elem_ty, accumulator), (elem_ty, elem));
// ctx.builder.build_store(accumulator_addr, result).unwrap(); ctx.builder.build_store(accumulator_addr, result).unwrap();
// Ok(()) Ok(())
// }, },
// llvm_usize.const_int(1, false), llvm_usize.const_int(1, false),
// )?; )?;
// let accumulator = ctx.builder.build_load(accumulator_addr, "").unwrap(); let accumulator = ctx.builder.build_load(accumulator_addr, "").unwrap();
// accumulator accumulator
} }
_ => unsupported_type(ctx, FN_NAME, &[a_ty]), _ => unsupported_type(ctx, FN_NAME, &[a_ty]),

View File

@ -1,8 +1,5 @@
use crate::codegen::{ use crate::codegen::{
// irrt::{call_ndarray_calc_size, call_ndarray_flatten_index}, llvm_intrinsics::call_int_umin, stmt::gen_for_callback_incrementing, CodeGenContext,
llvm_intrinsics::call_int_umin,
stmt::gen_for_callback_incrementing,
CodeGenContext,
CodeGenerator, CodeGenerator,
}; };
use inkwell::context::Context; use inkwell::context::Context;
@ -1210,27 +1207,25 @@ impl<'ctx> NDArrayType<'ctx> {
ctx: &'ctx Context, ctx: &'ctx Context,
dtype: BasicTypeEnum<'ctx>, dtype: BasicTypeEnum<'ctx>,
) -> Self { ) -> Self {
todo!() let llvm_usize = generator.get_size_type(ctx);
// let llvm_usize = generator.get_size_type(ctx); // struct NDArray { num_dims: size_t, dims: size_t*, data: T* }
//
// * num_dims: Number of dimensions in the array
// * dims: Pointer to an array containing the size of each dimension
// * data: Pointer to an array containing the array data
let llvm_ndarray = ctx
.struct_type(
&[
llvm_usize.into(),
llvm_usize.ptr_type(AddressSpace::default()).into(),
dtype.ptr_type(AddressSpace::default()).into(),
],
false,
)
.ptr_type(AddressSpace::default());
// // struct NDArray { num_dims: size_t, dims: size_t*, data: T* } NDArrayType::from_type(llvm_ndarray, llvm_usize)
// //
// // * num_dims: Number of dimensions in the array
// // * dims: Pointer to an array containing the size of each dimension
// // * data: Pointer to an array containing the array data
// let llvm_ndarray = ctx
// .struct_type(
// &[
// llvm_usize.into(),
// llvm_usize.ptr_type(AddressSpace::default()).into(),
// dtype.ptr_type(AddressSpace::default()).into(),
// ],
// false,
// )
// .ptr_type(AddressSpace::default());
// NDArrayType::from_type(llvm_ndarray, llvm_usize)
} }
/// Creates an [`NDArrayType`] from a [`PointerType`]. /// Creates an [`NDArrayType`] from a [`PointerType`].
@ -1664,22 +1659,23 @@ impl<'ctx, Index: UntypedArrayLikeAccessor<'ctx>> ArrayLikeIndexer<'ctx, Index>
indices: &Index, indices: &Index,
name: Option<&str>, name: Option<&str>,
) -> PointerValue<'ctx> { ) -> PointerValue<'ctx> {
todo!() let llvm_usize = generator.get_size_type(ctx.ctx);
// let llvm_usize = generator.get_size_type(ctx.ctx);
// let indices_elem_ty = indices let indices_elem_ty = indices
// .ptr_offset(ctx, generator, &llvm_usize.const_zero(), None) .ptr_offset(ctx, generator, &llvm_usize.const_zero(), None)
// .get_type() .get_type()
// .get_element_type(); .get_element_type();
// let Ok(indices_elem_ty) = IntType::try_from(indices_elem_ty) else { let Ok(indices_elem_ty) = IntType::try_from(indices_elem_ty) else {
// panic!("Expected list[int32] but got {indices_elem_ty}") panic!("Expected list[int32] but got {indices_elem_ty}")
// }; };
// assert_eq!( assert_eq!(
// indices_elem_ty.get_bit_width(), indices_elem_ty.get_bit_width(),
// 32, 32,
// "Expected list[int32] but got list[int{}]", "Expected list[int32] but got list[int{}]",
// indices_elem_ty.get_bit_width() indices_elem_ty.get_bit_width()
// ); );
todo!()
// let index = call_ndarray_flatten_index(generator, ctx, *self.0, indices); // let index = call_ndarray_flatten_index(generator, ctx, *self.0, indices);
@ -1801,39 +1797,27 @@ struct StructFieldsBuilder<'ctx> {
} }
impl<'ctx> StructField<'ctx> { impl<'ctx> StructField<'ctx> {
/// TODO: DOCUMENT ME
pub fn gep( pub fn gep(
&self, &self,
ctx: &CodeGenContext<'ctx, '_>, ctx: &CodeGenContext<'ctx, '_>,
struct_ptr: PointerValue<'ctx>, ptr: PointerValue<'ctx>,
) -> PointerValue<'ctx> { ) -> PointerValue<'ctx> {
let index_type = ctx.ctx.i32_type(); // TODO: I think I'm not supposed to use i32 for GEP like that ctx.builder.build_struct_gep(ptr, self.gep_index, self.name).unwrap()
unsafe {
ctx.builder
.build_in_bounds_gep(
struct_ptr,
&[index_type.const_zero(), index_type.const_int(self.gep_index as u64, false)],
self.name,
)
.unwrap()
}
} }
/// TODO: DOCUMENT ME
pub fn load( pub fn load(
&self, &self,
ctx: &CodeGenContext<'ctx, '_>, ctx: &CodeGenContext<'ctx, '_>,
struct_ptr: PointerValue<'ctx>, ptr: PointerValue<'ctx>,
) -> BasicValueEnum<'ctx> { ) -> BasicValueEnum<'ctx> {
ctx.builder.build_load(self.gep(ctx, struct_ptr), self.name).unwrap() ctx.builder.build_load(self.gep(ctx, ptr), self.name).unwrap()
} }
/// TODO: DOCUMENT ME pub fn store<V>(&self, ctx: &CodeGenContext<'ctx, '_>, ptr: PointerValue<'ctx>, value: V)
pub fn store<V>(&self, ctx: &CodeGenContext<'ctx, '_>, struct_ptr: PointerValue<'ctx>, value: V)
where where
V: BasicValue<'ctx>, V: BasicValue<'ctx>,
{ {
ctx.builder.build_store(self.gep(ctx, struct_ptr), value).unwrap(); ctx.builder.build_store(ptr, value).unwrap();
} }
} }
@ -1872,7 +1856,7 @@ impl<'ctx> StructFields<'ctx> {
self.fields.len() as u32 self.fields.len() as u32
} }
pub fn get_struct_type(&self, ctx: &'ctx Context) -> StructType<'ctx> { pub fn as_struct_type(&self, ctx: &'ctx Context) -> StructType<'ctx> {
let llvm_fields = self.fields.iter().map(|field| field.ty).collect_vec(); let llvm_fields = self.fields.iter().map(|field| field.ty).collect_vec();
ctx.struct_type(llvm_fields.as_slice(), false) ctx.struct_type(llvm_fields.as_slice(), false)
} }
@ -1916,11 +1900,7 @@ impl<'ctx> StructFieldsBuilder<'ctx> {
fn add_field(&mut self, name: &'static str, ty: BasicTypeEnum<'ctx>) -> StructField<'ctx> { fn add_field(&mut self, name: &'static str, ty: BasicTypeEnum<'ctx>) -> StructField<'ctx> {
let index = self.gep_index_counter; let index = self.gep_index_counter;
self.gep_index_counter += 1; self.gep_index_counter += 1;
StructField { gep_index: index, name, ty }
let field = StructField { gep_index: index, name, ty };
self.fields.push(field); // Register into self.fields
field // Return to the caller to conveniently let them do whatever they want
} }
fn end(self) -> StructFields<'ctx> { fn end(self) -> StructFields<'ctx> {
@ -1951,8 +1931,8 @@ impl<'ctx> NpArrayType<'ctx> {
NpArrayType { size_type, elem_type: ctx.ctx.i8_type().as_basic_type_enum() } NpArrayType { size_type, elem_type: ctx.ctx.i8_type().as_basic_type_enum() }
} }
pub fn get_struct_type(&self, ctx: &'ctx Context) -> StructType<'ctx> { pub fn struct_type(&self, ctx: &CodeGenContext<'ctx, '_>) -> StructType<'ctx> {
self.fields().whole_struct.get_struct_type(ctx) self.fields().whole_struct.as_struct_type(ctx.ctx)
} }
pub fn fields(&self) -> NpArrayStructFields<'ctx> { pub fn fields(&self) -> NpArrayStructFields<'ctx> {
@ -1978,43 +1958,29 @@ impl<'ctx> NpArrayType<'ctx> {
/// - `ndarray.itemsize` will be initialized to the size of `self.elem_type.size_of()`. /// - `ndarray.itemsize` will be initialized to the size of `self.elem_type.size_of()`.
/// - `ndarray.shape` and `ndarray.strides` will be allocated on the stack with number of elements being `in_ndims`, /// - `ndarray.shape` and `ndarray.strides` will be allocated on the stack with number of elements being `in_ndims`,
/// all with empty/uninitialized values. /// all with empty/uninitialized values.
pub fn var_alloc<G>( pub fn alloca(
&self, &self,
generator: &mut G, ctx: &CodeGenContext<'ctx, '_>,
ctx: &mut CodeGenContext<'ctx, '_>,
in_ndims: IntValue<'ctx>, in_ndims: IntValue<'ctx>,
name: Option<&str>, name: &str,
) -> NpArrayValue<'ctx> ) -> NpArrayValue<'ctx> {
where let fields = self.fields();
G: CodeGenerator + ?Sized, let ptr =
{ ctx.builder.build_alloca(fields.whole_struct.as_struct_type(ctx.ctx), name).unwrap();
let ptr = generator
.gen_var_alloc(ctx, self.get_struct_type(ctx.ctx).as_basic_type_enum(), name)
.unwrap();
// Allocate `in_dims` number of `size_type` on the stack for `shape` and `strides` // Allocate `in_dims` number of `size_type` on the stack for `shape` and `strides`
let allocated_shape = generator let allocated_shape =
.gen_array_var_alloc( ctx.builder.build_array_alloca(fields.shape.ty, in_ndims, "allocated_shape").unwrap();
ctx, let allocated_strides = ctx
self.size_type.as_basic_type_enum(), .builder
in_ndims, .build_array_alloca(fields.strides.ty, in_ndims, "allocated_strides")
Some("allocated_shape"),
)
.unwrap();
let allocated_strides = generator
.gen_array_var_alloc(
ctx,
self.size_type.as_basic_type_enum(),
in_ndims,
Some("allocated_strides"),
)
.unwrap(); .unwrap();
let value = NpArrayValue { ty: *self, ptr }; let value = NpArrayValue { ty: *self, ptr };
value.store_ndims(ctx, in_ndims); value.store_ndims(ctx, in_ndims);
value.store_itemsize(ctx, self.elem_type.size_of().unwrap()); value.store_itemsize(ctx, self.elem_type.size_of().unwrap());
value.store_shape(ctx, allocated_shape.base_ptr(ctx, generator)); value.store_shape(ctx, allocated_shape);
value.store_strides(ctx, allocated_strides.base_ptr(ctx, generator)); value.store_strides(ctx, allocated_strides);
return value; return value;
} }
@ -2072,15 +2038,13 @@ impl<'ctx> NpArrayValue<'ctx> {
&self, &self,
ctx: &CodeGenContext<'ctx, '_>, ctx: &CodeGenContext<'ctx, '_>,
) -> TypedArrayLikeAdapter<'ctx, IntValue<'ctx>> { ) -> TypedArrayLikeAdapter<'ctx, IntValue<'ctx>> {
// Get the pointer to `shape`
let field = self.ty.fields().shape; let field = self.ty.fields().shape;
let shape = field.load(ctx, self.ptr).into_pointer_value(); field.gep(ctx, self.ptr);
// Load `ndims`
let ndims = self.load_ndims(ctx); let ndims = self.load_ndims(ctx);
TypedArrayLikeAdapter { TypedArrayLikeAdapter {
adapted: ArraySliceValue(shape, ndims, Some(field.name)), adapted: ArraySliceValue(self.ptr, ndims, Some(field.name)),
downcast_fn: Box::new(|_ctx, x| x.into_int_value()), downcast_fn: Box::new(|_ctx, x| x.into_int_value()),
upcast_fn: Box::new(|_ctx, x| x.as_basic_value_enum()), upcast_fn: Box::new(|_ctx, x| x.as_basic_value_enum()),
} }
@ -2091,15 +2055,13 @@ impl<'ctx> NpArrayValue<'ctx> {
&self, &self,
ctx: &CodeGenContext<'ctx, '_>, ctx: &CodeGenContext<'ctx, '_>,
) -> TypedArrayLikeAdapter<'ctx, IntValue<'ctx>> { ) -> TypedArrayLikeAdapter<'ctx, IntValue<'ctx>> {
// Get the pointer to `strides`
let field = self.ty.fields().strides; let field = self.ty.fields().strides;
let strides = field.load(ctx, self.ptr).into_pointer_value(); field.gep(ctx, self.ptr);
// Load `ndims`
let ndims = self.load_ndims(ctx); let ndims = self.load_ndims(ctx);
TypedArrayLikeAdapter { TypedArrayLikeAdapter {
adapted: ArraySliceValue(strides, ndims, Some(field.name)), adapted: ArraySliceValue(self.ptr, ndims, Some(field.name)),
downcast_fn: Box::new(|_ctx, x| x.into_int_value()), downcast_fn: Box::new(|_ctx, x| x.into_int_value()),
upcast_fn: Box::new(|_ctx, x| x.as_basic_value_enum()), upcast_fn: Box::new(|_ctx, x| x.as_basic_value_enum()),
} }

View File

@ -4,8 +4,8 @@ mod test;
use super::{ use super::{
classes::{ classes::{
check_basic_types_match, ArrayLikeIndexer, ArrayLikeValue, ArraySliceValue, ListValue, ArrayLikeIndexer, ArrayLikeValue, ArraySliceValue, ListValue, NDArrayValue, NpArrayType,
NDArrayValue, NpArrayType, NpArrayValue, TypedArrayLikeAdapter, UntypedArrayLikeAccessor, NpArrayValue, TypedArrayLikeAdapter, UntypedArrayLikeAccessor,
}, },
llvm_intrinsics, CodeGenContext, CodeGenerator, llvm_intrinsics, CodeGenContext, CodeGenerator,
}; };
@ -17,7 +17,7 @@ use inkwell::{
memory_buffer::MemoryBuffer, memory_buffer::MemoryBuffer,
module::Module, module::Module,
types::{BasicType, BasicTypeEnum, FunctionType, IntType, PointerType}, types::{BasicType, BasicTypeEnum, FunctionType, IntType, PointerType},
values::{BasicValue, BasicValueEnum, CallSiteValue, FloatValue, FunctionValue, IntValue}, values::{BasicValueEnum, CallSiteValue, FloatValue, FunctionValue, IntValue},
AddressSpace, IntPredicate, AddressSpace, IntPredicate,
}; };
use itertools::Either; use itertools::Either;
@ -565,370 +565,370 @@ pub fn call_j0<'ctx>(ctx: &CodeGenContext<'ctx, '_>, v: FloatValue<'ctx>) -> Flo
.unwrap() .unwrap()
} }
// /// Generates a call to `__nac3_ndarray_calc_size`. Returns an [`IntValue`] representing the /// Generates a call to `__nac3_ndarray_calc_size`. Returns an [`IntValue`] representing the
// /// calculated total size. /// calculated total size.
// /// ///
// /// * `dims` - An [`ArrayLikeIndexer`] containing the size of each dimension. /// * `dims` - An [`ArrayLikeIndexer`] containing the size of each dimension.
// /// * `range` - The dimension index to begin and end (exclusively) calculating the dimensions for, /// * `range` - The dimension index to begin and end (exclusively) calculating the dimensions for,
// /// or [`None`] if starting from the first dimension and ending at the last dimension respectively. /// or [`None`] if starting from the first dimension and ending at the last dimension respectively.
// pub fn call_ndarray_calc_size<'ctx, G, Dims>( pub fn call_ndarray_calc_size<'ctx, G, Dims>(
// generator: &G, generator: &G,
// ctx: &CodeGenContext<'ctx, '_>, ctx: &CodeGenContext<'ctx, '_>,
// dims: &Dims, dims: &Dims,
// (begin, end): (Option<IntValue<'ctx>>, Option<IntValue<'ctx>>), (begin, end): (Option<IntValue<'ctx>>, Option<IntValue<'ctx>>),
// ) -> IntValue<'ctx> ) -> IntValue<'ctx>
// where where
// G: CodeGenerator + ?Sized, G: CodeGenerator + ?Sized,
// Dims: ArrayLikeIndexer<'ctx>, Dims: ArrayLikeIndexer<'ctx>,
// { {
// let llvm_usize = generator.get_size_type(ctx.ctx); let llvm_usize = generator.get_size_type(ctx.ctx);
// let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default()); let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default());
//
// let ndarray_calc_size_fn_name = match llvm_usize.get_bit_width() { let ndarray_calc_size_fn_name = match llvm_usize.get_bit_width() {
// 32 => "__nac3_ndarray_calc_size", 32 => "__nac3_ndarray_calc_size",
// 64 => "__nac3_ndarray_calc_size64", 64 => "__nac3_ndarray_calc_size64",
// bw => unreachable!("Unsupported size type bit width: {}", bw), bw => unreachable!("Unsupported size type bit width: {}", bw),
// }; };
// let ndarray_calc_size_fn_t = llvm_usize.fn_type( let ndarray_calc_size_fn_t = llvm_usize.fn_type(
// &[llvm_pusize.into(), llvm_usize.into(), llvm_usize.into(), llvm_usize.into()], &[llvm_pusize.into(), llvm_usize.into(), llvm_usize.into(), llvm_usize.into()],
// false, false,
// ); );
// let ndarray_calc_size_fn = let ndarray_calc_size_fn =
// ctx.module.get_function(ndarray_calc_size_fn_name).unwrap_or_else(|| { ctx.module.get_function(ndarray_calc_size_fn_name).unwrap_or_else(|| {
// ctx.module.add_function(ndarray_calc_size_fn_name, ndarray_calc_size_fn_t, None) ctx.module.add_function(ndarray_calc_size_fn_name, ndarray_calc_size_fn_t, None)
// }); });
//
// let begin = begin.unwrap_or_else(|| llvm_usize.const_zero()); let begin = begin.unwrap_or_else(|| llvm_usize.const_zero());
// let end = end.unwrap_or_else(|| dims.size(ctx, generator)); let end = end.unwrap_or_else(|| dims.size(ctx, generator));
// ctx.builder ctx.builder
// .build_call( .build_call(
// ndarray_calc_size_fn, ndarray_calc_size_fn,
// &[ &[
// dims.base_ptr(ctx, generator).into(), dims.base_ptr(ctx, generator).into(),
// dims.size(ctx, generator).into(), dims.size(ctx, generator).into(),
// begin.into(), begin.into(),
// end.into(), end.into(),
// ], ],
// "", "",
// ) )
// .map(CallSiteValue::try_as_basic_value) .map(CallSiteValue::try_as_basic_value)
// .map(|v| v.map_left(BasicValueEnum::into_int_value)) .map(|v| v.map_left(BasicValueEnum::into_int_value))
// .map(Either::unwrap_left) .map(Either::unwrap_left)
// .unwrap() .unwrap()
// } }
//
// /// Generates a call to `__nac3_ndarray_calc_nd_indices`. Returns a [`TypeArrayLikeAdpater`] /// Generates a call to `__nac3_ndarray_calc_nd_indices`. Returns a [`TypeArrayLikeAdpater`]
// /// containing `i32` indices of the flattened index. /// containing `i32` indices of the flattened index.
// /// ///
// /// * `index` - The index to compute the multidimensional index for. /// * `index` - The index to compute the multidimensional index for.
// /// * `ndarray` - LLVM pointer to the `NDArray`. This value must be the LLVM representation of an /// * `ndarray` - LLVM pointer to the `NDArray`. This value must be the LLVM representation of an
// /// `NDArray`. /// `NDArray`.
// pub fn call_ndarray_calc_nd_indices<'ctx, G: CodeGenerator + ?Sized>( pub fn call_ndarray_calc_nd_indices<'ctx, G: CodeGenerator + ?Sized>(
// generator: &G, generator: &G,
// ctx: &mut CodeGenContext<'ctx, '_>, ctx: &mut CodeGenContext<'ctx, '_>,
// index: IntValue<'ctx>, index: IntValue<'ctx>,
// ndarray: NDArrayValue<'ctx>, ndarray: NDArrayValue<'ctx>,
// ) -> TypedArrayLikeAdapter<'ctx, IntValue<'ctx>> { ) -> TypedArrayLikeAdapter<'ctx, IntValue<'ctx>> {
// let llvm_void = ctx.ctx.void_type(); let llvm_void = ctx.ctx.void_type();
// let llvm_i32 = ctx.ctx.i32_type(); let llvm_i32 = ctx.ctx.i32_type();
// let llvm_usize = generator.get_size_type(ctx.ctx); let llvm_usize = generator.get_size_type(ctx.ctx);
// let llvm_pi32 = llvm_i32.ptr_type(AddressSpace::default()); let llvm_pi32 = llvm_i32.ptr_type(AddressSpace::default());
// let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default()); let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default());
//
// let ndarray_calc_nd_indices_fn_name = match llvm_usize.get_bit_width() { let ndarray_calc_nd_indices_fn_name = match llvm_usize.get_bit_width() {
// 32 => "__nac3_ndarray_calc_nd_indices", 32 => "__nac3_ndarray_calc_nd_indices",
// 64 => "__nac3_ndarray_calc_nd_indices64", 64 => "__nac3_ndarray_calc_nd_indices64",
// bw => unreachable!("Unsupported size type bit width: {}", bw), bw => unreachable!("Unsupported size type bit width: {}", bw),
// }; };
// let ndarray_calc_nd_indices_fn = let ndarray_calc_nd_indices_fn =
// ctx.module.get_function(ndarray_calc_nd_indices_fn_name).unwrap_or_else(|| { ctx.module.get_function(ndarray_calc_nd_indices_fn_name).unwrap_or_else(|| {
// let fn_type = llvm_void.fn_type( let fn_type = llvm_void.fn_type(
// &[llvm_usize.into(), llvm_pusize.into(), llvm_usize.into(), llvm_pi32.into()], &[llvm_usize.into(), llvm_pusize.into(), llvm_usize.into(), llvm_pi32.into()],
// false, false,
// ); );
//
// ctx.module.add_function(ndarray_calc_nd_indices_fn_name, fn_type, None) ctx.module.add_function(ndarray_calc_nd_indices_fn_name, fn_type, None)
// }); });
//
// let ndarray_num_dims = ndarray.load_ndims(ctx); let ndarray_num_dims = ndarray.load_ndims(ctx);
// let ndarray_dims = ndarray.dim_sizes(); let ndarray_dims = ndarray.dim_sizes();
//
// let indices = ctx.builder.build_array_alloca(llvm_i32, ndarray_num_dims, "").unwrap(); let indices = ctx.builder.build_array_alloca(llvm_i32, ndarray_num_dims, "").unwrap();
//
// ctx.builder ctx.builder
// .build_call( .build_call(
// ndarray_calc_nd_indices_fn, ndarray_calc_nd_indices_fn,
// &[ &[
// index.into(), index.into(),
// ndarray_dims.base_ptr(ctx, generator).into(), ndarray_dims.base_ptr(ctx, generator).into(),
// ndarray_num_dims.into(), ndarray_num_dims.into(),
// indices.into(), indices.into(),
// ], ],
// "", "",
// ) )
// .unwrap(); .unwrap();
//
// TypedArrayLikeAdapter::from( TypedArrayLikeAdapter::from(
// ArraySliceValue::from_ptr_val(indices, ndarray_num_dims, None), ArraySliceValue::from_ptr_val(indices, ndarray_num_dims, None),
// Box::new(|_, v| v.into_int_value()), Box::new(|_, v| v.into_int_value()),
// Box::new(|_, v| v.into()), Box::new(|_, v| v.into()),
// ) )
// } }
//
// fn call_ndarray_flatten_index_impl<'ctx, G, Indices>( fn call_ndarray_flatten_index_impl<'ctx, G, Indices>(
// generator: &G, generator: &G,
// ctx: &CodeGenContext<'ctx, '_>, ctx: &CodeGenContext<'ctx, '_>,
// ndarray: NDArrayValue<'ctx>, ndarray: NDArrayValue<'ctx>,
// indices: &Indices, indices: &Indices,
// ) -> IntValue<'ctx> ) -> IntValue<'ctx>
// where where
// G: CodeGenerator + ?Sized, G: CodeGenerator + ?Sized,
// Indices: ArrayLikeIndexer<'ctx>, Indices: ArrayLikeIndexer<'ctx>,
// { {
// let llvm_i32 = ctx.ctx.i32_type(); let llvm_i32 = ctx.ctx.i32_type();
// let llvm_usize = generator.get_size_type(ctx.ctx); let llvm_usize = generator.get_size_type(ctx.ctx);
//
// let llvm_pi32 = llvm_i32.ptr_type(AddressSpace::default()); let llvm_pi32 = llvm_i32.ptr_type(AddressSpace::default());
// let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default()); let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default());
//
// debug_assert_eq!( debug_assert_eq!(
// IntType::try_from(indices.element_type(ctx, generator)) IntType::try_from(indices.element_type(ctx, generator))
// .map(IntType::get_bit_width) .map(IntType::get_bit_width)
// .unwrap_or_default(), .unwrap_or_default(),
// llvm_i32.get_bit_width(), llvm_i32.get_bit_width(),
// "Expected i32 value for argument `indices` to `call_ndarray_flatten_index_impl`" "Expected i32 value for argument `indices` to `call_ndarray_flatten_index_impl`"
// ); );
// debug_assert_eq!( debug_assert_eq!(
// indices.size(ctx, generator).get_type().get_bit_width(), indices.size(ctx, generator).get_type().get_bit_width(),
// llvm_usize.get_bit_width(), llvm_usize.get_bit_width(),
// "Expected usize integer value for argument `indices_size` to `call_ndarray_flatten_index_impl`" "Expected usize integer value for argument `indices_size` to `call_ndarray_flatten_index_impl`"
// ); );
//
// let ndarray_flatten_index_fn_name = match llvm_usize.get_bit_width() { let ndarray_flatten_index_fn_name = match llvm_usize.get_bit_width() {
// 32 => "__nac3_ndarray_flatten_index", 32 => "__nac3_ndarray_flatten_index",
// 64 => "__nac3_ndarray_flatten_index64", 64 => "__nac3_ndarray_flatten_index64",
// bw => unreachable!("Unsupported size type bit width: {}", bw), bw => unreachable!("Unsupported size type bit width: {}", bw),
// }; };
// let ndarray_flatten_index_fn = let ndarray_flatten_index_fn =
// ctx.module.get_function(ndarray_flatten_index_fn_name).unwrap_or_else(|| { ctx.module.get_function(ndarray_flatten_index_fn_name).unwrap_or_else(|| {
// let fn_type = llvm_usize.fn_type( let fn_type = llvm_usize.fn_type(
// &[llvm_pusize.into(), llvm_usize.into(), llvm_pi32.into(), llvm_usize.into()], &[llvm_pusize.into(), llvm_usize.into(), llvm_pi32.into(), llvm_usize.into()],
// false, false,
// ); );
//
// ctx.module.add_function(ndarray_flatten_index_fn_name, fn_type, None) ctx.module.add_function(ndarray_flatten_index_fn_name, fn_type, None)
// }); });
//
// let ndarray_num_dims = ndarray.load_ndims(ctx); let ndarray_num_dims = ndarray.load_ndims(ctx);
// let ndarray_dims = ndarray.dim_sizes(); let ndarray_dims = ndarray.dim_sizes();
//
// let index = ctx let index = ctx
// .builder .builder
// .build_call( .build_call(
// ndarray_flatten_index_fn, ndarray_flatten_index_fn,
// &[ &[
// ndarray_dims.base_ptr(ctx, generator).into(), ndarray_dims.base_ptr(ctx, generator).into(),
// ndarray_num_dims.into(), ndarray_num_dims.into(),
// indices.base_ptr(ctx, generator).into(), indices.base_ptr(ctx, generator).into(),
// indices.size(ctx, generator).into(), indices.size(ctx, generator).into(),
// ], ],
// "", "",
// ) )
// .map(CallSiteValue::try_as_basic_value) .map(CallSiteValue::try_as_basic_value)
// .map(|v| v.map_left(BasicValueEnum::into_int_value)) .map(|v| v.map_left(BasicValueEnum::into_int_value))
// .map(Either::unwrap_left) .map(Either::unwrap_left)
// .unwrap(); .unwrap();
//
// index index
// } }
//
// /// Generates a call to `__nac3_ndarray_flatten_index`. Returns the flattened index for the /// Generates a call to `__nac3_ndarray_flatten_index`. Returns the flattened index for the
// /// multidimensional index. /// multidimensional index.
// /// ///
// /// * `ndarray` - LLVM pointer to the `NDArray`. This value must be the LLVM representation of an /// * `ndarray` - LLVM pointer to the `NDArray`. This value must be the LLVM representation of an
// /// `NDArray`. /// `NDArray`.
// /// * `indices` - The multidimensional index to compute the flattened index for. /// * `indices` - The multidimensional index to compute the flattened index for.
// pub fn call_ndarray_flatten_index<'ctx, G, Index>( pub fn call_ndarray_flatten_index<'ctx, G, Index>(
// generator: &mut G, generator: &mut G,
// ctx: &mut CodeGenContext<'ctx, '_>, ctx: &mut CodeGenContext<'ctx, '_>,
// ndarray: NDArrayValue<'ctx>, ndarray: NDArrayValue<'ctx>,
// indices: &Index, indices: &Index,
// ) -> IntValue<'ctx> ) -> IntValue<'ctx>
// where where
// G: CodeGenerator + ?Sized, G: CodeGenerator + ?Sized,
// Index: ArrayLikeIndexer<'ctx>, Index: ArrayLikeIndexer<'ctx>,
// { {
// call_ndarray_flatten_index_impl(generator, ctx, ndarray, indices) call_ndarray_flatten_index_impl(generator, ctx, ndarray, indices)
// } }
//
// /// Generates a call to `__nac3_ndarray_calc_broadcast`. Returns a tuple containing the number of /// Generates a call to `__nac3_ndarray_calc_broadcast`. Returns a tuple containing the number of
// /// dimension and size of each dimension of the resultant `ndarray`. /// dimension and size of each dimension of the resultant `ndarray`.
// pub fn call_ndarray_calc_broadcast<'ctx, G: CodeGenerator + ?Sized>( pub fn call_ndarray_calc_broadcast<'ctx, G: CodeGenerator + ?Sized>(
// generator: &mut G, generator: &mut G,
// ctx: &mut CodeGenContext<'ctx, '_>, ctx: &mut CodeGenContext<'ctx, '_>,
// lhs: NDArrayValue<'ctx>, lhs: NDArrayValue<'ctx>,
// rhs: NDArrayValue<'ctx>, rhs: NDArrayValue<'ctx>,
// ) -> TypedArrayLikeAdapter<'ctx, IntValue<'ctx>> { ) -> TypedArrayLikeAdapter<'ctx, IntValue<'ctx>> {
// let llvm_usize = generator.get_size_type(ctx.ctx); let llvm_usize = generator.get_size_type(ctx.ctx);
// let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default()); let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default());
//
// let ndarray_calc_broadcast_fn_name = match llvm_usize.get_bit_width() { let ndarray_calc_broadcast_fn_name = match llvm_usize.get_bit_width() {
// 32 => "__nac3_ndarray_calc_broadcast", 32 => "__nac3_ndarray_calc_broadcast",
// 64 => "__nac3_ndarray_calc_broadcast64", 64 => "__nac3_ndarray_calc_broadcast64",
// bw => unreachable!("Unsupported size type bit width: {}", bw), bw => unreachable!("Unsupported size type bit width: {}", bw),
// }; };
// let ndarray_calc_broadcast_fn = let ndarray_calc_broadcast_fn =
// ctx.module.get_function(ndarray_calc_broadcast_fn_name).unwrap_or_else(|| { ctx.module.get_function(ndarray_calc_broadcast_fn_name).unwrap_or_else(|| {
// let fn_type = llvm_usize.fn_type( let fn_type = llvm_usize.fn_type(
// &[ &[
// llvm_pusize.into(), llvm_pusize.into(),
// llvm_usize.into(), llvm_usize.into(),
// llvm_pusize.into(), llvm_pusize.into(),
// llvm_usize.into(), llvm_usize.into(),
// llvm_pusize.into(), llvm_pusize.into(),
// ], ],
// false, false,
// ); );
//
// ctx.module.add_function(ndarray_calc_broadcast_fn_name, fn_type, None) ctx.module.add_function(ndarray_calc_broadcast_fn_name, fn_type, None)
// }); });
//
// let lhs_ndims = lhs.load_ndims(ctx); let lhs_ndims = lhs.load_ndims(ctx);
// let rhs_ndims = rhs.load_ndims(ctx); let rhs_ndims = rhs.load_ndims(ctx);
// let min_ndims = llvm_intrinsics::call_int_umin(ctx, lhs_ndims, rhs_ndims, None); let min_ndims = llvm_intrinsics::call_int_umin(ctx, lhs_ndims, rhs_ndims, None);
//
// gen_for_callback_incrementing( gen_for_callback_incrementing(
// generator, generator,
// ctx, ctx,
// llvm_usize.const_zero(), llvm_usize.const_zero(),
// (min_ndims, false), (min_ndims, false),
// |generator, ctx, _, idx| { |generator, ctx, _, idx| {
// let idx = ctx.builder.build_int_sub(min_ndims, idx, "").unwrap(); let idx = ctx.builder.build_int_sub(min_ndims, idx, "").unwrap();
// let (lhs_dim_sz, rhs_dim_sz) = unsafe { let (lhs_dim_sz, rhs_dim_sz) = unsafe {
// ( (
// lhs.dim_sizes().get_typed_unchecked(ctx, generator, &idx, None), lhs.dim_sizes().get_typed_unchecked(ctx, generator, &idx, None),
// rhs.dim_sizes().get_typed_unchecked(ctx, generator, &idx, None), rhs.dim_sizes().get_typed_unchecked(ctx, generator, &idx, None),
// ) )
// }; };
//
// let llvm_usize_const_one = llvm_usize.const_int(1, false); let llvm_usize_const_one = llvm_usize.const_int(1, false);
// let lhs_eqz = ctx let lhs_eqz = ctx
// .builder .builder
// .build_int_compare(IntPredicate::EQ, lhs_dim_sz, llvm_usize_const_one, "") .build_int_compare(IntPredicate::EQ, lhs_dim_sz, llvm_usize_const_one, "")
// .unwrap(); .unwrap();
// let rhs_eqz = ctx let rhs_eqz = ctx
// .builder .builder
// .build_int_compare(IntPredicate::EQ, rhs_dim_sz, llvm_usize_const_one, "") .build_int_compare(IntPredicate::EQ, rhs_dim_sz, llvm_usize_const_one, "")
// .unwrap(); .unwrap();
// let lhs_or_rhs_eqz = ctx.builder.build_or(lhs_eqz, rhs_eqz, "").unwrap(); let lhs_or_rhs_eqz = ctx.builder.build_or(lhs_eqz, rhs_eqz, "").unwrap();
//
// let lhs_eq_rhs = ctx let lhs_eq_rhs = ctx
// .builder .builder
// .build_int_compare(IntPredicate::EQ, lhs_dim_sz, rhs_dim_sz, "") .build_int_compare(IntPredicate::EQ, lhs_dim_sz, rhs_dim_sz, "")
// .unwrap(); .unwrap();
//
// let is_compatible = ctx.builder.build_or(lhs_or_rhs_eqz, lhs_eq_rhs, "").unwrap(); let is_compatible = ctx.builder.build_or(lhs_or_rhs_eqz, lhs_eq_rhs, "").unwrap();
//
// ctx.make_assert( ctx.make_assert(
// generator, generator,
// is_compatible, is_compatible,
// "0:ValueError", "0:ValueError",
// "operands could not be broadcast together", "operands could not be broadcast together",
// [None, None, None], [None, None, None],
// ctx.current_loc, ctx.current_loc,
// ); );
//
// Ok(()) Ok(())
// }, },
// llvm_usize.const_int(1, false), llvm_usize.const_int(1, false),
// ) )
// .unwrap(); .unwrap();
//
// let max_ndims = llvm_intrinsics::call_int_umax(ctx, lhs_ndims, rhs_ndims, None); let max_ndims = llvm_intrinsics::call_int_umax(ctx, lhs_ndims, rhs_ndims, None);
// let lhs_dims = lhs.dim_sizes().base_ptr(ctx, generator); let lhs_dims = lhs.dim_sizes().base_ptr(ctx, generator);
// let lhs_ndims = lhs.load_ndims(ctx); let lhs_ndims = lhs.load_ndims(ctx);
// let rhs_dims = rhs.dim_sizes().base_ptr(ctx, generator); let rhs_dims = rhs.dim_sizes().base_ptr(ctx, generator);
// let rhs_ndims = rhs.load_ndims(ctx); let rhs_ndims = rhs.load_ndims(ctx);
// let out_dims = ctx.builder.build_array_alloca(llvm_usize, max_ndims, "").unwrap(); let out_dims = ctx.builder.build_array_alloca(llvm_usize, max_ndims, "").unwrap();
// let out_dims = ArraySliceValue::from_ptr_val(out_dims, max_ndims, None); let out_dims = ArraySliceValue::from_ptr_val(out_dims, max_ndims, None);
//
// ctx.builder ctx.builder
// .build_call( .build_call(
// ndarray_calc_broadcast_fn, ndarray_calc_broadcast_fn,
// &[ &[
// lhs_dims.into(), lhs_dims.into(),
// lhs_ndims.into(), lhs_ndims.into(),
// rhs_dims.into(), rhs_dims.into(),
// rhs_ndims.into(), rhs_ndims.into(),
// out_dims.base_ptr(ctx, generator).into(), out_dims.base_ptr(ctx, generator).into(),
// ], ],
// "", "",
// ) )
// .unwrap(); .unwrap();
//
// TypedArrayLikeAdapter::from( TypedArrayLikeAdapter::from(
// out_dims, out_dims,
// Box::new(|_, v| v.into_int_value()), Box::new(|_, v| v.into_int_value()),
// Box::new(|_, v| v.into()), Box::new(|_, v| v.into()),
// ) )
// } }
//
// /// Generates a call to `__nac3_ndarray_calc_broadcast_idx`. Returns an [`ArrayAllocaValue`] /// Generates a call to `__nac3_ndarray_calc_broadcast_idx`. Returns an [`ArrayAllocaValue`]
// /// containing the indices used for accessing `array` corresponding to the index of the broadcasted /// containing the indices used for accessing `array` corresponding to the index of the broadcasted
// /// array `broadcast_idx`. /// array `broadcast_idx`.
// pub fn call_ndarray_calc_broadcast_index< pub fn call_ndarray_calc_broadcast_index<
// 'ctx, 'ctx,
// G: CodeGenerator + ?Sized, G: CodeGenerator + ?Sized,
// BroadcastIdx: UntypedArrayLikeAccessor<'ctx>, BroadcastIdx: UntypedArrayLikeAccessor<'ctx>,
// >( >(
// generator: &mut G, generator: &mut G,
// ctx: &mut CodeGenContext<'ctx, '_>, ctx: &mut CodeGenContext<'ctx, '_>,
// array: NDArrayValue<'ctx>, array: NDArrayValue<'ctx>,
// broadcast_idx: &BroadcastIdx, broadcast_idx: &BroadcastIdx,
// ) -> TypedArrayLikeAdapter<'ctx, IntValue<'ctx>> { ) -> TypedArrayLikeAdapter<'ctx, IntValue<'ctx>> {
// let llvm_i32 = ctx.ctx.i32_type(); let llvm_i32 = ctx.ctx.i32_type();
// let llvm_usize = generator.get_size_type(ctx.ctx); let llvm_usize = generator.get_size_type(ctx.ctx);
// let llvm_pi32 = llvm_i32.ptr_type(AddressSpace::default()); let llvm_pi32 = llvm_i32.ptr_type(AddressSpace::default());
// let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default()); let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default());
//
// let ndarray_calc_broadcast_fn_name = match llvm_usize.get_bit_width() { let ndarray_calc_broadcast_fn_name = match llvm_usize.get_bit_width() {
// 32 => "__nac3_ndarray_calc_broadcast_idx", 32 => "__nac3_ndarray_calc_broadcast_idx",
// 64 => "__nac3_ndarray_calc_broadcast_idx64", 64 => "__nac3_ndarray_calc_broadcast_idx64",
// bw => unreachable!("Unsupported size type bit width: {}", bw), bw => unreachable!("Unsupported size type bit width: {}", bw),
// }; };
// let ndarray_calc_broadcast_fn = let ndarray_calc_broadcast_fn =
// ctx.module.get_function(ndarray_calc_broadcast_fn_name).unwrap_or_else(|| { ctx.module.get_function(ndarray_calc_broadcast_fn_name).unwrap_or_else(|| {
// let fn_type = llvm_usize.fn_type( let fn_type = llvm_usize.fn_type(
// &[llvm_pusize.into(), llvm_usize.into(), llvm_pi32.into(), llvm_pi32.into()], &[llvm_pusize.into(), llvm_usize.into(), llvm_pi32.into(), llvm_pi32.into()],
// false, false,
// ); );
//
// ctx.module.add_function(ndarray_calc_broadcast_fn_name, fn_type, None) ctx.module.add_function(ndarray_calc_broadcast_fn_name, fn_type, None)
// }); });
//
// let broadcast_size = broadcast_idx.size(ctx, generator); let broadcast_size = broadcast_idx.size(ctx, generator);
// let out_idx = ctx.builder.build_array_alloca(llvm_i32, broadcast_size, "").unwrap(); let out_idx = ctx.builder.build_array_alloca(llvm_i32, broadcast_size, "").unwrap();
//
// let array_dims = array.dim_sizes().base_ptr(ctx, generator); let array_dims = array.dim_sizes().base_ptr(ctx, generator);
// let array_ndims = array.load_ndims(ctx); let array_ndims = array.load_ndims(ctx);
// let broadcast_idx_ptr = unsafe { let broadcast_idx_ptr = unsafe {
// broadcast_idx.ptr_offset_unchecked(ctx, generator, &llvm_usize.const_zero(), None) broadcast_idx.ptr_offset_unchecked(ctx, generator, &llvm_usize.const_zero(), None)
// }; };
//
// ctx.builder ctx.builder
// .build_call( .build_call(
// ndarray_calc_broadcast_fn, ndarray_calc_broadcast_fn,
// &[array_dims.into(), array_ndims.into(), broadcast_idx_ptr.into(), out_idx.into()], &[array_dims.into(), array_ndims.into(), broadcast_idx_ptr.into(), out_idx.into()],
// "", "",
// ) )
// .unwrap(); .unwrap();
//
// TypedArrayLikeAdapter::from( TypedArrayLikeAdapter::from(
// ArraySliceValue::from_ptr_val(out_idx, broadcast_size, None), ArraySliceValue::from_ptr_val(out_idx, broadcast_size, None),
// Box::new(|_, v| v.into_int_value()), Box::new(|_, v| v.into_int_value()),
// Box::new(|_, v| v.into()), Box::new(|_, v| v.into()),
// ) )
// } }
fn get_size_variant<'ctx>(ty: IntType<'ctx>) -> SizeVariant { fn get_size_variant<'ctx>(ty: IntType<'ctx>) -> SizeVariant {
match ty.get_bit_width() { match ty.get_bit_width() {
@ -965,28 +965,21 @@ where
}) })
} }
fn get_irrt_ndarray_ptr_type<'ctx>( fn get_ndarray_struct_ptr<'ctx>(ctx: &'ctx Context, size_type: IntType<'ctx>) -> PointerType<'ctx> {
ctx: &CodeGenContext<'ctx, '_>, let i8_type = ctx.i8_type();
size_type: IntType<'ctx>,
) -> PointerType<'ctx> {
let i8_type = ctx.ctx.i8_type();
let ndarray_ty = NpArrayType { size_type, elem_type: i8_type.as_basic_type_enum() }; let ndarray_ty = NpArrayType { size_type, elem_type: i8_type.as_basic_type_enum() };
let struct_ty = ndarray_ty.get_struct_type(ctx.ctx); let struct_ty = ndarray_ty.fields().whole_struct.as_struct_type(ctx);
struct_ty.ptr_type(AddressSpace::default()) struct_ty.ptr_type(AddressSpace::default())
} }
fn get_irrt_opaque_uint8_ptr_type<'ctx>(ctx: &CodeGenContext<'ctx, '_>) -> PointerType<'ctx> {
ctx.ctx.i8_type().ptr_type(AddressSpace::default())
}
pub fn call_nac3_ndarray_size<'ctx>( pub fn call_nac3_ndarray_size<'ctx>(
ctx: &CodeGenContext<'ctx, '_>, ctx: &CodeGenContext<'ctx, '_>,
ndarray: NpArrayValue<'ctx>, ndarray: NpArrayValue<'ctx>,
) -> IntValue<'ctx> { ) -> IntValue<'ctx> {
let size_type = ndarray.ty.size_type; let size_type = ndarray.ty.size_type;
let function = get_size_type_dependent_function(ctx, size_type, "__nac3_ndarray_size", || { let function = get_size_type_dependent_function(ctx, size_type, "__nac3_ndarray_size", || {
size_type.fn_type(&[get_irrt_ndarray_ptr_type(ctx, size_type).into()], false) size_type.fn_type(&[get_ndarray_struct_ptr(ctx.ctx, size_type).into()], false)
}); });
ctx.builder ctx.builder
@ -996,44 +989,3 @@ pub fn call_nac3_ndarray_size<'ctx>(
.unwrap_left() .unwrap_left()
.into_int_value() .into_int_value()
} }
pub fn call_nac3_ndarray_fill_generic<'ctx>(
ctx: &CodeGenContext<'ctx, '_>,
ndarray: NpArrayValue<'ctx>,
fill_value: BasicValueEnum<'ctx>,
) {
// Sanity check on type of `fill_value`
check_basic_types_match(ndarray.ty.elem_type, fill_value.get_type().as_basic_type_enum())
.unwrap();
let size_type = ndarray.ty.size_type;
let function =
get_size_type_dependent_function(ctx, size_type, "__nac3_ndarray_fill_generic", || {
ctx.ctx.void_type().fn_type(
&[
get_irrt_ndarray_ptr_type(ctx, size_type).into(), // NDArray<SizeT>* ndarray
get_irrt_opaque_uint8_ptr_type(ctx).into(), // uint8_t* pvalue
],
false,
)
});
// Put `fill_value` onto the stack and get a pointer to it, and that pointer will be `pvalue`
let pvalue = ctx.builder.build_alloca(ndarray.ty.elem_type, "fill_value").unwrap();
ctx.builder.build_store(pvalue, fill_value).unwrap();
// Cast pvalue to `uint8_t*`
let pvalue = ctx.builder.build_pointer_cast(pvalue, get_irrt_opaque_uint8_ptr_type(ctx), "").unwrap();
// Call the IRRT function
ctx.builder
.build_call(
function,
&[
ndarray.ptr.into(), // ndarray
pvalue.into(), // pvalue
],
"",
)
.unwrap();
}

View File

@ -7,7 +7,6 @@ use crate::{
typedef::{CallId, FuncArg, Type, TypeEnum, Unifier}, typedef::{CallId, FuncArg, Type, TypeEnum, Unifier},
}, },
}; };
use classes::NpArrayType;
use crossbeam::channel::{unbounded, Receiver, Sender}; use crossbeam::channel::{unbounded, Receiver, Sender};
use inkwell::{ use inkwell::{
attributes::{Attribute, AttributeLoc}, attributes::{Attribute, AttributeLoc},
@ -477,11 +476,7 @@ fn get_llvm_type<'ctx, G: CodeGenerator + ?Sized>(
ctx, module, generator, unifier, top_level, type_cache, dtype, ctx, module, generator, unifier, top_level, type_cache, dtype,
); );
let ndarray_ty = NpArrayType { NDArrayType::new(generator, ctx, element_type).as_base_type().into()
size_type: generator.get_size_type(ctx),
elem_type: element_type,
};
ndarray_ty.get_struct_type(ctx).as_basic_type_enum()
} }
_ => unreachable!( _ => unreachable!(

View File

@ -2,11 +2,15 @@ use crate::{
codegen::{ codegen::{
classes::{ classes::{
ArrayLikeIndexer, ArrayLikeValue, ListType, ListValue, NDArrayType, NDArrayValue, ArrayLikeIndexer, ArrayLikeValue, ListType, ListValue, NDArrayType, NDArrayValue,
NpArrayType, ProxyType, ProxyValue, TypedArrayLikeAccessor, TypedArrayLikeAdapter, ProxyType, ProxyValue, TypedArrayLikeAccessor, TypedArrayLikeAdapter,
TypedArrayLikeMutator, UntypedArrayLikeAccessor, UntypedArrayLikeMutator, TypedArrayLikeMutator, UntypedArrayLikeAccessor, UntypedArrayLikeMutator,
}, },
expr::gen_binop_expr_with_values, expr::gen_binop_expr_with_values,
irrt::call_nac3_ndarray_fill_generic, irrt::{
calculate_len_for_slice_range, call_ndarray_calc_broadcast,
call_ndarray_calc_broadcast_index, call_ndarray_calc_nd_indices,
call_ndarray_calc_size,
},
llvm_intrinsics::{self, call_memcpy_generic}, llvm_intrinsics::{self, call_memcpy_generic},
stmt::{gen_for_callback_incrementing, gen_for_range_callback, gen_if_else_expr_callback}, stmt::{gen_for_callback_incrementing, gen_for_range_callback, gen_if_else_expr_callback},
CodeGenContext, CodeGenerator, CodeGenContext, CodeGenerator,
@ -22,7 +26,7 @@ use crate::{
typedef::{FunSignature, Type, TypeEnum}, typedef::{FunSignature, Type, TypeEnum},
}, },
}; };
use inkwell::types::{AnyTypeEnum, BasicTypeEnum, IntType, PointerType}; use inkwell::types::{AnyTypeEnum, BasicTypeEnum, PointerType};
use inkwell::{ use inkwell::{
types::BasicType, types::BasicType,
values::{BasicValueEnum, IntValue, PointerValue}, values::{BasicValueEnum, IntValue, PointerValue},
@ -30,8 +34,6 @@ use inkwell::{
}; };
use nac3parser::ast::{Operator, StrRef}; use nac3parser::ast::{Operator, StrRef};
use super::{classes::NpArrayValue, stmt::gen_return};
// /// Creates an uninitialized `NDArray` instance. // /// Creates an uninitialized `NDArray` instance.
// fn create_ndarray_uninitialized<'ctx, G: CodeGenerator + ?Sized>( // fn create_ndarray_uninitialized<'ctx, G: CodeGenerator + ?Sized>(
// generator: &mut G, // generator: &mut G,
@ -2013,335 +2015,3 @@ use super::{classes::NpArrayValue, stmt::gen_return};
// Ok(()) // Ok(())
// } // }
// //
fn simple_assert<'ctx, G>(
generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>,
cond: IntValue<'ctx>,
msg: &str,
) where
G: CodeGenerator + ?Sized,
{
let mut full_msg = String::from("simple_assert failed: ");
full_msg.push_str(msg);
ctx.make_assert(
generator,
cond,
"0:ValueError",
full_msg.as_str(),
[None, None, None],
ctx.current_loc,
);
}
fn copy_array_slice<'ctx, G, Src, Dst>(
generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>,
dst: Dst,
src: Src,
) where
G: CodeGenerator + ?Sized,
Dst: TypedArrayLikeMutator<'ctx, IntType<'ctx>>,
Src: TypedArrayLikeAccessor<'ctx, IntType<'ctx>>,
{
// Sanity check
let len_match = ctx
.builder
.build_int_compare(
IntPredicate::EQ,
src.size(ctx, generator),
dst.size(ctx, generator),
"len_match",
)
.unwrap();
simple_assert(generator, ctx, len_match, "copy_array_slice length mismatched");
let size_type = generator.get_size_type(ctx.ctx);
let init_val = size_type.const_zero();
let max_val = (dst.size(ctx, generator), false);
let incr_val = size_type.const_int(1, false);
gen_for_callback_incrementing(
generator,
ctx,
init_val,
max_val,
|generator, ctx, _hooks, idx| {
let value = src.get_typed(ctx, generator, &idx, Some("copy_array_slice.tmp"));
dst.set_typed(ctx, generator, &idx, value);
Ok(())
},
incr_val,
)
.unwrap();
}
pub fn alloca_ndarray_uninitialized<'ctx, G>(
generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>,
elem_type: BasicTypeEnum<'ctx>,
ndims: IntValue<'ctx>,
name: Option<&str>,
) -> Result<NpArrayValue<'ctx>, String>
where
G: CodeGenerator + ?Sized,
{
let size_type = generator.get_size_type(ctx.ctx);
let ndarray_ty = NpArrayType { size_type, elem_type };
let ndarray = ndarray_ty.var_alloc(generator, ctx, ndims, name);
Ok(ndarray)
}
pub struct Producer<'ctx, G: CodeGenerator + ?Sized, T> {
pub count: IntValue<'ctx>,
pub write_to_slice: Box<
dyn Fn(
&mut G,
&mut CodeGenContext<'ctx, '_>,
&TypedArrayLikeAdapter<'ctx, T>,
) -> Result<(), String>
+ 'ctx,
>,
}
/// TODO: UPDATE DOCUMENTATION
/// LLVM-typed implementation for generating a [`Producer`] that sets a list of ints.
///
/// * `elem_ty` - The element type of the `NDArray`.
/// * `shape` - The `shape` parameter used to construct the `NDArray`.
///
/// ### Notes on `shape`
///
/// Just like numpy, the `shape` argument can be:
/// 1. A list of `int32`; e.g., `np.empty([600, 800, 3])`
/// 2. A tuple of `int32`; e.g., `np.empty((600, 800, 3))`
/// 3. A scalar `int32`; e.g., `np.empty(3)`, this is functionally equivalent to `np.empty([3])`
///
/// See also [`typecheck::type_inferencer::fold_numpy_function_call_shape_argument`] to
/// learn how `shape` gets from being a Python user expression to here.
fn parse_input_shape_arg<'ctx, G>(
generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>,
shape: BasicValueEnum<'ctx>,
shape_ty: Type,
) -> Result<Producer<'ctx, G, IntValue<'ctx>>, String>
where
G: CodeGenerator + ?Sized,
{
let size_type = generator.get_size_type(ctx.ctx);
match &*ctx.unifier.get_ty(shape_ty) {
TypeEnum::TObj { obj_id, .. }
if *obj_id == ctx.primitives.list.obj_id(&ctx.unifier).unwrap() =>
{
// 1. A list of ints; e.g., `np.empty([600, 800, 3])`
// A list has to be a PointerValue
let shape_list = ListValue::from_ptr_val(shape.into_pointer_value(), size_type, None);
// Create `Producer`
let ndims = shape_list.load_size(ctx, Some("count"));
Ok(Producer {
count: ndims,
write_to_slice: Box::new(move |ctx, generator, dst_slice| {
// Basically iterate through the list and write to `dst_slice` accordingly
let init_val = size_type.const_zero();
let max_val = (ndims, false);
let incr_val = size_type.const_int(1, false);
gen_for_callback_incrementing(
ctx,
generator,
init_val,
max_val,
|generator, ctx, _hooks, idx| {
// Get the dimension at `idx`
let dim =
shape_list.data().get(ctx, generator, &idx, None).into_int_value();
// Cast `dim` to SizeT
let dim = ctx
.builder
.build_int_s_extend_or_bit_cast(dim, size_type, "dim_casted")
.unwrap();
// Write
dst_slice.set_typed(ctx, generator, &idx, dim);
Ok(())
},
incr_val,
)?;
Ok(())
}),
})
}
TypeEnum::TTuple { ty: tuple_types } => {
// 2. A tuple of ints; e.g., `np.empty((600, 800, 3))`
// Get the length/size of the tuple, which also happens to be the value of `ndims`.
let ndims = tuple_types.len();
// A tuple has to be a StructValue
// Read [`codegen::expr::gen_expr`] to see how `nac3core` translates a Python tuple into LLVM.
let shape_tuple = shape.into_struct_value();
Ok(Producer {
count: size_type.const_int(ndims as u64, false),
write_to_slice: Box::new(move |generator, ctx, dst_slice| {
for dim_i in 0..ndims {
// Get the dimension at `dim_i`
let dim = ctx
.builder
.build_extract_value(
shape_tuple,
dim_i as u32,
format!("dim{dim_i}").as_str(),
)
.unwrap()
.into_int_value();
// Cast `dim` to SizeT
let dim = ctx
.builder
.build_int_s_extend_or_bit_cast(dim, size_type, "dim_casted")
.unwrap();
// Write
dst_slice.set_typed(
ctx,
generator,
&size_type.const_int(dim_i as u64, false),
dim,
);
}
Ok(())
}),
})
}
TypeEnum::TObj { obj_id, .. }
if *obj_id == ctx.primitives.int32.obj_id(&ctx.unifier).unwrap() =>
{
// 3. A scalar int; e.g., `np.empty(3)`, this is functionally equivalent to `np.empty([3])`
// The value has to be an integer
let shape_int = shape.into_int_value();
Ok(Producer {
count: size_type.const_int(1, false),
write_to_slice: Box::new(move |generator, ctx, dst_slice| {
// Only index 0 is set with the input value
let dim_i = size_type.const_zero();
// Cast `shape_int` to SizeT
let dim = ctx
.builder
.build_int_s_extend_or_bit_cast(shape_int, size_type, "dim_casted")
.unwrap();
// Write
dst_slice.set_typed(ctx, generator, &dim_i, dim);
Ok(())
}),
})
}
_ => panic!("parse_input_shape_arg encountered unknown type"),
}
}
/// TODO: DOCUMENT ME
fn alloca_ndarray_uninitialized_shaped<'ctx, G>(
generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>,
elem_type: BasicTypeEnum<'ctx>,
shape_producer: Producer<'ctx, G, IntValue<'ctx>>,
name: Option<&str>,
) -> Result<NpArrayValue<'ctx>, String>
where
G: CodeGenerator + ?Sized,
{
// Allocate an uninitialized ndarray
let ndims = shape_producer.count;
let ndarray = alloca_ndarray_uninitialized(generator, ctx, elem_type, ndims, name)?;
// Fill `ndarray.shape` with `shape_producer`
(shape_producer.write_to_slice)(generator, ctx, &ndarray.shape_slice(ctx))?;
Ok(ndarray)
}
/// LLVM-typed implementation for generating the implementation for constructing an empty `NDArray`.
fn call_ndarray_empty_impl<'ctx, G>(
generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>,
elem_ty: Type,
shape: BasicValueEnum<'ctx>,
shape_ty: Type,
name: Option<&str>,
) -> Result<NpArrayValue<'ctx>, String>
where
G: CodeGenerator + ?Sized,
{
let elem_type = ctx.get_llvm_type(generator, elem_ty);
let shape_producer = parse_input_shape_arg(generator, ctx, shape, shape_ty)?;
alloca_ndarray_uninitialized_shaped(generator, ctx, elem_type, shape_producer, name)
}
/// Generates LLVM IR for `np.empty`.
pub fn gen_ndarray_empty<'ctx>(
context: &mut CodeGenContext<'ctx, '_>,
obj: &Option<(Type, ValueEnum<'ctx>)>,
fun: (&FunSignature, DefinitionId),
args: &[(Option<StrRef>, ValueEnum<'ctx>)],
generator: &mut dyn CodeGenerator,
) -> Result<PointerValue<'ctx>, String> {
assert!(obj.is_none());
assert_eq!(args.len(), 1);
let shape_ty = fun.0.args[0].ty;
let shape = args[0].1.clone().to_basic_value_enum(context, generator, shape_ty)?;
let ndarray = call_ndarray_empty_impl(
generator,
context,
context.primitives.float,
shape,
shape_ty,
None,
)?;
Ok(ndarray.ptr)
}
/// Generates LLVM IR for `np.zeros`.
///
/// NOTE: Current `dtype` is always `float64`.
pub fn gen_ndarray_zeros<'ctx>(
context: &mut CodeGenContext<'ctx, '_>,
obj: &Option<(Type, ValueEnum<'ctx>)>,
fun: (&FunSignature, DefinitionId),
args: &[(Option<StrRef>, ValueEnum<'ctx>)],
generator: &mut dyn CodeGenerator,
) -> Result<PointerValue<'ctx>, String> {
assert!(obj.is_none());
assert_eq!(args.len(), 1);
let shape_ty = fun.0.args[0].ty;
let shape = args[0].1.clone().to_basic_value_enum(context, generator, shape_ty)?;
// Allocate an ndarray and fill it later
let ndarray = call_ndarray_empty_impl(
generator,
context,
context.primitives.float, // float64
shape,
shape_ty,
None,
)?;
// TRICK: The float64 type could be conveniently extracted out of `ndarray`
let float_type = ndarray.ty.elem_type.into_float_type();
// Fill the ndarray
call_nac3_ndarray_fill_generic(context, ndarray, float_type.const_float(1.0).into());
// Return our ndarray
println!("ndarray.ptr = {}", ndarray.ptr);
Ok(ndarray.ptr)
}

View File

@ -23,4 +23,4 @@ pub mod codegen;
pub mod symbol_resolver; pub mod symbol_resolver;
pub mod toplevel; pub mod toplevel;
pub mod typecheck; pub mod typecheck;
pub mod util; pub mod util;

View File

@ -1193,13 +1193,14 @@ impl<'a> BuiltinBuilder<'a> {
self.ndarray_float, self.ndarray_float,
&[(self.ndarray_factory_fn_shape_arg_tvar.ty, "shape")], &[(self.ndarray_factory_fn_shape_arg_tvar.ty, "shape")],
Box::new(move |ctx, obj, fun, args, generator| { Box::new(move |ctx, obj, fun, args, generator| {
let func = match prim { todo!()
PrimDef::FunNpNDArray | PrimDef::FunNpEmpty => gen_ndarray_empty, // let func = match prim {
PrimDef::FunNpZeros => gen_ndarray_zeros, // PrimDef::FunNpNDArray | PrimDef::FunNpEmpty => gen_ndarray_empty,
PrimDef::FunNpOnes => todo!(), // gen_ndarray_ones, // PrimDef::FunNpZeros => gen_ndarray_zeros,
_ => unreachable!(), // PrimDef::FunNpOnes => gen_ndarray_ones,
}; // _ => unreachable!(),
func(ctx, &obj, fun, &args, generator).map(|val| Some(val.as_basic_value_enum())) // };
// func(ctx, &obj, fun, &args, generator).map(|val| Some(val.as_basic_value_enum()))
}), }),
) )
} }

View File

@ -1,5 +0,0 @@
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SizeVariant {
Bits32,
Bits64,
}

View File

@ -1,3 +0,0 @@
def run() -> int32:
hello = np_zeros((3, 4))
return 0

View File

@ -449,9 +449,6 @@ fn main() {
.create_target_machine(llvm_options.opt_level) .create_target_machine(llvm_options.opt_level)
.expect("couldn't create target machine"); .expect("couldn't create target machine");
// NOTE: DEBUG PRINT
main.print_to_file("standalone.ll").unwrap();
let pass_options = PassBuilderOptions::create(); let pass_options = PassBuilderOptions::create();
pass_options.set_merge_functions(true); pass_options.set_merge_functions(true);
let passes = format!("default<O{}>", opt_level as u32); let passes = format!("default<O{}>", opt_level as u32);