Compare commits

..

13 Commits

Author SHA1 Message Date
David Mak b2994ff90a WIP 2024-03-21 21:16:05 +08:00
David Mak 2d1f243975 core: Implement elementwise binary operators
Including immediate variants of these operators.
2024-03-21 21:11:43 +08:00
David Mak 4f236ea411 core: Add handling of ndarrays in gen_binop_expr 2024-03-21 21:11:43 +08:00
David Mak e3fe3f03fb core: Implement calculations for broadcasting ndarrays 2024-03-21 21:11:43 +08:00
David Mak deb325de4f core: Extract codegen portion of gen_binop_expr
This allows binops to be generated internally using LLVM values as
input. Required in a future change.
2024-03-21 21:11:43 +08:00
David Mak aa84cc425f core: Refactor VarMap to IndexMap
This is the only Map I can find that preserves insertion order while
also deduplicating elements by key.
2024-03-21 21:10:39 +08:00
David Mak f7fbc629aa core: Add ArrayLikeValue
For exposing LLVM values that can be accessed like an array.
2024-03-21 21:10:19 +08:00
David Mak 724651d2bb core: Allow unsized CodeGenerator to be passed to some codegen functions
Enables codegen_callback to call these codegen functions as well.
2024-03-21 15:46:10 +08:00
David Mak 2665668e21 core: Simplify typed value assertions 2024-03-21 15:46:10 +08:00
David Mak 9b1c559efb core: Add gen_for_callback_incrementing
Simplifies generation of monotonically increasing for loops.
2024-03-21 15:46:10 +08:00
David Mak 5ecc2a905e core: Add missing unchecked accessors for NDArrayDimsProxy 2024-03-21 15:46:10 +08:00
David Mak 2a8a5bbfea core: Split numpy into codegen and toplevel 2024-03-21 15:46:10 +08:00
David Mak 3ed8ce7215 core: Apply clippy suggestions 2024-03-21 15:46:10 +08:00
8 changed files with 218 additions and 109 deletions

View File

