[core] Move alloca and map_value of ProxyType to implementations

These functions may not be invokable by the same set of parameters as
some classes has associated states.
This commit is contained in:
David Mak 2024-11-27 17:54:00 +08:00
parent a3c1d469fc
commit 363e1a1f84
6 changed files with 149 additions and 86 deletions

View File

@ -18,7 +18,7 @@ use nac3core::{
irrt::call_ndarray_calc_size, irrt::call_ndarray_calc_size,
llvm_intrinsics::{call_int_smax, call_memcpy_generic, call_stackrestore, call_stacksave}, llvm_intrinsics::{call_int_smax, call_memcpy_generic, call_stackrestore, call_stacksave},
stmt::{gen_block, gen_for_callback_incrementing, gen_if_callback, gen_with}, stmt::{gen_block, gen_for_callback_incrementing, gen_if_callback, gen_with},
types::{NDArrayType, ProxyType}, types::NDArrayType,
values::{ values::{
ArrayLikeIndexer, ArrayLikeValue, ArraySliceValue, ListValue, NDArrayValue, ProxyValue, ArrayLikeIndexer, ArrayLikeValue, ArraySliceValue, ListValue, NDArrayValue, ProxyValue,
RangeValue, UntypedArrayLikeAccessor, RangeValue, UntypedArrayLikeAccessor,
@ -460,12 +460,20 @@ fn format_rpc_arg<'ctx>(
let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, arg_ty); let (elem_ty, _) = unpack_ndarray_var_tys(&mut ctx.unifier, arg_ty);
let llvm_elem_ty = ctx.get_llvm_type(generator, elem_ty); let llvm_elem_ty = ctx.get_llvm_type(generator, elem_ty);
let llvm_arg_ty = NDArrayType::new(generator, ctx.ctx, llvm_elem_ty); let llvm_arg = NDArrayValue::from_pointer_value(
let llvm_arg = llvm_arg_ty.map_value(arg.into_pointer_value(), None); arg.into_pointer_value(),
llvm_elem_ty,
llvm_usize,
None,
);
let llvm_usize_sizeof = ctx let llvm_usize_sizeof = ctx
.builder .builder
.build_int_truncate_or_bit_cast(llvm_arg_ty.size_type().size_of(), llvm_usize, "") .build_int_truncate_or_bit_cast(
llvm_arg.get_type().size_type().size_of(),
llvm_usize,
"",
)
.unwrap(); .unwrap();
let llvm_pdata_sizeof = ctx let llvm_pdata_sizeof = ctx
.builder .builder
@ -598,7 +606,7 @@ fn format_rpc_ret<'ctx>(
// Allocate the resulting ndarray // Allocate the resulting ndarray
// A condition after format_rpc_ret ensures this will not be popped this off. // A condition after format_rpc_ret ensures this will not be popped this off.
let ndarray = llvm_ret_ty.new_value(generator, ctx, Some("rpc.result")); let ndarray = llvm_ret_ty.alloca(generator, ctx, Some("rpc.result"));
// Setup ndims // Setup ndims
let ndims = let ndims =

View File

@ -32,7 +32,7 @@ use super::{
gen_for_callback_incrementing, gen_if_callback, gen_if_else_expr_callback, gen_raise, gen_for_callback_incrementing, gen_if_callback, gen_if_else_expr_callback, gen_raise,
gen_var, gen_var,
}, },
types::{ListType, ProxyType}, types::ListType,
values::{ values::{
ArrayLikeIndexer, ArrayLikeValue, ListValue, NDArrayValue, ProxyValue, RangeValue, ArrayLikeIndexer, ArrayLikeValue, ListValue, NDArrayValue, ProxyValue, RangeValue,
TypedArrayLikeAccessor, UntypedArrayLikeAccessor, TypedArrayLikeAccessor, UntypedArrayLikeAccessor,
@ -1112,7 +1112,7 @@ pub fn allocate_list<'ctx, G: CodeGenerator + ?Sized>(
// List structure; type { ty*, size_t } // List structure; type { ty*, size_t }
let arr_ty = ListType::new(generator, ctx.ctx, llvm_elem_ty); let arr_ty = ListType::new(generator, ctx.ctx, llvm_elem_ty);
let list = arr_ty.new_value(generator, ctx, name); let list = arr_ty.alloca(generator, ctx, name);
let length = ctx.builder.build_int_z_extend(length, llvm_usize, "").unwrap(); let length = ctx.builder.build_int_z_extend(length, llvm_usize, "").unwrap();
list.store_size(ctx, generator, length); list.store_size(ctx, generator, length);

View File

@ -111,6 +111,31 @@ impl<'ctx> ListType<'ctx> {
.map(PointerType::get_element_type) .map(PointerType::get_element_type)
.unwrap() .unwrap()
} }
/// Allocates an instance of [`ListValue`] as if by calling `alloca` on the base type.
#[must_use]
pub fn alloca<G: CodeGenerator + ?Sized>(
&self,
generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>,
name: Option<&'ctx str>,
) -> <Self as ProxyType<'ctx>>::Value {
<Self as ProxyType<'ctx>>::Value::from_pointer_value(
self.raw_alloca(generator, ctx, name),
self.llvm_usize,
name,
)
}
/// Converts an existing value into a [`ListValue`].
#[must_use]
pub fn map_value(
&self,
value: <<Self as ProxyType<'ctx>>::Value as ProxyValue<'ctx>>::Base,
name: Option<&'ctx str>,
) -> <Self as ProxyType<'ctx>>::Value {
<Self as ProxyType<'ctx>>::Value::from_pointer_value(value, self.llvm_usize, name)
}
} }
impl<'ctx> ProxyType<'ctx> for ListType<'ctx> { impl<'ctx> ProxyType<'ctx> for ListType<'ctx> {
@ -137,25 +162,22 @@ impl<'ctx> ProxyType<'ctx> for ListType<'ctx> {
Self::is_representable(llvm_ty, generator.get_size_type(ctx)) Self::is_representable(llvm_ty, generator.get_size_type(ctx))
} }
fn new_value<G: CodeGenerator + ?Sized>( fn raw_alloca<G: CodeGenerator + ?Sized>(
&self, &self,
generator: &mut G, generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>, ctx: &mut CodeGenContext<'ctx, '_>,
name: Option<&'ctx str>, name: Option<&'ctx str>,
) -> Self::Value { ) -> <Self::Value as ProxyValue<'ctx>>::Base {
self.map_value(
generator generator
.gen_var_alloc( .gen_var_alloc(
ctx, ctx,
self.as_base_type().get_element_type().into_struct_type().into(), self.as_base_type().get_element_type().into_struct_type().into(),
name, name,
) )
.unwrap(), .unwrap()
name,
)
} }
fn new_array_value<G: CodeGenerator + ?Sized>( fn array_alloca<G: CodeGenerator + ?Sized>(
&self, &self,
generator: &mut G, generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>, ctx: &mut CodeGenContext<'ctx, '_>,
@ -172,14 +194,6 @@ impl<'ctx> ProxyType<'ctx> for ListType<'ctx> {
.unwrap() .unwrap()
} }
fn map_value(
&self,
value: <Self::Value as ProxyValue<'ctx>>::Base,
name: Option<&'ctx str>,
) -> Self::Value {
Self::Value::from_pointer_value(value, self.llvm_usize, name)
}
fn as_base_type(&self) -> Self::Base { fn as_base_type(&self) -> Self::Base {
self.ty self.ty
} }

