Compare commits

..

16 Commits

Author SHA1 Message Date
David Mak d2ce0679ed WIP 2024-03-22 17:16:03 +08:00
David Mak aa673fce4e core: Implement elementwise binary operators
Including immediate variants of these operators.
2024-03-22 17:16:03 +08:00
David Mak ddfd19d00c core: Add handling of ndarrays in gen_binop_expr 2024-03-22 17:16:03 +08:00
David Mak 4887cd8007 core: Implement calculations for broadcasting ndarrays 2024-03-22 17:15:49 +08:00
David Mak 876e850d71 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-22 17:11:16 +08:00
David Mak 1de2e9a4be core: Remove ArrayValue variants of accessors 2024-03-22 17:11:16 +08:00
David Mak 2b0beea8c0 core: Use more typed slices in APIs 2024-03-22 17:11:16 +08:00
David Mak 5778de02fc core: Fix index-based operations not returning i32 2024-03-22 17:11:15 +08:00
David Mak 13f06f3e29 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-22 15:51:23 +08:00
David Mak f0da9c0283 core: Add ArrayLikeValue
For exposing LLVM values that can be accessed like an array.
2024-03-22 15:51:06 +08:00
David Mak 2c4bf3ce59 core: Allow unsized CodeGenerator to be passed to some codegen functions
Enables codegen_callback to call these codegen functions as well.
2024-03-22 15:07:28 +08:00
David Mak e980f19c93 core: Simplify typed value assertions 2024-03-22 15:07:28 +08:00
David Mak cfbc37c1ed core: Add gen_for_callback_incrementing
Simplifies generation of monotonically increasing for loops.
2024-03-22 15:07:28 +08:00
David Mak 50264e8750 core: Add missing unchecked accessors for NDArrayDimsProxy 2024-03-22 15:07:28 +08:00
David Mak 1b77e62901 core: Split numpy into codegen and toplevel 2024-03-22 15:07:28 +08:00
David Mak fd44ee6887 core: Apply clippy suggestions 2024-03-22 15:07:23 +08:00
8 changed files with 109 additions and 218 deletions

View File

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

View File