@ -1,12 +1,12 @@
use inkwell::{ use inkwell::{
IntPredicate, IntPredicate,
types::{AnyTypeEnum, BasicTypeEnum, IntType, PointerType}, types::{AnyTypeEnum, BasicTypeEnum, IntType, PointerType},
values::{BasicValueEnum, IntValue, PointerValue}, values::{ArrayValue, BasicValueEnum, IntValue, PointerValue},
}; };
use crate::codegen::{ use crate::codegen::{
CodeGenContext, CodeGenContext,
CodeGenerator, CodeGenerator,
irrt::{call_ndarray_calc_size, call_ndarray_flatten_index}, irrt::{call_ndarray_calc_size, call_ndarray_flatten_index, call_ndarray_flatten_index_const},
llvm_intrinsics::call_int_umin, llvm_intrinsics::call_int_umin,
stmt::gen_for_callback_incrementing, stmt::gen_for_callback_incrementing,
}; };
@ -200,7 +200,8 @@ type ValueDowncastFn<'ctx, T> = Box<dyn Fn(&mut CodeGenContext<'ctx, '_>, BasicV
type ValueUpcastFn<'ctx, T> = Box<dyn Fn(&mut CodeGenContext<'ctx, '_>, T) -> BasicValueEnum<'ctx>>; type ValueUpcastFn<'ctx, T> = Box<dyn Fn(&mut CodeGenContext<'ctx, '_>, T) -> BasicValueEnum<'ctx>>;
/// An adapter for constraining untyped array values as typed values. /// An adapter for constraining untyped array values as typed values.
pub struct TypedArrayLikeAdapter<'ctx, T, Adapted: ArrayLikeValue<'ctx> = ArraySliceValue<'ctx>> { #[allow(clippy::type_complexity)]
pub struct TypedArrayLikeAdapter<'ctx, T, Adapted: ArrayLikeValue<'ctx>> {
adapted: Adapted, adapted: Adapted,
downcast_fn: ValueDowncastFn<'ctx, T>, downcast_fn: ValueDowncastFn<'ctx, T>,
upcast_fn: ValueUpcastFn<'ctx, T>, upcast_fn: ValueUpcastFn<'ctx, T>,
@ -213,7 +214,7 @@ impl<'ctx, T, Adapted> TypedArrayLikeAdapter<'ctx, T, Adapted>
/// * `adapted` - The value to be adapted. /// * `adapted` - The value to be adapted.
/// * `downcast_fn` - The function converting a [`BasicValueEnum`] into a `T`. /// * `downcast_fn` - The function converting a [`BasicValueEnum`] into a `T`.
/// * `upcast_fn` - The function converting a T into a [`BasicValueEnum`]. /// * `upcast_fn` - The function converting a T into a [`BasicValueEnum`].
pub fn from( fn from(
adapted: Adapted, adapted: Adapted,
downcast_fn: ValueDowncastFn<'ctx, T>, downcast_fn: ValueDowncastFn<'ctx, T>,
upcast_fn: ValueUpcastFn<'ctx, T>, upcast_fn: ValueUpcastFn<'ctx, T>,
@ -497,8 +498,8 @@ impl<'ctx> ListValue<'ctx> {
/// Returns the double-indirection pointer to the `data` array, as if by calling `getelementptr` /// Returns the double-indirection pointer to the `data` array, as if by calling `getelementptr`
/// on the field. /// on the field.
#[must_use] #[must_use]
pub fn data(&self) -> ListDataProxy<'ctx, '_> { pub fn data(&self) -> ListDataProxy<'ctx> {
ListDataProxy(self) ListDataProxy(*self)
} }
/// Stores the `size` of this `list` into this instance. /// Stores the `size` of this `list` into this instance.
@ -536,9 +537,9 @@ impl<'ctx> From<ListValue<'ctx>> for PointerValue<'ctx> {
/// Proxy type for accessing the `data` array of an `list` instance in LLVM. /// Proxy type for accessing the `data` array of an `list` instance in LLVM.
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct ListDataProxy<'ctx, 'a>(&'a ListValue<'ctx>); pub struct ListDataProxy<'ctx>(ListValue<'ctx>);
impl<'ctx> ArrayLikeValue<'ctx> for ListDataProxy<'ctx, '_> { impl<'ctx> ArrayLikeValue<'ctx> for ListDataProxy<'ctx> {
fn element_type<G: CodeGenerator + ?Sized>( fn element_type<G: CodeGenerator + ?Sized>(
&self, &self,
_: &CodeGenContext<'ctx, '_>, _: &CodeGenContext<'ctx, '_>,
@ -568,7 +569,7 @@ impl<'ctx> ArrayLikeValue<'ctx> for ListDataProxy<'ctx, '_> {
} }
} }
impl<'ctx> ArrayLikeIndexer<'ctx> for ListDataProxy<'ctx, '_> { impl<'ctx> ArrayLikeIndexer<'ctx> for ListDataProxy<'ctx> {
unsafe fn ptr_offset_unchecked<G: CodeGenerator + ?Sized>( unsafe fn ptr_offset_unchecked<G: CodeGenerator + ?Sized>(
&self, &self,
ctx: &mut CodeGenContext<'ctx, '_>, ctx: &mut CodeGenContext<'ctx, '_>,
@ -613,8 +614,8 @@ impl<'ctx> ArrayLikeIndexer<'ctx> for ListDataProxy<'ctx, '_> {
} }
} }
impl<'ctx> UntypedArrayLikeAccessor<'ctx> for ListDataProxy<'ctx, '_> {} impl<'ctx> UntypedArrayLikeAccessor<'ctx> for ListDataProxy<'ctx> {}
impl<'ctx> UntypedArrayLikeMutator<'ctx> for ListDataProxy<'ctx, '_> {} impl<'ctx> UntypedArrayLikeMutator<'ctx> for ListDataProxy<'ctx> {}
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
pub fn assert_is_range(_value: PointerValue) {} pub fn assert_is_range(_value: PointerValue) {}
@ -928,8 +929,8 @@ impl<'ctx> NDArrayValue<'ctx> {
/// Returns a proxy object to the field storing the size of each dimension of this `NDArray`. /// Returns a proxy object to the field storing the size of each dimension of this `NDArray`.
#[must_use] #[must_use]
pub fn dim_sizes(&self) -> NDArrayDimsProxy<'ctx, '_> { pub fn dim_sizes(&self) -> NDArrayDimsProxy<'ctx> {
NDArrayDimsProxy(self) NDArrayDimsProxy(*self)
} }
/// Returns the double-indirection pointer to the `data` array, as if by calling `getelementptr` /// Returns the double-indirection pointer to the `data` array, as if by calling `getelementptr`
@ -965,8 +966,8 @@ impl<'ctx> NDArrayValue<'ctx> {
/// Returns a proxy object to the field storing the data of this `NDArray`. /// Returns a proxy object to the field storing the data of this `NDArray`.
#[must_use] #[must_use]
pub fn data(&self) -> NDArrayDataProxy<'ctx, '_> { pub fn data(&self) -> NDArrayDataProxy<'ctx> {
NDArrayDataProxy(self) NDArrayDataProxy(*self)
} }
} }
@ -978,9 +979,9 @@ impl<'ctx> From<NDArrayValue<'ctx>> for PointerValue<'ctx> {
/// Proxy type for accessing the `dims` array of an `NDArray` instance in LLVM. /// Proxy type for accessing the `dims` array of an `NDArray` instance in LLVM.
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct NDArrayDimsProxy<'ctx, 'a>(&'a NDArrayValue<'ctx>); pub struct NDArrayDimsProxy<'ctx>(NDArrayValue<'ctx>);
impl<'ctx> ArrayLikeValue<'ctx> for NDArrayDimsProxy<'ctx, '_> { impl<'ctx> ArrayLikeValue<'ctx> for NDArrayDimsProxy<'ctx> {
fn element_type<G: CodeGenerator + ?Sized>( fn element_type<G: CodeGenerator + ?Sized>(
&self, &self,
ctx: &CodeGenContext<'ctx, '_>, ctx: &CodeGenContext<'ctx, '_>,
@ -1010,7 +1011,7 @@ impl<'ctx> ArrayLikeValue<'ctx> for NDArrayDimsProxy<'ctx, '_> {
} }
} }
impl<'ctx> ArrayLikeIndexer<'ctx, IntValue<'ctx>> for NDArrayDimsProxy<'ctx, '_> { impl<'ctx> ArrayLikeIndexer<'ctx, IntValue<'ctx>> for NDArrayDimsProxy<'ctx> {
unsafe fn ptr_offset_unchecked<G: CodeGenerator + ?Sized>( unsafe fn ptr_offset_unchecked<G: CodeGenerator + ?Sized>(
&self, &self,
ctx: &mut CodeGenContext<'ctx, '_>, ctx: &mut CodeGenContext<'ctx, '_>,
@ -1058,10 +1059,10 @@ impl<'ctx> ArrayLikeIndexer<'ctx, IntValue<'ctx>> for NDArrayDimsProxy<'ctx, '_>
} }
} }
impl<'ctx> UntypedArrayLikeAccessor<'ctx, IntValue<'ctx>> for NDArrayDimsProxy<'ctx, '_> {} impl<'ctx> UntypedArrayLikeAccessor<'ctx, IntValue<'ctx>> for NDArrayDimsProxy<'ctx> {}
impl<'ctx> UntypedArrayLikeMutator<'ctx, IntValue<'ctx>> for NDArrayDimsProxy<'ctx, '_> {} impl<'ctx> UntypedArrayLikeMutator<'ctx, IntValue<'ctx>> for NDArrayDimsProxy<'ctx> {}
impl<'ctx> TypedArrayLikeAccessor<'ctx, IntValue<'ctx>> for NDArrayDimsProxy<'ctx, '_> { impl<'ctx> TypedArrayLikeAccessor<'ctx, IntValue<'ctx>> for NDArrayDimsProxy<'ctx> {
fn downcast_to_type( fn downcast_to_type(
&self, &self,
_: &mut CodeGenContext<'ctx, '_>, _: &mut CodeGenContext<'ctx, '_>,
@ -1071,7 +1072,7 @@ impl<'ctx> TypedArrayLikeAccessor<'ctx, IntValue<'ctx>> for NDArrayDimsProxy<'ct
} }
} }
impl<'ctx> TypedArrayLikeMutator<'ctx, IntValue<'ctx>> for NDArrayDimsProxy<'ctx, '_> { impl<'ctx> TypedArrayLikeMutator<'ctx, IntValue<'ctx>> for NDArrayDimsProxy<'ctx> {
fn upcast_from_type( fn upcast_from_type(
&self, &self,
_: &mut CodeGenContext<'ctx, '_>, _: &mut CodeGenContext<'ctx, '_>,
@ -1083,9 +1084,9 @@ impl<'ctx> TypedArrayLikeMutator<'ctx, IntValue<'ctx>> for NDArrayDimsProxy<'ctx
/// Proxy type for accessing the `data` array of an `NDArray` instance in LLVM. /// Proxy type for accessing the `data` array of an `NDArray` instance in LLVM.
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct NDArrayDataProxy<'ctx, 'a>(&'a NDArrayValue<'ctx>); pub struct NDArrayDataProxy<'ctx>(NDArrayValue<'ctx>);
impl<'ctx> ArrayLikeValue<'ctx> for NDArrayDataProxy<'ctx, '_> { impl<'ctx> ArrayLikeValue<'ctx> for NDArrayDataProxy<'ctx> {
fn element_type<G: CodeGenerator + ?Sized>( fn element_type<G: CodeGenerator + ?Sized>(
&self, &self,
ctx: &CodeGenContext<'ctx, '_>, ctx: &CodeGenContext<'ctx, '_>,
@ -1115,7 +1116,7 @@ impl<'ctx> ArrayLikeValue<'ctx> for NDArrayDataProxy<'ctx, '_> {
} }
} }
impl<'ctx> ArrayLikeIndexer<'ctx> for NDArrayDataProxy<'ctx, '_> { impl<'ctx> ArrayLikeIndexer<'ctx> for NDArrayDataProxy<'ctx> {
unsafe fn ptr_offset_unchecked<G: CodeGenerator + ?Sized>( unsafe fn ptr_offset_unchecked<G: CodeGenerator + ?Sized>(
&self, &self,
ctx: &mut CodeGenContext<'ctx, '_>, ctx: &mut CodeGenContext<'ctx, '_>,
@ -1159,10 +1160,102 @@ impl<'ctx> ArrayLikeIndexer<'ctx> for NDArrayDataProxy<'ctx, '_> {
} }
} }
impl<'ctx> UntypedArrayLikeAccessor<'ctx, IntValue<'ctx>> for NDArrayDataProxy<'ctx, '_> {} impl<'ctx> UntypedArrayLikeAccessor<'ctx, IntValue<'ctx>> for NDArrayDataProxy<'ctx> {}
impl<'ctx> UntypedArrayLikeMutator<'ctx, IntValue<'ctx>> for NDArrayDataProxy<'ctx, '_> {} impl<'ctx> UntypedArrayLikeMutator<'ctx, IntValue<'ctx>> for NDArrayDataProxy<'ctx> {}
impl<'ctx, Index: UntypedArrayLikeAccessor<'ctx>> ArrayLikeIndexer<'ctx, Index> for NDArrayDataProxy<'ctx, '_> { impl<'ctx> ArrayLikeIndexer<'ctx, ArrayValue<'ctx>> for NDArrayDataProxy<'ctx> {
unsafe fn ptr_offset_unchecked<G: CodeGenerator + ?Sized>(
&self,
ctx: &mut CodeGenContext<'ctx, '_>,
generator: &mut G,
indices: ArrayValue<'ctx>,
name: Option<&str>,
) -> PointerValue<'ctx> {
let index = call_ndarray_flatten_index_const(
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<G: CodeGenerator + ?Sized>(
&self,
ctx: &mut CodeGenContext<'ctx, '_>,
generator: &mut G,
indices: ArrayValue<'ctx>,
name: Option<&str>,
) -> PointerValue<'ctx> {
let llvm_usize = generator.get_size_type(ctx.ctx);
let indices_elem_ty = indices.get_type().get_element_type();
let Ok(indices_elem_ty) = IntType::try_from(indices_elem_ty) else {
panic!("Expected [int32] but got [{indices_elem_ty}]")
};
assert_eq!(indices_elem_ty.get_bit_width(), 32, "Expected [int32] but got [{indices_elem_ty}]");
let nidx_leq_ndims = ctx.builder.build_int_compare(
IntPredicate::SLE,
llvm_usize.const_int(indices.get_type().len() as u64, false),
self.0.load_ndims(ctx),
""
).unwrap();
ctx.make_assert(
generator,
nidx_leq_ndims,
"0:IndexError",
"invalid index to scalar variable",
[None, None, None],
ctx.current_loc,
);
for idx in 0..indices.get_type().len() {
let i = llvm_usize.const_int(idx as u64, false);
let dim_idx = ctx.builder
.build_extract_value(indices, idx, "")
.map(BasicValueEnum::into_int_value)
.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_typed_unchecked(ctx, generator, i, None)
};
let dim_lt = ctx.builder.build_int_compare(
IntPredicate::SLT,
dim_idx,
dim_sz,
""
).unwrap();
ctx.make_assert(
generator,
dim_lt,
"0:IndexError",
"index {0} is out of bounds for axis 0 with size {1}",
[Some(dim_idx), Some(dim_sz), None],
ctx.current_loc,
);
}
unsafe {
self.ptr_offset_unchecked(ctx, generator, indices, name)
}
}
}
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<G: CodeGenerator + ?Sized>( unsafe fn ptr_offset_unchecked<G: CodeGenerator + ?Sized>(
&self, &self,
ctx: &mut CodeGenContext<'ctx, '_>, ctx: &mut CodeGenContext<'ctx, '_>,
@ -1176,12 +1269,12 @@ impl<'ctx, Index: UntypedArrayLikeAccessor<'ctx>> ArrayLikeIndexer<'ctx, Index>
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!(indices_elem_ty.get_bit_width(), 32, "Expected list[int32] but got list[int{}]", indices_elem_ty.get_bit_width()); assert_eq!(indices_elem_ty.get_bit_width(), 32, "Expected list[int32] but got {indices_elem_ty}");
let index = call_ndarray_flatten_index( let index = call_ndarray_flatten_index(
generator, generator,
ctx, ctx,
*self.0, self.0,
&indices, &indices,
); );
@ -1234,9 +1327,6 @@ impl<'ctx, Index: UntypedArrayLikeAccessor<'ctx>> ArrayLikeIndexer<'ctx, Index>
self.0.dim_sizes().get_typed_unchecked(ctx, generator, i, None), self.0.dim_sizes().get_typed_unchecked(ctx, generator, i, None),
) )
}; };
let dim_idx = ctx.builder
.build_int_z_extend_or_bit_cast(dim_idx, dim_sz.get_type(), "")
.unwrap();
let dim_lt = ctx.builder.build_int_compare( let dim_lt = ctx.builder.build_int_compare(
IntPredicate::SLT, IntPredicate::SLT,
@ -1265,5 +1355,5 @@ impl<'ctx, Index: UntypedArrayLikeAccessor<'ctx>> ArrayLikeIndexer<'ctx, Index>
} }
} }
impl<'ctx, Index: UntypedArrayLikeAccessor<'ctx>> UntypedArrayLikeAccessor<'ctx, Index> for NDArrayDataProxy<'ctx, '_> {} impl<'ctx, Index: UntypedArrayLikeAccessor<'ctx>> UntypedArrayLikeAccessor<'ctx, Index> for NDArrayDataProxy<'ctx> {}
impl<'ctx, Index: UntypedArrayLikeAccessor<'ctx>> UntypedArrayLikeMutator<'ctx, Index> for NDArrayDataProxy<'ctx, '_> {} impl<'ctx, Index: UntypedArrayLikeAccessor<'ctx>> UntypedArrayLikeMutator<'ctx, Index> for NDArrayDataProxy<'ctx> {}