View File

@ -1,3 +1,21 @@
//! This module contains abstraction over all intrinsic composite types of NAC3.
//!
//! # `raw_alloca` vs `alloca` vs `construct`
//!
//! There are three ways of creating a new object instance using the abstractions provided by this
//! module.
//!
//! - `raw_alloca`: Allocates the object on the stack, returning an instance of
//! [`impl BasicValue`][inkwell::values::BasicValue]. This is similar to a `malloc` expression in
//! C++ but the object is allocated on the stack.
//! - `alloca`: Similar to `raw_alloca`, but also wraps the allocated object with
//! [`<Self as ProxyType<'ctx>>::Value`][ProxyValue], and returns the wrapped object. The returned
//! object will not initialize any value or fields. This is similar to a type-safe `malloc`
//! expression in C++ but the object is allocated on the stack.
//! - `construct`: Similar to `alloca`, but performs some initialization on the value or fields of
//! the returned object. This is similar to a `new` expression in C++ but the object is allocated
//! on the stack.
use inkwell::{context::Context, types::BasicType, values::IntValue}; use inkwell::{context::Context, types::BasicType, values::IntValue};
use super::{ use super::{
@ -35,16 +53,17 @@ pub trait ProxyType<'ctx>: Into<Self::Base> {
llvm_ty: Self::Base, llvm_ty: Self::Base,
) -> Result<(), String>; ) -> Result<(), String>;
/// Creates a new value of this type. /// Creates a new value of this type, returning the LLVM instance of this value.
fn new_value<G: CodeGenerator + ?Sized>( fn raw_alloca<G: CodeGenerator + ?Sized>(
&self, &self,
generator: &mut G, generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>, ctx: &mut CodeGenContext<'ctx, '_>,
name: Option<&'ctx str>, name: Option<&'ctx str>,
) -> Self::Value; ) -> <Self::Value as ProxyValue<'ctx>>::Base;
/// Creates a new array value of this type. /// Creates a new array value of this type, returning an [`ArraySliceValue`] encapsulating the
fn new_array_value<G: CodeGenerator + ?Sized>( /// resulting array.
fn array_alloca<G: CodeGenerator + ?Sized>(
&self, &self,
generator: &mut G, generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>, ctx: &mut CodeGenContext<'ctx, '_>,
@ -52,13 +71,6 @@ pub trait ProxyType<'ctx>: Into<Self::Base> {
name: Option<&'ctx str>, name: Option<&'ctx str>,
) -> ArraySliceValue<'ctx>; ) -> ArraySliceValue<'ctx>;
/// Converts an existing value into a [`ProxyValue`] of this type.
fn map_value(
&self,
value: <Self::Value as ProxyValue<'ctx>>::Base,
name: Option<&'ctx str>,
) -> Self::Value;
/// Returns the [base type][Self::Base] of this proxy. /// Returns the [base type][Self::Base] of this proxy.
fn as_base_type(&self) -> Self::Base; fn as_base_type(&self) -> Self::Base;
} }