@ -43,6 +43,7 @@ use itertools::{chain, izip, Itertools, Either};
use nac3parser::ast::{
self, Boolop, Comprehension, Constant, Expr, ExprKind, Location, Operator, StrRef,
};
use crate::codegen::classes::ArraySliceValue;
use super::{CodeGenerator, llvm_intrinsics::call_memcpy_generic, need_sret};
@ -1330,12 +1331,14 @@ fn gen_ndarray_subscript_expr<'ctx, G: CodeGenerator>(
} else {
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()
.get(
ctx,
generator,
ctx.ctx.i32_type().const_array(&[index]),
ArraySliceValue::from_ptr_val(index_addr, llvm_usize.const_int(1, false), None),
None,
)
.into()))
@ -1351,6 +1354,8 @@ fn gen_ndarray_subscript_expr<'ctx, G: CodeGenerator>(
} else {
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
// elements over
@ -1405,7 +1410,7 @@ fn gen_ndarray_subscript_expr<'ctx, G: CodeGenerator>(
let v_data_src_ptr = v.data().ptr_offset(
ctx,
generator,
ctx.ctx.i32_type().const_array(&[index]),
ArraySliceValue::from_ptr_val(index_addr, llvm_usize.const_int(1, false), None),
None
);
call_memcpy_generic(

View File

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

View File

@ -3,12 +3,12 @@ use crate::typecheck::typedef::Type;
use super::{
classes::{
ArrayLikeIndexer,
ArraySliceValue,
ArrayLikeValue,
ArraySliceValue,
ListValue,
NDArrayValue,
TypedArrayLikeAdapter,
UntypedArrayLikeAccessor,
UntypedArrayLikeMutator,
},
CodeGenContext,
CodeGenerator,
@ -20,7 +20,7 @@ use inkwell::{
memory_buffer::MemoryBuffer,
module::Module,
types::{BasicTypeEnum, IntType},
values::{ArrayValue, BasicValueEnum, CallSiteValue, FloatValue, IntValue, PointerValue},
values::{BasicValueEnum, CallSiteValue, FloatValue, IntValue},
AddressSpace, IntPredicate,
};
use itertools::Either;
@ -628,7 +628,8 @@ pub fn call_ndarray_calc_size<'ctx, G, Dims>(
.unwrap()
}
/// Generates a call to `__nac3_ndarray_calc_nd_indices`.
/// Generates a call to `__nac3_ndarray_calc_nd_indices`. Returns a [`TypeArrayLikeAdpater`]
/// containing `i32` indices of the flattened index.
///
/// * `index` - The index to compute the multidimensional index for.
/// * `ndarray` - LLVM pointer to the `NDArray`. This value must be the LLVM representation of an
@ -638,10 +639,11 @@ pub fn call_ndarray_calc_nd_indices<'ctx, G: CodeGenerator + ?Sized>(
ctx: &mut CodeGenContext<'ctx, '_>,
index: IntValue<'ctx>,
ndarray: NDArrayValue<'ctx>,
) -> ArraySliceValue<'ctx> {
) -> TypedArrayLikeAdapter<'ctx, IntValue<'ctx>> {
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_pi32 = llvm_i32.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() {
@ -655,7 +657,7 @@ pub fn call_ndarray_calc_nd_indices<'ctx, G: CodeGenerator + ?Sized>(
llvm_usize.into(),
llvm_pusize.into(),
llvm_usize.into(),
llvm_pusize.into(),
llvm_pi32.into(),
],
false,
);
@ -667,7 +669,7 @@ pub fn call_ndarray_calc_nd_indices<'ctx, G: CodeGenerator + ?Sized>(
let ndarray_dims = ndarray.dim_sizes();
let indices = ctx.builder.build_array_alloca(
llvm_usize,
llvm_i32,
ndarray_num_dims,
"",
).unwrap();
@ -685,7 +687,11 @@ pub fn call_ndarray_calc_nd_indices<'ctx, G: CodeGenerator + ?Sized>(
)
.unwrap();
ArraySliceValue::from_ptr_val(indices, ndarray_num_dims, None)
TypedArrayLikeAdapter::from(
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>(
@ -780,49 +786,6 @@ pub fn call_ndarray_flatten_index<'ctx, G, Index>(
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
/// dimension and size of each dimension of the resultant `ndarray`.
@ -831,7 +794,7 @@ pub fn call_ndarray_calc_broadcast<'ctx, G: CodeGenerator + ?Sized>(
ctx: &mut CodeGenContext<'ctx, '_>,
lhs: NDArrayValue<'ctx>,
rhs: NDArrayValue<'ctx>,
) -> (IntValue<'ctx>, PointerValue<'ctx>) {
) -> TypedArrayLikeAdapter<'ctx, IntValue<'ctx>> {
let llvm_usize = generator.get_size_type(ctx.ctx);
let llvm_pusize = llvm_usize.ptr_type(AddressSpace::default());
@ -881,6 +844,7 @@ pub fn call_ndarray_calc_broadcast<'ctx, G: CodeGenerator + ?Sized>(
let rhs_dims = rhs.dim_sizes().base_ptr(ctx, generator);
let rhs_ndims = rhs.load_ndims(ctx);
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
.build_call(
@ -890,24 +854,31 @@ pub fn call_ndarray_calc_broadcast<'ctx, G: CodeGenerator + ?Sized>(
lhs_ndims.into(),
rhs_dims.into(),
rhs_ndims.into(),
out_dims.into(),
out_dims.base_ptr(ctx, generator).into(),
],
"",
)
.unwrap();
(max_ndims, out_dims)
TypedArrayLikeAdapter::from(
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`]
/// containing the indices used for accessing `array` corresponding to the `broadcast_idx`.
/// containing the indices used for accessing `array` corresponding to the index of the broadcasted
/// array `broadcast_idx`.
pub fn call_ndarray_calc_broadcast_index<'ctx, G: CodeGenerator + ?Sized, BroadcastIdx: UntypedArrayLikeAccessor<'ctx>>(
generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>,
array: NDArrayValue<'ctx>,
broadcast_idx: &BroadcastIdx,
) -> ArraySliceValue<'ctx> {
) -> TypedArrayLikeAdapter<'ctx, IntValue<'ctx>> {
let llvm_i32 = ctx.ctx.i32_type();
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 ndarray_calc_broadcast_fn_name = match llvm_usize.get_bit_width() {
@ -920,8 +891,8 @@ pub fn call_ndarray_calc_broadcast_index<'ctx, G: CodeGenerator + ?Sized, Broadc
&[
llvm_pusize.into(),
llvm_usize.into(),
llvm_pusize.into(),
llvm_usize.into(),
llvm_pi32.into(),
llvm_pi32.into(),
],
false,
);
@ -932,8 +903,7 @@ pub fn call_ndarray_calc_broadcast_index<'ctx, G: CodeGenerator + ?Sized, Broadc
// TODO: Assertions
let broadcast_size = broadcast_idx.size(ctx, generator);
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 out_idx = ctx.builder.build_array_alloca(llvm_i32, broadcast_size, "").unwrap();
let array_dims = array.dim_sizes().base_ptr(ctx, generator);
let array_ndims = array.load_ndims(ctx);
@ -953,11 +923,15 @@ pub fn call_ndarray_calc_broadcast_index<'ctx, G: CodeGenerator + ?Sized, Broadc
array_dims.into(),
array_ndims.into(),
broadcast_idx_ptr.into(),
out_idx.base_ptr(ctx, generator).into(),
out_idx.into(),
],
"",
)
.unwrap();
out_idx
TypedArrayLikeAdapter::from(
ArraySliceValue::from_ptr_val(out_idx, broadcast_size, None),
Box::new(|_, v| v.into_int_value()),
Box::new(|_, v| v.into()),
)
}

View File

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

View File

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

View File

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

View File

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