View File

@ -43,7 +43,6 @@ use itertools::{chain, izip, Itertools, Either};
use nac3parser::ast::{ use nac3parser::ast::{
self, Boolop, Comprehension, Constant, Expr, ExprKind, Location, Operator, StrRef, self, Boolop, Comprehension, Constant, Expr, ExprKind, Location, Operator, StrRef,
}; };
use crate::codegen::classes::ArraySliceValue;
use super::{CodeGenerator, llvm_intrinsics::call_memcpy_generic, need_sret}; use super::{CodeGenerator, llvm_intrinsics::call_memcpy_generic, need_sret};
@ -1331,14 +1330,12 @@ fn gen_ndarray_subscript_expr<'ctx, G: CodeGenerator>(
} else { } else {
return Ok(None) return Ok(None)
}; };
let index_addr = generator.gen_var_alloc(ctx, index.get_type().into(), None)?;
ctx.builder.build_store(index_addr, index).unwrap();
Ok(Some(v.data() Ok(Some(v.data()
.get( .get(
ctx, ctx,
generator, generator,
ArraySliceValue::from_ptr_val(index_addr, llvm_usize.const_int(1, false), None), ctx.ctx.i32_type().const_array(&[index]),
None, None,
) )
.into())) .into()))
@ -1354,8 +1351,6 @@ fn gen_ndarray_subscript_expr<'ctx, G: CodeGenerator>(
} else { } else {
return Ok(None) return Ok(None)
}; };
let index_addr = generator.gen_var_alloc(ctx, index.get_type().into(), None)?;
ctx.builder.build_store(index_addr, index).unwrap();
// Create a new array, remove the top dimension from the dimension-size-list, and copy the // Create a new array, remove the top dimension from the dimension-size-list, and copy the
// elements over // elements over
@ -1410,7 +1405,7 @@ fn gen_ndarray_subscript_expr<'ctx, G: CodeGenerator>(
let v_data_src_ptr = v.data().ptr_offset( let v_data_src_ptr = v.data().ptr_offset(
ctx, ctx,
generator, generator,
ArraySliceValue::from_ptr_val(index_addr, llvm_usize.const_int(1, false), None), ctx.ctx.i32_type().const_array(&[index]),
None None
); );
call_memcpy_generic( call_memcpy_generic(

View File

@ -245,13 +245,13 @@ void __nac3_ndarray_calc_nd_indices64(
uint64_t index, uint64_t index,
const uint64_t* dims, const uint64_t* dims,
uint64_t num_dims, uint64_t num_dims,
uint32_t* idxs uint64_t* idxs
) { ) {
uint64_t stride = 1; uint64_t stride = 1;
for (uint64_t dim = 0; dim < num_dims; dim++) { for (uint64_t dim = 0; dim < num_dims; dim++) {
uint64_t i = num_dims - dim - 1; uint64_t i = num_dims - dim - 1;
__builtin_assume(dims[i] > 0); __builtin_assume(dims[i] > 0);
idxs[i] = (uint32_t) ((index / stride) % dims[i]); idxs[i] = (index / stride) % dims[i];
stride *= dims[i]; stride *= dims[i];
} }
} }
@ -371,11 +371,11 @@ void __nac3_ndarray_calc_broadcast_idx(
void __nac3_ndarray_calc_broadcast_idx64( void __nac3_ndarray_calc_broadcast_idx64(
const uint64_t *src_dims, const uint64_t *src_dims,
uint64_t src_ndims, uint64_t src_ndims,
const uint32_t *in_idx, const uint64_t *in_idx,
uint32_t *out_idx uint64_t *out_idx
) { ) {
for (uint64_t i = 0; i < src_ndims; ++i) { for (uint64_t i = 0; i < src_ndims; ++i) {
uint64_t src_i = src_ndims - i - 1; uint64_t src_i = src_ndims - i - 1;
out_idx[src_i] = src_dims[src_i] == 1 ? 0 : (uint32_t) in_idx[src_i]; out_idx[src_i] = src_dims[src_i] == 1 ? 0 : in_idx[src_i];
} }
} }

View File

@ -3,12 +3,12 @@ use crate::typecheck::typedef::Type;
use super::{ use super::{
classes::{ classes::{
ArrayLikeIndexer, ArrayLikeIndexer,
ArrayLikeValue,
ArraySliceValue, ArraySliceValue,
ArrayLikeValue,
ListValue, ListValue,
NDArrayValue, NDArrayValue,
TypedArrayLikeAdapter,
UntypedArrayLikeAccessor, UntypedArrayLikeAccessor,
UntypedArrayLikeMutator,
}, },
CodeGenContext, CodeGenContext,
CodeGenerator, CodeGenerator,
@ -20,7 +20,7 @@ use inkwell::{
memory_buffer::MemoryBuffer, memory_buffer::MemoryBuffer,
module::Module, module::Module,
types::{BasicTypeEnum, IntType}, types::{BasicTypeEnum, IntType},
values::{BasicValueEnum, CallSiteValue, FloatValue, IntValue}, values::{ArrayValue, BasicValueEnum, CallSiteValue, FloatValue, IntValue, PointerValue},
AddressSpace, IntPredicate, AddressSpace, IntPredicate,
}; };
use itertools::Either; use itertools::Either;
@ -628,8 +628,7 @@ pub fn call_ndarray_calc_size<'ctx, G, Dims>(
.unwrap() .unwrap()
} }
/// Generates a call to `__nac3_ndarray_calc_nd_indices`. Returns a [`TypeArrayLikeAdpater`] /// Generates a call to `__nac3_ndarray_calc_nd_indices`.
/// 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
@ -639,11 +638,10 @@ pub fn call_ndarray_calc_nd_indices<'ctx, G: CodeGenerator + ?Sized>(
ctx: &mut CodeGenContext<'ctx, '_>, ctx: &mut CodeGenContext<'ctx, '_>,
index: IntValue<'ctx>, index: IntValue<'ctx>,
ndarray: NDArrayValue<'ctx>, ndarray: NDArrayValue<'ctx>,
) -> TypedArrayLikeAdapter<'ctx, IntValue<'ctx>> { ) -> ArraySliceValue<'ctx> {
let llvm_void = ctx.ctx.void_type(); let llvm_void = ctx.ctx.void_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_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() {
@ -657,7 +655,7 @@ pub fn call_ndarray_calc_nd_indices<'ctx, G: CodeGenerator + ?Sized>(
llvm_usize.into(), llvm_usize.into(),
llvm_pusize.into(), llvm_pusize.into(),
llvm_usize.into(), llvm_usize.into(),
llvm_pi32.into(), llvm_pusize.into(),
], ],
false, false,
); );
@ -669,7 +667,7 @@ pub fn call_ndarray_calc_nd_indices<'ctx, G: CodeGenerator + ?Sized>(
let ndarray_dims = ndarray.dim_sizes(); let ndarray_dims = ndarray.dim_sizes();
let indices = ctx.builder.build_array_alloca( let indices = ctx.builder.build_array_alloca(
llvm_i32, llvm_usize,
ndarray_num_dims, ndarray_num_dims,
"", "",
).unwrap(); ).unwrap();
@ -687,11 +685,7 @@ pub fn call_ndarray_calc_nd_indices<'ctx, G: CodeGenerator + ?Sized>(
) )
.unwrap(); .unwrap();
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()),
)
} }
fn call_ndarray_flatten_index_impl<'ctx, G, Indices>( fn call_ndarray_flatten_index_impl<'ctx, G, Indices>(
@ -786,6 +780,49 @@ pub fn call_ndarray_flatten_index<'ctx, G, Index>(
indices, indices,
) )
} }
/// Generates a call to `__nac3_ndarray_flatten_index`. Returns the flattened index for the
/// multidimensional index.
///
/// * `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_const<'ctx, G: CodeGenerator + ?Sized>(
generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>,
ndarray: NDArrayValue<'ctx>,
indices: ArrayValue<'ctx>,
) -> IntValue<'ctx> {
let llvm_usize = generator.get_size_type(ctx.ctx);
let indices_size = indices.get_type().len();
let indices_alloca = generator.gen_array_var_alloc(
ctx,
indices.get_type().get_element_type(),
llvm_usize.const_int(indices_size as u64, false),
None,
).unwrap();
for i in 0..indices_size {
let v = ctx.builder.build_extract_value(indices, i, "")
.unwrap()
.into_int_value();
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,
)
}
/// 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`.
@ -794,7 +831,7 @@ pub fn call_ndarray_calc_broadcast<'ctx, G: CodeGenerator + ?Sized>(
ctx: &mut CodeGenContext<'ctx, '_>, ctx: &mut CodeGenContext<'ctx, '_>,
lhs: NDArrayValue<'ctx>, lhs: NDArrayValue<'ctx>,
rhs: NDArrayValue<'ctx>, rhs: NDArrayValue<'ctx>,
) -> TypedArrayLikeAdapter<'ctx, IntValue<'ctx>> { ) -> (IntValue<'ctx>, PointerValue<'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());
@ -844,7 +881,6 @@ pub fn call_ndarray_calc_broadcast<'ctx, G: CodeGenerator + ?Sized>(
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);
ctx.builder ctx.builder
.build_call( .build_call(
@ -854,31 +890,24 @@ pub fn call_ndarray_calc_broadcast<'ctx, G: CodeGenerator + ?Sized>(
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.into(),
], ],
"", "",
) )
.unwrap(); .unwrap();
TypedArrayLikeAdapter::from( (max_ndims, out_dims)
out_dims,
Box::new(|_, v| v.into_int_value()),
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 `broadcast_idx`.
/// array `broadcast_idx`.
pub fn call_ndarray_calc_broadcast_index<'ctx, G: CodeGenerator + ?Sized, BroadcastIdx: UntypedArrayLikeAccessor<'ctx>>( pub fn call_ndarray_calc_broadcast_index<'ctx, G: CodeGenerator + ?Sized, 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>> { ) -> ArraySliceValue<'ctx> {
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_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() {
@ -891,8 +920,8 @@ pub fn call_ndarray_calc_broadcast_index<'ctx, G: CodeGenerator + ?Sized, Broadc
&[ &[
llvm_pusize.into(), llvm_pusize.into(),
llvm_usize.into(), llvm_usize.into(),
llvm_pi32.into(), llvm_pusize.into(),
llvm_pi32.into(), llvm_usize.into(),
], ],
false, false,
); );
@ -903,7 +932,8 @@ pub fn call_ndarray_calc_broadcast_index<'ctx, G: CodeGenerator + ?Sized, Broadc
// TODO: Assertions // TODO: Assertions
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_usize, broadcast_size, "").unwrap();
let out_idx = ArraySliceValue::from_ptr_val(out_idx, broadcast_size, None);
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);
@ -923,15 +953,11 @@ pub fn call_ndarray_calc_broadcast_index<'ctx, G: CodeGenerator + ?Sized, Broadc
array_dims.into(), array_dims.into(),
array_ndims.into(), array_ndims.into(),
broadcast_idx_ptr.into(), broadcast_idx_ptr.into(),
out_idx.into(), out_idx.base_ptr(ctx, generator).into(),
], ],
"", "",
) )
.unwrap(); .unwrap();
TypedArrayLikeAdapter::from( out_idx
ArraySliceValue::from_ptr_val(out_idx, broadcast_size, None),
Box::new(|_, v| v.into_int_value()),
Box::new(|_, v| v.into()),
)
} }