View File

@ -175,6 +175,37 @@ impl<'ctx> NDArrayType<'ctx> {
pub fn element_type(&self) -> BasicTypeEnum<'ctx> { pub fn element_type(&self) -> BasicTypeEnum<'ctx> {
self.dtype self.dtype
} }
/// Allocates an instance of [`NDArrayValue`] as if by calling `alloca` on the base type.
#[must_use]
pub fn alloca<G: CodeGenerator + ?Sized>(
&self,
generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>,
name: Option<&'ctx str>,
) -> <Self as ProxyType<'ctx>>::Value {
<Self as ProxyType<'ctx>>::Value::from_pointer_value(
self.raw_alloca(generator, ctx, name),
self.dtype,
self.llvm_usize,
name,
)
}
/// Converts an existing value into a [`NDArrayValue`].
#[must_use]
pub fn map_value(
&self,
value: <<Self as ProxyType<'ctx>>::Value as ProxyValue<'ctx>>::Base,
name: Option<&'ctx str>,
) -> <Self as ProxyType<'ctx>>::Value {
<Self as ProxyType<'ctx>>::Value::from_pointer_value(
value,
self.dtype,
self.llvm_usize,
name,
)
}
} }
impl<'ctx> ProxyType<'ctx> for NDArrayType<'ctx> { impl<'ctx> ProxyType<'ctx> for NDArrayType<'ctx> {
@ -201,25 +232,22 @@ impl<'ctx> ProxyType<'ctx> for NDArrayType<'ctx> {
Self::is_representable(llvm_ty, generator.get_size_type(ctx)) Self::is_representable(llvm_ty, generator.get_size_type(ctx))
} }
fn new_value<G: CodeGenerator + ?Sized>( fn raw_alloca<G: CodeGenerator + ?Sized>(
&self, &self,
generator: &mut G, generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>, ctx: &mut CodeGenContext<'ctx, '_>,
name: Option<&'ctx str>, name: Option<&'ctx str>,
) -> Self::Value { ) -> <Self::Value as ProxyValue<'ctx>>::Base {
self.map_value(
generator generator
.gen_var_alloc( .gen_var_alloc(
ctx, ctx,
self.as_base_type().get_element_type().into_struct_type().into(), self.as_base_type().get_element_type().into_struct_type().into(),
name, name,
) )
.unwrap(), .unwrap()
name,
)
} }
fn new_array_value<G: CodeGenerator + ?Sized>( fn array_alloca<G: CodeGenerator + ?Sized>(
&self, &self,
generator: &mut G, generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>, ctx: &mut CodeGenContext<'ctx, '_>,
@ -236,16 +264,6 @@ impl<'ctx> ProxyType<'ctx> for NDArrayType<'ctx> {
.unwrap() .unwrap()
} }
fn map_value(
&self,
value: <Self::Value as ProxyValue<'ctx>>::Base,
name: Option<&'ctx str>,
) -> Self::Value {
debug_assert_eq!(value.get_type(), self.as_base_type());
NDArrayValue::from_pointer_value(value, self.dtype, self.llvm_usize, name)
}
fn as_base_type(&self) -> Self::Base { fn as_base_type(&self) -> Self::Base {
self.ty self.ty
} }