View File

@ -8,18 +8,17 @@ use crate::{
codegen::{ codegen::{
classes::{ classes::{
ArrayLikeIndexer, ArrayLikeIndexer,
ArraySliceValue,
ArrayLikeValue, ArrayLikeValue,
ListValue, ListValue,
NDArrayValue, NDArrayValue,
TypedArrayLikeAccessor, TypedArrayLikeAccessor,
TypedArrayLikeAdapter,
UntypedArrayLikeAccessor, UntypedArrayLikeAccessor,
}, },
CodeGenContext, CodeGenContext,
CodeGenerator, CodeGenerator,
irrt::{ irrt::{
call_ndarray_calc_broadcast, call_ndarray_calc_broadcast,
call_ndarray_calc_broadcast_index,
call_ndarray_calc_nd_indices, call_ndarray_calc_nd_indices,
call_ndarray_calc_size, call_ndarray_calc_size,
}, },
@ -327,7 +326,7 @@ fn ndarray_fill_indexed<'ctx, G, ValueFn>(
) -> Result<(), String> ) -> Result<(), String>
where where
G: CodeGenerator + ?Sized, G: CodeGenerator + ?Sized,
ValueFn: Fn(&mut G, &mut CodeGenContext<'ctx, '_>, TypedArrayLikeAdapter<'ctx, IntValue<'ctx>>) -> Result<BasicValueEnum<'ctx>, String>, ValueFn: Fn(&mut G, &mut CodeGenContext<'ctx, '_>, ArraySliceValue<'ctx>) -> Result<BasicValueEnum<'ctx>, String>,
{ {
ndarray_fill_flattened( ndarray_fill_flattened(
generator, generator,
@ -348,7 +347,7 @@ fn ndarray_fill_indexed<'ctx, G, ValueFn>(
/// Generates the LLVM IR for populating the entire `NDArray` using a lambda with the same-indexed /// Generates the LLVM IR for populating the entire `NDArray` using a lambda with the same-indexed
/// element from two other `NDArray` as its input. /// element from two other `NDArray` as its input.
fn ndarray_broadcast_fill<'ctx, G, ValueFn>( fn ndarray_broadcast_fill_flattened<'ctx, G, ValueFn>(
generator: &mut G, generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>, ctx: &mut CodeGenContext<'ctx, '_>,
elem_ty: Type, elem_ty: Type,
@ -361,18 +360,15 @@ fn ndarray_broadcast_fill<'ctx, G, ValueFn>(
G: CodeGenerator + ?Sized, G: CodeGenerator + ?Sized,
ValueFn: Fn(&mut G, &mut CodeGenContext<'ctx, '_>, Type, (BasicValueEnum<'ctx>, BasicValueEnum<'ctx>)) -> Result<BasicValueEnum<'ctx>, String>, ValueFn: Fn(&mut G, &mut CodeGenContext<'ctx, '_>, Type, (BasicValueEnum<'ctx>, BasicValueEnum<'ctx>)) -> Result<BasicValueEnum<'ctx>, String>,
{ {
ndarray_fill_indexed( ndarray_fill_flattened(
generator, generator,
ctx, ctx,
res, res,
|generator, ctx, idx| { |generator, ctx, idx| {
let lhs_idx = call_ndarray_calc_broadcast_index(generator, ctx, lhs, &idx);
let rhs_idx = call_ndarray_calc_broadcast_index(generator, ctx, rhs, &idx);
let elem = unsafe { let elem = unsafe {
( (
lhs.data().get_unchecked(ctx, generator, lhs_idx, None), lhs.data().get_unchecked(ctx, generator, idx, None),
rhs.data().get_unchecked(ctx, generator, rhs_idx, None), rhs.data().get_unchecked(ctx, generator, idx, None),
) )
}; };
@ -512,7 +508,6 @@ fn call_ndarray_eye_impl<'ctx, G: CodeGenerator + ?Sized>(
ncols: IntValue<'ctx>, ncols: IntValue<'ctx>,
offset: IntValue<'ctx>, offset: IntValue<'ctx>,
) -> Result<NDArrayValue<'ctx>, String> { ) -> Result<NDArrayValue<'ctx>, String> {
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_usize_2 = llvm_usize.array_type(2); let llvm_usize_2 = llvm_usize.array_type(2);
@ -543,15 +538,15 @@ fn call_ndarray_eye_impl<'ctx, G: CodeGenerator + ?Sized>(
|generator, ctx, indices| { |generator, ctx, indices| {
let (row, col) = unsafe { let (row, col) = unsafe {
( (
indices.get_typed_unchecked(ctx, generator, llvm_usize.const_zero(), None), indices.get_unchecked(ctx, generator, llvm_usize.const_int(0, false), None).into_int_value(),
indices.get_typed_unchecked(ctx, generator, llvm_usize.const_int(1, false), None), indices.get_unchecked(ctx, generator, llvm_usize.const_int(1, false), None).into_int_value(),
) )
}; };
let col_with_offset = ctx.builder let col_with_offset = ctx.builder
.build_int_add( .build_int_add(
col, col,
ctx.builder.build_int_s_extend_or_bit_cast(offset, llvm_i32, "").unwrap(), ctx.builder.build_int_s_extend_or_bit_cast(offset, llvm_usize, "").unwrap(),
"", "",
) )
.unwrap(); .unwrap();
@ -634,7 +629,7 @@ pub fn ndarray_elementwise_binop_impl<'ctx, G, ValueFn>(
this: NDArrayValue<'ctx>, this: NDArrayValue<'ctx>,
other: NDArrayValue<'ctx>, other: NDArrayValue<'ctx>,
value_fn: ValueFn, value_fn: ValueFn,
) -> Result<NDArrayValue<'ctx>, String> ) -> Result<NDArrayValue<'ctx>, String>
where where
G: CodeGenerator, G: CodeGenerator,
ValueFn: Fn(&mut G, &mut CodeGenContext<'ctx, '_>, Type, (BasicValueEnum<'ctx>, BasicValueEnum<'ctx>)) -> Result<BasicValueEnum<'ctx>, String>, ValueFn: Fn(&mut G, &mut CodeGenContext<'ctx, '_>, Type, (BasicValueEnum<'ctx>, BasicValueEnum<'ctx>)) -> Result<BasicValueEnum<'ctx>, String>,
@ -646,18 +641,23 @@ pub fn ndarray_elementwise_binop_impl<'ctx, G, ValueFn>(
ctx, ctx,
elem_ty, elem_ty,
&ndarray_dims, &ndarray_dims,
|generator, ctx, v| { |_, _, v| {
Ok(v.size(ctx, generator)) Ok(v.0)
}, },
|generator, ctx, v, idx| { |_, ctx, v, idx| {
unsafe { unsafe {
Ok(v.get_typed_unchecked(ctx, generator, idx, None)) let data_ptr = ctx.builder.build_in_bounds_gep(v.1, &[idx], "")
.map_err(|e| e.to_string())?;
ctx.builder.build_load(data_ptr, "")
.map(BasicValueEnum::into_int_value)
.map_err(|e| e.to_string())
} }
}, },
).unwrap() ).unwrap()
}); });
ndarray_broadcast_fill( ndarray_broadcast_fill_flattened(
generator, generator,
ctx, ctx,
elem_ty, elem_ty,

View File

@ -696,7 +696,7 @@ impl Unifier {
self.set_a_to_b(a, x); self.set_a_to_b(a, x);
} }
(TVar { fields: Some(fields), range, is_const_generic: false, .. }, TTuple { ty }) => { (TVar { fields: Some(fields), range, is_const_generic: false, .. }, TTuple { ty }) => {
let len = i32::try_from(ty.len()).unwrap(); let len = ty.len() as i32;
for (k, v) in fields { for (k, v) in fields {
match *k { match *k {
RecordKey::Int(i) => { RecordKey::Int(i) => {

View File

@ -74,8 +74,7 @@ impl SymbolResolver for Resolver {
if let Some(id) = str_store.get(s) { if let Some(id) = str_store.get(s) {
*id *id
} else { } else {
let id = i32::try_from(str_store.len()) let id = str_store.len() as i32;
.expect("Symbol resolver string store size exceeds max capacity (i32::MAX)");
str_store.insert(s.to_string(), id); str_store.insert(s.to_string(), id);
id id
} }

View File

@ -247,8 +247,6 @@ fn handle_assignment_pattern(
} }
fn main() { fn main() {
const SIZE_T: u32 = usize::BITS;
let cli = CommandLineArgs::parse(); let cli = CommandLineArgs::parse();
let CommandLineArgs { let CommandLineArgs {
file_name, file_name,
@ -289,6 +287,7 @@ fn main() {
// The default behavior for -O<n> where n>3 defaults to O3 for both Clang and GCC // The default behavior for -O<n> where n>3 defaults to O3 for both Clang and GCC
_ => OptimizationLevel::Aggressive, _ => OptimizationLevel::Aggressive,
}; };
const SIZE_T: u32 = 64;
let program = match fs::read_to_string(file_name.clone()) { let program = match fs::read_to_string(file_name.clone()) {
Ok(program) => program, Ok(program) => program,