View File

@ -76,6 +76,30 @@ impl<'ctx> RangeType<'ctx> {
pub fn value_type(&self) -> IntType<'ctx> { pub fn value_type(&self) -> IntType<'ctx> {
self.as_base_type().get_element_type().into_array_type().get_element_type().into_int_type() self.as_base_type().get_element_type().into_array_type().get_element_type().into_int_type()
} }
/// Allocates an instance of [`RangeValue`] as if by calling `alloca` on the base type.
#[must_use]
pub fn alloca<G: CodeGenerator + ?Sized>(
&self,
generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>,
name: Option<&'ctx str>,
) -> <Self as ProxyType<'ctx>>::Value {
<Self as ProxyType<'ctx>>::Value::from_pointer_value(
self.raw_alloca(generator, ctx, name),
name,
)
}
/// Converts an existing value into a [`RangeValue`].
#[must_use]
pub fn map_value(
&self,
value: <<Self as ProxyType<'ctx>>::Value as ProxyValue<'ctx>>::Base,
name: Option<&'ctx str>,
) -> <Self as ProxyType<'ctx>>::Value {
<Self as ProxyType<'ctx>>::Value::from_pointer_value(value, name)
}
} }
impl<'ctx> ProxyType<'ctx> for RangeType<'ctx> { impl<'ctx> ProxyType<'ctx> for RangeType<'ctx> {
@ -102,25 +126,22 @@ impl<'ctx> ProxyType<'ctx> for RangeType<'ctx> {
Self::is_representable(llvm_ty) Self::is_representable(llvm_ty)
} }
fn new_value<G: CodeGenerator + ?Sized>( fn raw_alloca<G: CodeGenerator + ?Sized>(
&self, &self,
generator: &mut G, generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>, ctx: &mut CodeGenContext<'ctx, '_>,
name: Option<&'ctx str>, name: Option<&'ctx str>,
) -> Self::Value { ) -> <Self::Value as ProxyValue<'ctx>>::Base {
self.map_value(
generator generator
.gen_var_alloc( .gen_var_alloc(
ctx, ctx,
self.as_base_type().get_element_type().into_struct_type().into(), self.as_base_type().get_element_type().into_struct_type().into(),
name, name,
) )
.unwrap(), .unwrap()
name,
)
} }
fn new_array_value<G: CodeGenerator + ?Sized>( fn array_alloca<G: CodeGenerator + ?Sized>(
&self, &self,
generator: &mut G, generator: &mut G,
ctx: &mut CodeGenContext<'ctx, '_>, ctx: &mut CodeGenContext<'ctx, '_>,
@ -137,16 +158,6 @@ impl<'ctx> ProxyType<'ctx> for RangeType<'ctx> {
.unwrap() .unwrap()
} }
fn map_value(
&self,
value: <Self::Value as ProxyValue<'ctx>>::Base,
name: Option<&'ctx str>,
) -> Self::Value {
debug_assert_eq!(value.get_type(), self.as_base_type());
RangeValue::from_pointer_value(value, name)
}
fn as_base_type(&self) -> Self::Base { fn as_base_type(&self) -> Self::Base {
self.ty self.ty
} }