[core] codegen: Refactor Proxy{Type,Value} for StructProxy{Type,Value}
This commit is contained in:
parent
c36aac323d
commit
da8480148a
@ -19,9 +19,9 @@ use nac3core::{
|
|||||||
llvm_intrinsics::{call_int_smax, call_memcpy, call_stackrestore, call_stacksave},
|
llvm_intrinsics::{call_int_smax, call_memcpy, 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},
|
||||||
type_aligned_alloca,
|
type_aligned_alloca,
|
||||||
types::ndarray::NDArrayType,
|
types::{ndarray::NDArrayType, RangeType},
|
||||||
values::{
|
values::{
|
||||||
ArrayLikeIndexer, ArrayLikeValue, ArraySliceValue, ListValue, ProxyValue, RangeValue,
|
ArrayLikeIndexer, ArrayLikeValue, ArraySliceValue, ListValue, ProxyValue,
|
||||||
UntypedArrayLikeAccessor,
|
UntypedArrayLikeAccessor,
|
||||||
},
|
},
|
||||||
CodeGenContext, CodeGenerator,
|
CodeGenContext, CodeGenerator,
|
||||||
@ -1431,7 +1431,7 @@ fn polymorphic_print<'ctx>(
|
|||||||
fmt.push_str("range(");
|
fmt.push_str("range(");
|
||||||
flush(ctx, generator, &mut fmt, &mut args);
|
flush(ctx, generator, &mut fmt, &mut args);
|
||||||
|
|
||||||
let val = RangeValue::from_pointer_value(value.into_pointer_value(), None);
|
let val = RangeType::new(ctx).map_value(value.into_pointer_value(), None);
|
||||||
|
|
||||||
let (start, stop, step) = destructure_range(ctx, val);
|
let (start, stop, step) = destructure_range(ctx, val);
|
||||||
|
|
||||||
|
@ -11,10 +11,10 @@ use super::{
|
|||||||
irrt::calculate_len_for_slice_range,
|
irrt::calculate_len_for_slice_range,
|
||||||
llvm_intrinsics,
|
llvm_intrinsics,
|
||||||
macros::codegen_unreachable,
|
macros::codegen_unreachable,
|
||||||
types::{ndarray::NDArrayType, ListType, TupleType},
|
types::{ndarray::NDArrayType, ListType, RangeType, TupleType},
|
||||||
values::{
|
values::{
|
||||||
ndarray::{NDArrayOut, NDArrayValue, ScalarOrNDArray},
|
ndarray::{NDArrayOut, NDArrayValue, ScalarOrNDArray},
|
||||||
ProxyValue, RangeValue, TypedArrayLikeAccessor, UntypedArrayLikeAccessor,
|
ProxyValue, TypedArrayLikeAccessor, UntypedArrayLikeAccessor,
|
||||||
},
|
},
|
||||||
CodeGenContext, CodeGenerator,
|
CodeGenContext, CodeGenerator,
|
||||||
};
|
};
|
||||||
@ -47,7 +47,7 @@ pub fn call_len<'ctx, G: CodeGenerator + ?Sized>(
|
|||||||
let range_ty = ctx.primitives.range;
|
let range_ty = ctx.primitives.range;
|
||||||
|
|
||||||
Ok(if ctx.unifier.unioned(arg_ty, range_ty) {
|
Ok(if ctx.unifier.unioned(arg_ty, range_ty) {
|
||||||
let arg = RangeValue::from_pointer_value(arg.into_pointer_value(), Some("range"));
|
let arg = RangeType::new(ctx).map_value(arg.into_pointer_value(), Some("range"));
|
||||||
let (start, end, step) = destructure_range(ctx, arg);
|
let (start, end, step) = destructure_range(ctx, arg);
|
||||||
calculate_len_for_slice_range(generator, ctx, start, end, step)
|
calculate_len_for_slice_range(generator, ctx, start, end, step)
|
||||||
} else {
|
} else {
|
||||||
|
@ -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::{ndarray::NDArrayType, ListType},
|
types::{ndarray::NDArrayType, ListType, RangeType},
|
||||||
values::{
|
values::{
|
||||||
ndarray::{NDArrayOut, RustNDIndex, ScalarOrNDArray},
|
ndarray::{NDArrayOut, RustNDIndex, ScalarOrNDArray},
|
||||||
ArrayLikeIndexer, ArrayLikeValue, ListValue, ProxyValue, RangeValue,
|
ArrayLikeIndexer, ArrayLikeValue, ListValue, ProxyValue, RangeValue,
|
||||||
@ -1151,7 +1151,7 @@ pub fn gen_comprehension<'ctx, G: CodeGenerator>(
|
|||||||
if *obj_id == ctx.primitives.range.obj_id(&ctx.unifier).unwrap() =>
|
if *obj_id == ctx.primitives.range.obj_id(&ctx.unifier).unwrap() =>
|
||||||
{
|
{
|
||||||
let iter_val =
|
let iter_val =
|
||||||
RangeValue::from_pointer_value(iter_val.into_pointer_value(), Some("range"));
|
RangeType::new(ctx).map_value(iter_val.into_pointer_value(), Some("range"));
|
||||||
let (start, stop, step) = destructure_range(ctx, iter_val);
|
let (start, stop, step) = destructure_range(ctx, iter_val);
|
||||||
let diff = ctx.builder.build_int_sub(stop, start, "diff").unwrap();
|
let diff = ctx.builder.build_int_sub(stop, start, "diff").unwrap();
|
||||||
// add 1 to the length as the value is rounded to zero
|
// add 1 to the length as the value is rounded to zero
|
||||||
|
@ -55,10 +55,9 @@ pub fn call_nac3_ndarray_broadcast_shapes<'ctx, G, Shape>(
|
|||||||
let llvm_usize = ctx.get_size_type();
|
let llvm_usize = ctx.get_size_type();
|
||||||
|
|
||||||
assert_eq!(num_shape_entries.get_type(), llvm_usize);
|
assert_eq!(num_shape_entries.get_type(), llvm_usize);
|
||||||
assert!(ShapeEntryType::is_type(
|
assert!(ShapeEntryType::is_representable(
|
||||||
generator,
|
shape_entries.base_ptr(ctx, generator).get_type(),
|
||||||
ctx.ctx,
|
llvm_usize,
|
||||||
shape_entries.base_ptr(ctx, generator).get_type()
|
|
||||||
)
|
)
|
||||||
.is_ok());
|
.is_ok());
|
||||||
assert_eq!(dst_ndims.get_type(), llvm_usize);
|
assert_eq!(dst_ndims.get_type(), llvm_usize);
|
||||||
|
@ -17,10 +17,10 @@ use super::{
|
|||||||
gen_in_range_check,
|
gen_in_range_check,
|
||||||
irrt::{handle_slice_indices, list_slice_assignment},
|
irrt::{handle_slice_indices, list_slice_assignment},
|
||||||
macros::codegen_unreachable,
|
macros::codegen_unreachable,
|
||||||
types::ndarray::NDArrayType,
|
types::{ndarray::NDArrayType, RangeType},
|
||||||
values::{
|
values::{
|
||||||
ndarray::{RustNDIndex, ScalarOrNDArray},
|
ndarray::{RustNDIndex, ScalarOrNDArray},
|
||||||
ArrayLikeIndexer, ArraySliceValue, ListValue, ProxyValue, RangeValue,
|
ArrayLikeIndexer, ArraySliceValue, ListValue, ProxyValue,
|
||||||
},
|
},
|
||||||
CodeGenContext, CodeGenerator,
|
CodeGenContext, CodeGenerator,
|
||||||
};
|
};
|
||||||
@ -511,7 +511,7 @@ pub fn gen_for<G: CodeGenerator>(
|
|||||||
if *obj_id == ctx.primitives.range.obj_id(&ctx.unifier).unwrap() =>
|
if *obj_id == ctx.primitives.range.obj_id(&ctx.unifier).unwrap() =>
|
||||||
{
|
{
|
||||||
let iter_val =
|
let iter_val =
|
||||||
RangeValue::from_pointer_value(iter_val.into_pointer_value(), Some("range"));
|
RangeType::new(ctx).map_value(iter_val.into_pointer_value(), Some("range"));
|
||||||
// Internal variable for loop; Cannot be assigned
|
// Internal variable for loop; Cannot be assigned
|
||||||
let i = generator.gen_var_alloc(ctx, int32.into(), Some("for.i.addr"))?;
|
let i = generator.gen_var_alloc(ctx, int32.into(), Some("for.i.addr"))?;
|
||||||
// Variable declared in "target" expression of the loop; Can be reassigned *or* shadowed
|
// Variable declared in "target" expression of the loop; Can be reassigned *or* shadowed
|
||||||
|
@ -455,8 +455,10 @@ fn test_classes_range_type_new() {
|
|||||||
let ctx = inkwell::context::Context::create();
|
let ctx = inkwell::context::Context::create();
|
||||||
let generator = DefaultCodeGenerator::new(String::new(), ctx.i64_type());
|
let generator = DefaultCodeGenerator::new(String::new(), ctx.i64_type());
|
||||||
|
|
||||||
|
let llvm_usize = generator.get_size_type(&ctx);
|
||||||
|
|
||||||
let llvm_range = RangeType::new_with_generator(&generator, &ctx);
|
let llvm_range = RangeType::new_with_generator(&generator, &ctx);
|
||||||
assert!(RangeType::is_representable(llvm_range.as_base_type()).is_ok());
|
assert!(RangeType::is_representable(llvm_range.as_base_type(), llvm_usize).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -56,34 +56,6 @@ impl<'ctx> ListStructFields<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ListType<'ctx> {
|
impl<'ctx> ListType<'ctx> {
|
||||||
/// Checks whether `llvm_ty` represents a `list` type, returning [Err] if it does not.
|
|
||||||
pub fn is_representable(
|
|
||||||
llvm_ty: PointerType<'ctx>,
|
|
||||||
llvm_usize: IntType<'ctx>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
let ctx = llvm_ty.get_context();
|
|
||||||
|
|
||||||
let llvm_ty = llvm_ty.get_element_type();
|
|
||||||
let AnyTypeEnum::StructType(llvm_ty) = llvm_ty else {
|
|
||||||
return Err(format!("Expected struct type for `list` type, got {llvm_ty}"));
|
|
||||||
};
|
|
||||||
|
|
||||||
let fields = ListStructFields::new(ctx, llvm_usize);
|
|
||||||
|
|
||||||
check_struct_type_matches_fields(
|
|
||||||
fields,
|
|
||||||
llvm_ty,
|
|
||||||
"list",
|
|
||||||
&[(fields.items.name(), &|ty| {
|
|
||||||
if ty.is_pointer_type() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(format!("Expected T* for `list.items`, got {ty}"))
|
|
||||||
}
|
|
||||||
})],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an instance of [`StructFields`] containing all field accessors for this type.
|
/// Returns an instance of [`StructFields`] containing all field accessors for this type.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn fields(item: BasicTypeEnum<'ctx>, llvm_usize: IntType<'ctx>) -> ListStructFields<'ctx> {
|
fn fields(item: BasicTypeEnum<'ctx>, llvm_usize: IntType<'ctx>) -> ListStructFields<'ctx> {
|
||||||
@ -184,7 +156,7 @@ impl<'ctx> ListType<'ctx> {
|
|||||||
/// Creates an [`ListType`] from a [`PointerType`].
|
/// Creates an [`ListType`] from a [`PointerType`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_type(ptr_ty: PointerType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
pub fn from_type(ptr_ty: PointerType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
||||||
debug_assert!(Self::is_representable(ptr_ty, llvm_usize).is_ok());
|
debug_assert!(Self::has_same_repr(ptr_ty, llvm_usize).is_ok());
|
||||||
|
|
||||||
let ctx = ptr_ty.get_context();
|
let ctx = ptr_ty.get_context();
|
||||||
|
|
||||||
@ -336,24 +308,39 @@ impl<'ctx> ProxyType<'ctx> for ListType<'ctx> {
|
|||||||
type Base = PointerType<'ctx>;
|
type Base = PointerType<'ctx>;
|
||||||
type Value = ListValue<'ctx>;
|
type Value = ListValue<'ctx>;
|
||||||
|
|
||||||
fn is_type<G: CodeGenerator + ?Sized>(
|
fn is_representable(
|
||||||
generator: &G,
|
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: impl BasicType<'ctx>,
|
llvm_ty: impl BasicType<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
||||||
<Self as ProxyType<'ctx>>::is_representable(generator, ctx, ty)
|
Self::has_same_repr(ty, llvm_usize)
|
||||||
} else {
|
} else {
|
||||||
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_representable<G: CodeGenerator + ?Sized>(
|
fn has_same_repr(ty: Self::Base, llvm_usize: IntType<'ctx>) -> Result<(), String> {
|
||||||
generator: &G,
|
let ctx = ty.get_context();
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: Self::Base,
|
let llvm_ty = ty.get_element_type();
|
||||||
) -> Result<(), String> {
|
let AnyTypeEnum::StructType(llvm_ty) = llvm_ty else {
|
||||||
Self::is_representable(llvm_ty, generator.get_size_type(ctx))
|
return Err(format!("Expected struct type for `list` type, got {llvm_ty}"));
|
||||||
|
};
|
||||||
|
|
||||||
|
let fields = ListStructFields::new(ctx, llvm_usize);
|
||||||
|
|
||||||
|
check_struct_type_matches_fields(
|
||||||
|
fields,
|
||||||
|
llvm_ty,
|
||||||
|
"list",
|
||||||
|
&[(fields.items.name(), &|ty| {
|
||||||
|
if ty.is_pointer_type() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(format!("Expected T* for `list.items`, got {ty}"))
|
||||||
|
}
|
||||||
|
})],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
||||||
|
@ -17,8 +17,7 @@
|
|||||||
//! on the stack.
|
//! on the stack.
|
||||||
|
|
||||||
use inkwell::{
|
use inkwell::{
|
||||||
context::Context,
|
types::{BasicType, IntType},
|
||||||
types::BasicType,
|
|
||||||
values::{IntValue, PointerValue},
|
values::{IntValue, PointerValue},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -46,18 +45,12 @@ pub trait ProxyType<'ctx>: Into<Self::Base> {
|
|||||||
/// The type of values represented by this type.
|
/// The type of values represented by this type.
|
||||||
type Value: ProxyValue<'ctx, Type = Self>;
|
type Value: ProxyValue<'ctx, Type = Self>;
|
||||||
|
|
||||||
fn is_type<G: CodeGenerator + ?Sized>(
|
fn is_representable(
|
||||||
generator: &G,
|
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: impl BasicType<'ctx>,
|
llvm_ty: impl BasicType<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Result<(), String>;
|
) -> Result<(), String>;
|
||||||
|
|
||||||
/// Checks whether `llvm_ty` can be represented by this [`ProxyType`].
|
fn has_same_repr(ty: Self::Base, llvm_usize: IntType<'ctx>) -> Result<(), String>;
|
||||||
fn is_representable<G: CodeGenerator + ?Sized>(
|
|
||||||
generator: &G,
|
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: Self::Base,
|
|
||||||
) -> Result<(), String>;
|
|
||||||
|
|
||||||
/// Returns the type that should be used in `alloca` IR statements.
|
/// Returns the type that should be used in `alloca` IR statements.
|
||||||
fn alloca_type(&self) -> impl BasicType<'ctx>;
|
fn alloca_type(&self) -> impl BasicType<'ctx>;
|
||||||
|
@ -32,28 +32,6 @@ pub struct ShapeEntryStructFields<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ShapeEntryType<'ctx> {
|
impl<'ctx> ShapeEntryType<'ctx> {
|
||||||
/// Checks whether `llvm_ty` represents a [`ShapeEntryType`], returning [Err] if it does not.
|
|
||||||
pub fn is_representable(
|
|
||||||
llvm_ty: PointerType<'ctx>,
|
|
||||||
llvm_usize: IntType<'ctx>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
let ctx = llvm_ty.get_context();
|
|
||||||
|
|
||||||
let llvm_ndarray_ty = llvm_ty.get_element_type();
|
|
||||||
let AnyTypeEnum::StructType(llvm_ndarray_ty) = llvm_ndarray_ty else {
|
|
||||||
return Err(format!(
|
|
||||||
"Expected struct type for `ShapeEntry` type, got {llvm_ndarray_ty}"
|
|
||||||
));
|
|
||||||
};
|
|
||||||
|
|
||||||
check_struct_type_matches_fields(
|
|
||||||
Self::fields(ctx, llvm_usize),
|
|
||||||
llvm_ndarray_ty,
|
|
||||||
"NDArray",
|
|
||||||
&[],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an instance of [`StructFields`] containing all field accessors for this type.
|
/// Returns an instance of [`StructFields`] containing all field accessors for this type.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn fields(
|
fn fields(
|
||||||
@ -103,7 +81,7 @@ impl<'ctx> ShapeEntryType<'ctx> {
|
|||||||
/// Creates a [`ShapeEntryType`] from a [`PointerType`] representing an `ShapeEntry`.
|
/// Creates a [`ShapeEntryType`] from a [`PointerType`] representing an `ShapeEntry`.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_type(ptr_ty: PointerType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
pub fn from_type(ptr_ty: PointerType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
||||||
debug_assert!(Self::is_representable(ptr_ty, llvm_usize).is_ok());
|
debug_assert!(Self::has_same_repr(ptr_ty, llvm_usize).is_ok());
|
||||||
|
|
||||||
Self { ty: ptr_ty, llvm_usize }
|
Self { ty: ptr_ty, llvm_usize }
|
||||||
}
|
}
|
||||||
@ -152,24 +130,33 @@ impl<'ctx> ProxyType<'ctx> for ShapeEntryType<'ctx> {
|
|||||||
type Base = PointerType<'ctx>;
|
type Base = PointerType<'ctx>;
|
||||||
type Value = ShapeEntryValue<'ctx>;
|
type Value = ShapeEntryValue<'ctx>;
|
||||||
|
|
||||||
fn is_type<G: CodeGenerator + ?Sized>(
|
fn is_representable(
|
||||||
generator: &G,
|
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: impl BasicType<'ctx>,
|
llvm_ty: impl BasicType<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
||||||
<Self as ProxyType<'ctx>>::is_representable(generator, ctx, ty)
|
Self::has_same_repr(ty, llvm_usize)
|
||||||
} else {
|
} else {
|
||||||
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_representable<G: CodeGenerator + ?Sized>(
|
fn has_same_repr(ty: Self::Base, llvm_usize: IntType<'ctx>) -> Result<(), String> {
|
||||||
generator: &G,
|
let ctx = ty.get_context();
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: Self::Base,
|
let llvm_ndarray_ty = ty.get_element_type();
|
||||||
) -> Result<(), String> {
|
let AnyTypeEnum::StructType(llvm_ndarray_ty) = llvm_ndarray_ty else {
|
||||||
Self::is_representable(llvm_ty, generator.get_size_type(ctx))
|
return Err(format!(
|
||||||
|
"Expected struct type for `ShapeEntry` type, got {llvm_ndarray_ty}"
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
check_struct_type_matches_fields(
|
||||||
|
Self::fields(ctx, llvm_usize),
|
||||||
|
llvm_ndarray_ty,
|
||||||
|
"NDArray",
|
||||||
|
&[],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
||||||
|
@ -58,36 +58,6 @@ impl<'ctx> ContiguousNDArrayStructFields<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ContiguousNDArrayType<'ctx> {
|
impl<'ctx> ContiguousNDArrayType<'ctx> {
|
||||||
/// Checks whether `llvm_ty` represents a `ndarray` type, returning [Err] if it does not.
|
|
||||||
pub fn is_representable(
|
|
||||||
llvm_ty: PointerType<'ctx>,
|
|
||||||
llvm_usize: IntType<'ctx>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
let ctx = llvm_ty.get_context();
|
|
||||||
|
|
||||||
let llvm_ty = llvm_ty.get_element_type();
|
|
||||||
let AnyTypeEnum::StructType(llvm_ty) = llvm_ty else {
|
|
||||||
return Err(format!(
|
|
||||||
"Expected struct type for `ContiguousNDArray` type, got {llvm_ty}"
|
|
||||||
));
|
|
||||||
};
|
|
||||||
|
|
||||||
let fields = ContiguousNDArrayStructFields::new(ctx, llvm_usize);
|
|
||||||
|
|
||||||
check_struct_type_matches_fields(
|
|
||||||
fields,
|
|
||||||
llvm_ty,
|
|
||||||
"ContiguousNDArray",
|
|
||||||
&[(fields.data.name(), &|ty| {
|
|
||||||
if ty.is_pointer_type() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(format!("Expected T* for `ContiguousNDArray.data`, got {ty}"))
|
|
||||||
}
|
|
||||||
})],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an instance of [`StructFields`] containing all field accessors for this type.
|
/// Returns an instance of [`StructFields`] containing all field accessors for this type.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn fields(
|
fn fields(
|
||||||
@ -160,7 +130,7 @@ impl<'ctx> ContiguousNDArrayType<'ctx> {
|
|||||||
item: BasicTypeEnum<'ctx>,
|
item: BasicTypeEnum<'ctx>,
|
||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
debug_assert!(Self::is_representable(ptr_ty, llvm_usize).is_ok());
|
debug_assert!(Self::has_same_repr(ptr_ty, llvm_usize).is_ok());
|
||||||
|
|
||||||
Self { ty: ptr_ty, item, llvm_usize }
|
Self { ty: ptr_ty, item, llvm_usize }
|
||||||
}
|
}
|
||||||
@ -222,24 +192,41 @@ impl<'ctx> ProxyType<'ctx> for ContiguousNDArrayType<'ctx> {
|
|||||||
type Base = PointerType<'ctx>;
|
type Base = PointerType<'ctx>;
|
||||||
type Value = ContiguousNDArrayValue<'ctx>;
|
type Value = ContiguousNDArrayValue<'ctx>;
|
||||||
|
|
||||||
fn is_type<G: CodeGenerator + ?Sized>(
|
fn is_representable(
|
||||||
generator: &G,
|
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: impl BasicType<'ctx>,
|
llvm_ty: impl BasicType<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
||||||
<Self as ProxyType<'ctx>>::is_representable(generator, ctx, ty)
|
Self::has_same_repr(ty, llvm_usize)
|
||||||
} else {
|
} else {
|
||||||
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_representable<G: CodeGenerator + ?Sized>(
|
fn has_same_repr(ty: Self::Base, llvm_usize: IntType<'ctx>) -> Result<(), String> {
|
||||||
generator: &G,
|
let ctx = ty.get_context();
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: Self::Base,
|
let llvm_ty = ty.get_element_type();
|
||||||
) -> Result<(), String> {
|
let AnyTypeEnum::StructType(llvm_ty) = llvm_ty else {
|
||||||
Self::is_representable(llvm_ty, generator.get_size_type(ctx))
|
return Err(format!(
|
||||||
|
"Expected struct type for `ContiguousNDArray` type, got {llvm_ty}"
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
let fields = ContiguousNDArrayStructFields::new(ctx, llvm_usize);
|
||||||
|
|
||||||
|
check_struct_type_matches_fields(
|
||||||
|
fields,
|
||||||
|
llvm_ty,
|
||||||
|
"ContiguousNDArray",
|
||||||
|
&[(fields.data.name(), &|ty| {
|
||||||
|
if ty.is_pointer_type() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(format!("Expected T* for `ContiguousNDArray.data`, got {ty}"))
|
||||||
|
}
|
||||||
|
})],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
||||||
|
@ -35,25 +35,6 @@ pub struct NDIndexStructFields<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> NDIndexType<'ctx> {
|
impl<'ctx> NDIndexType<'ctx> {
|
||||||
/// Checks whether `llvm_ty` represents a `ndindex` type, returning [Err] if it does not.
|
|
||||||
pub fn is_representable(
|
|
||||||
llvm_ty: PointerType<'ctx>,
|
|
||||||
llvm_usize: IntType<'ctx>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
let ctx = llvm_ty.get_context();
|
|
||||||
|
|
||||||
let llvm_ty = llvm_ty.get_element_type();
|
|
||||||
let AnyTypeEnum::StructType(llvm_ty) = llvm_ty else {
|
|
||||||
return Err(format!(
|
|
||||||
"Expected struct type for `ContiguousNDArray` type, got {llvm_ty}"
|
|
||||||
));
|
|
||||||
};
|
|
||||||
|
|
||||||
let fields = NDIndexStructFields::new(ctx, llvm_usize);
|
|
||||||
|
|
||||||
check_struct_type_matches_fields(fields, llvm_ty, "NDIndex", &[])
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn fields(
|
fn fields(
|
||||||
ctx: impl AsContextRef<'ctx>,
|
ctx: impl AsContextRef<'ctx>,
|
||||||
@ -96,7 +77,7 @@ impl<'ctx> NDIndexType<'ctx> {
|
|||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_type(ptr_ty: PointerType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
pub fn from_type(ptr_ty: PointerType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
||||||
debug_assert!(Self::is_representable(ptr_ty, llvm_usize).is_ok());
|
debug_assert!(Self::has_same_repr(ptr_ty, llvm_usize).is_ok());
|
||||||
|
|
||||||
Self { ty: ptr_ty, llvm_usize }
|
Self { ty: ptr_ty, llvm_usize }
|
||||||
}
|
}
|
||||||
@ -180,24 +161,30 @@ impl<'ctx> ProxyType<'ctx> for NDIndexType<'ctx> {
|
|||||||
type Base = PointerType<'ctx>;
|
type Base = PointerType<'ctx>;
|
||||||
type Value = NDIndexValue<'ctx>;
|
type Value = NDIndexValue<'ctx>;
|
||||||
|
|
||||||
fn is_type<G: CodeGenerator + ?Sized>(
|
fn is_representable(
|
||||||
generator: &G,
|
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: impl BasicType<'ctx>,
|
llvm_ty: impl BasicType<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
||||||
<Self as ProxyType<'ctx>>::is_representable(generator, ctx, ty)
|
Self::has_same_repr(ty, llvm_usize)
|
||||||
} else {
|
} else {
|
||||||
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_representable<G: CodeGenerator + ?Sized>(
|
fn has_same_repr(ty: Self::Base, llvm_usize: IntType<'ctx>) -> Result<(), String> {
|
||||||
generator: &G,
|
let ctx = ty.get_context();
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: Self::Base,
|
let llvm_ty = ty.get_element_type();
|
||||||
) -> Result<(), String> {
|
let AnyTypeEnum::StructType(llvm_ty) = llvm_ty else {
|
||||||
Self::is_representable(llvm_ty, generator.get_size_type(ctx))
|
return Err(format!(
|
||||||
|
"Expected struct type for `ContiguousNDArray` type, got {llvm_ty}"
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
let fields = NDIndexStructFields::new(ctx, llvm_usize);
|
||||||
|
|
||||||
|
check_struct_type_matches_fields(fields, llvm_ty, "NDIndex", &[])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
||||||
|
@ -62,26 +62,6 @@ pub struct NDArrayStructFields<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> NDArrayType<'ctx> {
|
impl<'ctx> NDArrayType<'ctx> {
|
||||||
/// Checks whether `llvm_ty` represents a `ndarray` type, returning [Err] if it does not.
|
|
||||||
pub fn is_representable(
|
|
||||||
llvm_ty: PointerType<'ctx>,
|
|
||||||
llvm_usize: IntType<'ctx>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
let ctx = llvm_ty.get_context();
|
|
||||||
|
|
||||||
let llvm_ndarray_ty = llvm_ty.get_element_type();
|
|
||||||
let AnyTypeEnum::StructType(llvm_ndarray_ty) = llvm_ndarray_ty else {
|
|
||||||
return Err(format!("Expected struct type for `NDArray` type, got {llvm_ndarray_ty}"));
|
|
||||||
};
|
|
||||||
|
|
||||||
check_struct_type_matches_fields(
|
|
||||||
Self::fields(ctx, llvm_usize),
|
|
||||||
llvm_ndarray_ty,
|
|
||||||
"NDArray",
|
|
||||||
&[],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an instance of [`StructFields`] containing all field accessors for this type.
|
/// Returns an instance of [`StructFields`] containing all field accessors for this type.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn fields(
|
fn fields(
|
||||||
@ -211,7 +191,7 @@ impl<'ctx> NDArrayType<'ctx> {
|
|||||||
ndims: u64,
|
ndims: u64,
|
||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
debug_assert!(Self::is_representable(ptr_ty, llvm_usize).is_ok());
|
debug_assert!(Self::has_same_repr(ptr_ty, llvm_usize).is_ok());
|
||||||
|
|
||||||
NDArrayType { ty: ptr_ty, dtype, ndims, llvm_usize }
|
NDArrayType { ty: ptr_ty, dtype, ndims, llvm_usize }
|
||||||
}
|
}
|
||||||
@ -450,24 +430,31 @@ impl<'ctx> ProxyType<'ctx> for NDArrayType<'ctx> {
|
|||||||
type Base = PointerType<'ctx>;
|
type Base = PointerType<'ctx>;
|
||||||
type Value = NDArrayValue<'ctx>;
|
type Value = NDArrayValue<'ctx>;
|
||||||
|
|
||||||
fn is_type<G: CodeGenerator + ?Sized>(
|
fn is_representable(
|
||||||
generator: &G,
|
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: impl BasicType<'ctx>,
|
llvm_ty: impl BasicType<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
||||||
<Self as ProxyType<'ctx>>::is_representable(generator, ctx, ty)
|
Self::has_same_repr(ty, llvm_usize)
|
||||||
} else {
|
} else {
|
||||||
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_representable<G: CodeGenerator + ?Sized>(
|
fn has_same_repr(ty: Self::Base, llvm_usize: IntType<'ctx>) -> Result<(), String> {
|
||||||
generator: &G,
|
let ctx = ty.get_context();
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: Self::Base,
|
let llvm_ndarray_ty = ty.get_element_type();
|
||||||
) -> Result<(), String> {
|
let AnyTypeEnum::StructType(llvm_ndarray_ty) = llvm_ndarray_ty else {
|
||||||
Self::is_representable(llvm_ty, generator.get_size_type(ctx))
|
return Err(format!("Expected struct type for `NDArray` type, got {llvm_ndarray_ty}"));
|
||||||
|
};
|
||||||
|
|
||||||
|
check_struct_type_matches_fields(
|
||||||
|
Self::fields(ctx, llvm_usize),
|
||||||
|
llvm_ndarray_ty,
|
||||||
|
"NDArray",
|
||||||
|
&[],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
||||||
|
@ -44,26 +44,6 @@ pub struct NDIterStructFields<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> NDIterType<'ctx> {
|
impl<'ctx> NDIterType<'ctx> {
|
||||||
/// Checks whether `llvm_ty` represents a `nditer` type, returning [Err] if it does not.
|
|
||||||
pub fn is_representable(
|
|
||||||
llvm_ty: PointerType<'ctx>,
|
|
||||||
llvm_usize: IntType<'ctx>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
let ctx = llvm_ty.get_context();
|
|
||||||
|
|
||||||
let llvm_ty = llvm_ty.get_element_type();
|
|
||||||
let AnyTypeEnum::StructType(llvm_ndarray_ty) = llvm_ty else {
|
|
||||||
return Err(format!("Expected struct type for `NDIter` type, got {llvm_ty}"));
|
|
||||||
};
|
|
||||||
|
|
||||||
check_struct_type_matches_fields(
|
|
||||||
Self::fields(ctx, llvm_usize),
|
|
||||||
llvm_ndarray_ty,
|
|
||||||
"NDIter",
|
|
||||||
&[],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an instance of [`StructFields`] containing all field accessors for this type.
|
/// Returns an instance of [`StructFields`] containing all field accessors for this type.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn fields(ctx: impl AsContextRef<'ctx>, llvm_usize: IntType<'ctx>) -> NDIterStructFields<'ctx> {
|
fn fields(ctx: impl AsContextRef<'ctx>, llvm_usize: IntType<'ctx>) -> NDIterStructFields<'ctx> {
|
||||||
@ -110,7 +90,7 @@ impl<'ctx> NDIterType<'ctx> {
|
|||||||
/// Creates an [`NDIterType`] from a [`PointerType`] representing an `NDIter`.
|
/// Creates an [`NDIterType`] from a [`PointerType`] representing an `NDIter`.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_type(ptr_ty: PointerType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
pub fn from_type(ptr_ty: PointerType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
||||||
debug_assert!(Self::is_representable(ptr_ty, llvm_usize).is_ok());
|
debug_assert!(Self::has_same_repr(ptr_ty, llvm_usize).is_ok());
|
||||||
|
|
||||||
Self { ty: ptr_ty, llvm_usize }
|
Self { ty: ptr_ty, llvm_usize }
|
||||||
}
|
}
|
||||||
@ -208,24 +188,31 @@ impl<'ctx> ProxyType<'ctx> for NDIterType<'ctx> {
|
|||||||
type Base = PointerType<'ctx>;
|
type Base = PointerType<'ctx>;
|
||||||
type Value = NDIterValue<'ctx>;
|
type Value = NDIterValue<'ctx>;
|
||||||
|
|
||||||
fn is_type<G: CodeGenerator + ?Sized>(
|
fn is_representable(
|
||||||
generator: &G,
|
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: impl BasicType<'ctx>,
|
llvm_ty: impl BasicType<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
||||||
<Self as ProxyType<'ctx>>::is_representable(generator, ctx, ty)
|
Self::has_same_repr(ty, llvm_usize)
|
||||||
} else {
|
} else {
|
||||||
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_representable<G: CodeGenerator + ?Sized>(
|
fn has_same_repr(ty: Self::Base, llvm_usize: IntType<'ctx>) -> Result<(), String> {
|
||||||
generator: &G,
|
let ctx = ty.get_context();
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: Self::Base,
|
let llvm_ty = ty.get_element_type();
|
||||||
) -> Result<(), String> {
|
let AnyTypeEnum::StructType(llvm_ndarray_ty) = llvm_ty else {
|
||||||
Self::is_representable(llvm_ty, generator.get_size_type(ctx))
|
return Err(format!("Expected struct type for `NDIter` type, got {llvm_ty}"));
|
||||||
|
};
|
||||||
|
|
||||||
|
check_struct_type_matches_fields(
|
||||||
|
Self::fields(ctx, llvm_usize),
|
||||||
|
llvm_ndarray_ty,
|
||||||
|
"NDIter",
|
||||||
|
&[],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
||||||
|
@ -17,12 +17,125 @@ use crate::{
|
|||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
pub struct RangeType<'ctx> {
|
pub struct RangeType<'ctx> {
|
||||||
ty: PointerType<'ctx>,
|
ty: PointerType<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> RangeType<'ctx> {
|
impl<'ctx> RangeType<'ctx> {
|
||||||
/// Checks whether `llvm_ty` represents a `range` type, returning [Err] if it does not.
|
/// Creates an LLVM type corresponding to the expected structure of a `Range`.
|
||||||
pub fn is_representable(llvm_ty: PointerType<'ctx>) -> Result<(), String> {
|
#[must_use]
|
||||||
let llvm_range_ty = llvm_ty.get_element_type();
|
fn llvm_type(ctx: &'ctx Context) -> PointerType<'ctx> {
|
||||||
|
// typedef int32_t Range[3];
|
||||||
|
let llvm_i32 = ctx.i32_type();
|
||||||
|
llvm_i32.array_type(3).ptr_type(AddressSpace::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_impl(ctx: &'ctx Context, llvm_usize: IntType<'ctx>) -> Self {
|
||||||
|
let llvm_range = Self::llvm_type(ctx);
|
||||||
|
|
||||||
|
RangeType { ty: llvm_range, llvm_usize }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an instance of [`RangeType`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(ctx: &CodeGenContext<'ctx, '_>) -> Self {
|
||||||
|
Self::new_impl(ctx.ctx, ctx.get_size_type())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an instance of [`RangeType`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn new_with_generator<G: CodeGenerator + ?Sized>(
|
||||||
|
generator: &G,
|
||||||
|
ctx: &'ctx Context,
|
||||||
|
) -> Self {
|
||||||
|
Self::new_impl(ctx, generator.get_size_type(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an [`RangeType`] from a [unifier type][Type].
|
||||||
|
#[must_use]
|
||||||
|
pub fn from_unifier_type(ctx: &mut CodeGenContext<'ctx, '_>, ty: Type) -> Self {
|
||||||
|
// Check unifier type
|
||||||
|
assert!(
|
||||||
|
matches!(&*ctx.unifier.get_ty_immutable(ty), TypeEnum::TObj { obj_id, .. } if *obj_id == ctx.primitives.range.obj_id(&ctx.unifier).unwrap())
|
||||||
|
);
|
||||||
|
|
||||||
|
Self::new(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an [`RangeType`] from a [`PointerType`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn from_type(ptr_ty: PointerType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
||||||
|
debug_assert!(Self::has_same_repr(ptr_ty, llvm_usize).is_ok());
|
||||||
|
|
||||||
|
RangeType { ty: ptr_ty, llvm_usize }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the type of all fields of this `range` type.
|
||||||
|
#[must_use]
|
||||||
|
pub fn value_type(&self) -> IntType<'ctx> {
|
||||||
|
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.
|
||||||
|
///
|
||||||
|
/// See [`ProxyType::raw_alloca`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn alloca<G: CodeGenerator + ?Sized>(
|
||||||
|
&self,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
name: Option<&'ctx str>,
|
||||||
|
) -> <Self as ProxyType<'ctx>>::Value {
|
||||||
|
<Self as ProxyType<'ctx>>::Value::from_pointer_value(
|
||||||
|
self.raw_alloca(ctx, name),
|
||||||
|
self.llvm_usize,
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allocates an instance of [`RangeValue`] as if by calling `alloca` on the base type.
|
||||||
|
///
|
||||||
|
/// See [`ProxyType::raw_alloca_var`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn alloca_var<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_var(generator, ctx, name),
|
||||||
|
self.llvm_usize,
|
||||||
|
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, self.llvm_usize, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> ProxyType<'ctx> for RangeType<'ctx> {
|
||||||
|
type Base = PointerType<'ctx>;
|
||||||
|
type Value = RangeValue<'ctx>;
|
||||||
|
|
||||||
|
fn is_representable(
|
||||||
|
llvm_ty: impl BasicType<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
||||||
|
Self::has_same_repr(ty, llvm_usize)
|
||||||
|
} else {
|
||||||
|
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_same_repr(ty: Self::Base, _: IntType<'ctx>) -> Result<(), String> {
|
||||||
|
let llvm_range_ty = ty.get_element_type();
|
||||||
let AnyTypeEnum::ArrayType(llvm_range_ty) = llvm_range_ty else {
|
let AnyTypeEnum::ArrayType(llvm_range_ty) = llvm_range_ty else {
|
||||||
return Err(format!("Expected array type for `range` type, got {llvm_range_ty}"));
|
return Err(format!("Expected array type for `range` type, got {llvm_range_ty}"));
|
||||||
};
|
};
|
||||||
@ -49,120 +162,6 @@ impl<'ctx> RangeType<'ctx> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an LLVM type corresponding to the expected structure of a `Range`.
|
|
||||||
#[must_use]
|
|
||||||
fn llvm_type(ctx: &'ctx Context) -> PointerType<'ctx> {
|
|
||||||
// typedef int32_t Range[3];
|
|
||||||
let llvm_i32 = ctx.i32_type();
|
|
||||||
llvm_i32.array_type(3).ptr_type(AddressSpace::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_impl(ctx: &'ctx Context) -> Self {
|
|
||||||
let llvm_range = Self::llvm_type(ctx);
|
|
||||||
|
|
||||||
RangeType { ty: llvm_range }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an instance of [`RangeType`].
|
|
||||||
#[must_use]
|
|
||||||
pub fn new(ctx: &CodeGenContext<'ctx, '_>) -> Self {
|
|
||||||
RangeType::new_impl(ctx.ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an instance of [`RangeType`].
|
|
||||||
#[must_use]
|
|
||||||
pub fn new_with_generator<G: CodeGenerator + ?Sized>(_: &G, ctx: &'ctx Context) -> Self {
|
|
||||||
Self::new_impl(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an [`RangeType`] from a [unifier type][Type].
|
|
||||||
#[must_use]
|
|
||||||
pub fn from_unifier_type(ctx: &mut CodeGenContext<'ctx, '_>, ty: Type) -> Self {
|
|
||||||
// Check unifier type
|
|
||||||
assert!(
|
|
||||||
matches!(&*ctx.unifier.get_ty_immutable(ty), TypeEnum::TObj { obj_id, .. } if *obj_id == ctx.primitives.range.obj_id(&ctx.unifier).unwrap())
|
|
||||||
);
|
|
||||||
|
|
||||||
Self::new(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an [`RangeType`] from a [`PointerType`].
|
|
||||||
#[must_use]
|
|
||||||
pub fn from_type(ptr_ty: PointerType<'ctx>) -> Self {
|
|
||||||
debug_assert!(Self::is_representable(ptr_ty).is_ok());
|
|
||||||
|
|
||||||
RangeType { ty: ptr_ty }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the type of all fields of this `range` type.
|
|
||||||
#[must_use]
|
|
||||||
pub fn value_type(&self) -> IntType<'ctx> {
|
|
||||||
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.
|
|
||||||
///
|
|
||||||
/// See [`ProxyType::raw_alloca`].
|
|
||||||
#[must_use]
|
|
||||||
pub fn alloca<G: CodeGenerator + ?Sized>(
|
|
||||||
&self,
|
|
||||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
|
||||||
name: Option<&'ctx str>,
|
|
||||||
) -> <Self as ProxyType<'ctx>>::Value {
|
|
||||||
<Self as ProxyType<'ctx>>::Value::from_pointer_value(self.raw_alloca(ctx, name), name)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Allocates an instance of [`RangeValue`] as if by calling `alloca` on the base type.
|
|
||||||
///
|
|
||||||
/// See [`ProxyType::raw_alloca_var`].
|
|
||||||
#[must_use]
|
|
||||||
pub fn alloca_var<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_var(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> {
|
|
||||||
type Base = PointerType<'ctx>;
|
|
||||||
type Value = RangeValue<'ctx>;
|
|
||||||
|
|
||||||
fn is_type<G: CodeGenerator + ?Sized>(
|
|
||||||
generator: &G,
|
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: impl BasicType<'ctx>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
|
||||||
<Self as ProxyType<'ctx>>::is_representable(generator, ctx, ty)
|
|
||||||
} else {
|
|
||||||
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_representable<G: CodeGenerator + ?Sized>(
|
|
||||||
_: &G,
|
|
||||||
_: &'ctx Context,
|
|
||||||
llvm_ty: Self::Base,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
Self::is_representable(llvm_ty)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
||||||
self.as_base_type().get_element_type().into_struct_type()
|
self.as_base_type().get_element_type().into_struct_type()
|
||||||
}
|
}
|
||||||
|
@ -21,11 +21,6 @@ pub struct TupleType<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> TupleType<'ctx> {
|
impl<'ctx> TupleType<'ctx> {
|
||||||
/// Checks whether `llvm_ty` represents any tuple type, returning [Err] if it does not.
|
|
||||||
pub fn is_representable(_value: StructType<'ctx>) -> Result<(), String> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an LLVM type corresponding to the expected structure of a tuple.
|
/// Creates an LLVM type corresponding to the expected structure of a tuple.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn llvm_type(ctx: &'ctx Context, tys: &[BasicTypeEnum<'ctx>]) -> StructType<'ctx> {
|
fn llvm_type(ctx: &'ctx Context, tys: &[BasicTypeEnum<'ctx>]) -> StructType<'ctx> {
|
||||||
@ -83,7 +78,7 @@ impl<'ctx> TupleType<'ctx> {
|
|||||||
/// Creates an [`TupleType`] from a [`StructType`].
|
/// Creates an [`TupleType`] from a [`StructType`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_type(struct_ty: StructType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
pub fn from_type(struct_ty: StructType<'ctx>, llvm_usize: IntType<'ctx>) -> Self {
|
||||||
debug_assert!(Self::is_representable(struct_ty).is_ok());
|
debug_assert!(Self::has_same_repr(struct_ty, llvm_usize).is_ok());
|
||||||
|
|
||||||
TupleType { ty: struct_ty, llvm_usize }
|
TupleType { ty: struct_ty, llvm_usize }
|
||||||
}
|
}
|
||||||
@ -165,24 +160,19 @@ impl<'ctx> ProxyType<'ctx> for TupleType<'ctx> {
|
|||||||
type Base = StructType<'ctx>;
|
type Base = StructType<'ctx>;
|
||||||
type Value = TupleValue<'ctx>;
|
type Value = TupleValue<'ctx>;
|
||||||
|
|
||||||
fn is_type<G: CodeGenerator + ?Sized>(
|
fn is_representable(
|
||||||
generator: &G,
|
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: impl BasicType<'ctx>,
|
llvm_ty: impl BasicType<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
if let BasicTypeEnum::StructType(ty) = llvm_ty.as_basic_type_enum() {
|
if let BasicTypeEnum::StructType(ty) = llvm_ty.as_basic_type_enum() {
|
||||||
<Self as ProxyType<'ctx>>::is_representable(generator, ctx, ty)
|
Self::has_same_repr(ty, llvm_usize)
|
||||||
} else {
|
} else {
|
||||||
Err(format!("Expected struct type, got {llvm_ty:?}"))
|
Err(format!("Expected struct type, got {llvm_ty:?}"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_representable<G: CodeGenerator + ?Sized>(
|
fn has_same_repr(_: Self::Base, _: IntType<'ctx>) -> Result<(), String> {
|
||||||
_generator: &G,
|
Ok(())
|
||||||
_ctx: &'ctx Context,
|
|
||||||
llvm_ty: Self::Base,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
Self::is_representable(llvm_ty)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
||||||
|
@ -61,50 +61,6 @@ impl<'ctx> SliceFields<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> SliceType<'ctx> {
|
impl<'ctx> SliceType<'ctx> {
|
||||||
/// Checks whether `llvm_ty` represents a `slice` type, returning [Err] if it does not.
|
|
||||||
pub fn is_representable(
|
|
||||||
llvm_ty: PointerType<'ctx>,
|
|
||||||
llvm_usize: IntType<'ctx>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
let ctx = llvm_ty.get_context();
|
|
||||||
|
|
||||||
let fields = SliceFields::new(ctx, llvm_usize);
|
|
||||||
|
|
||||||
let llvm_ty = llvm_ty.get_element_type();
|
|
||||||
let AnyTypeEnum::StructType(llvm_ty) = llvm_ty else {
|
|
||||||
return Err(format!("Expected struct type for `Slice` type, got {llvm_ty}"));
|
|
||||||
};
|
|
||||||
|
|
||||||
check_struct_type_matches_fields(
|
|
||||||
fields,
|
|
||||||
llvm_ty,
|
|
||||||
"Slice",
|
|
||||||
&[
|
|
||||||
(fields.start.name(), &|ty| {
|
|
||||||
if ty.is_int_type() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(format!("Expected int type for `Slice.start`, got {ty}"))
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
(fields.stop.name(), &|ty| {
|
|
||||||
if ty.is_int_type() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(format!("Expected int type for `Slice.stop`, got {ty}"))
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
(fields.step.name(), &|ty| {
|
|
||||||
if ty.is_int_type() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(format!("Expected int type for `Slice.step`, got {ty}"))
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Move this into e.g. StructProxyType
|
// TODO: Move this into e.g. StructProxyType
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_fields(&self) -> SliceFields<'ctx> {
|
pub fn get_fields(&self) -> SliceFields<'ctx> {
|
||||||
@ -156,7 +112,7 @@ impl<'ctx> SliceType<'ctx> {
|
|||||||
int_ty: IntType<'ctx>,
|
int_ty: IntType<'ctx>,
|
||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
debug_assert!(Self::is_representable(ptr_ty, int_ty).is_ok());
|
debug_assert!(Self::has_same_repr(ptr_ty, int_ty).is_ok());
|
||||||
|
|
||||||
Self { ty: ptr_ty, int_ty, llvm_usize }
|
Self { ty: ptr_ty, int_ty, llvm_usize }
|
||||||
}
|
}
|
||||||
@ -221,24 +177,55 @@ impl<'ctx> ProxyType<'ctx> for SliceType<'ctx> {
|
|||||||
type Base = PointerType<'ctx>;
|
type Base = PointerType<'ctx>;
|
||||||
type Value = SliceValue<'ctx>;
|
type Value = SliceValue<'ctx>;
|
||||||
|
|
||||||
fn is_type<G: CodeGenerator + ?Sized>(
|
fn is_representable(
|
||||||
generator: &G,
|
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: impl BasicType<'ctx>,
|
llvm_ty: impl BasicType<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
if let BasicTypeEnum::PointerType(ty) = llvm_ty.as_basic_type_enum() {
|
||||||
<Self as ProxyType<'ctx>>::is_representable(generator, ctx, ty)
|
Self::has_same_repr(ty, llvm_usize)
|
||||||
} else {
|
} else {
|
||||||
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
Err(format!("Expected pointer type, got {llvm_ty:?}"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_representable<G: CodeGenerator + ?Sized>(
|
fn has_same_repr(ty: Self::Base, llvm_usize: IntType<'ctx>) -> Result<(), String> {
|
||||||
generator: &G,
|
let ctx = ty.get_context();
|
||||||
ctx: &'ctx Context,
|
|
||||||
llvm_ty: Self::Base,
|
let fields = SliceFields::new(ctx, llvm_usize);
|
||||||
) -> Result<(), String> {
|
|
||||||
Self::is_representable(llvm_ty, generator.get_size_type(ctx))
|
let llvm_ty = ty.get_element_type();
|
||||||
|
let AnyTypeEnum::StructType(llvm_ty) = llvm_ty else {
|
||||||
|
return Err(format!("Expected struct type for `Slice` type, got {llvm_ty}"));
|
||||||
|
};
|
||||||
|
|
||||||
|
check_struct_type_matches_fields(
|
||||||
|
fields,
|
||||||
|
llvm_ty,
|
||||||
|
"Slice",
|
||||||
|
&[
|
||||||
|
(fields.start.name(), &|ty| {
|
||||||
|
if ty.is_int_type() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(format!("Expected int type for `Slice.start`, got {ty}"))
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
(fields.stop.name(), &|ty| {
|
||||||
|
if ty.is_int_type() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(format!("Expected int type for `Slice.stop`, got {ty}"))
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
(fields.step.name(), &|ty| {
|
||||||
|
if ty.is_int_type() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(format!("Expected int type for `Slice.step`, got {ty}"))
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
fn alloca_type(&self) -> impl BasicType<'ctx> {
|
||||||
|
@ -21,15 +21,6 @@ pub struct ListValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ListValue<'ctx> {
|
impl<'ctx> ListValue<'ctx> {
|
||||||
/// Checks whether `value` is an instance of `list`, returning [Err] if `value` is not an
|
|
||||||
/// instance.
|
|
||||||
pub fn is_representable(
|
|
||||||
value: PointerValue<'ctx>,
|
|
||||||
llvm_usize: IntType<'ctx>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
ListType::is_representable(value.get_type(), llvm_usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an [`ListValue`] from a [`PointerValue`].
|
/// Creates an [`ListValue`] from a [`PointerValue`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_pointer_value(
|
pub fn from_pointer_value(
|
||||||
@ -37,7 +28,7 @@ impl<'ctx> ListValue<'ctx> {
|
|||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
debug_assert!(Self::is_representable(ptr, llvm_usize).is_ok());
|
debug_assert!(Self::is_instance(ptr, llvm_usize).is_ok());
|
||||||
|
|
||||||
ListValue { value: ptr, llvm_usize, name }
|
ListValue { value: ptr, llvm_usize, name }
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use inkwell::{context::Context, values::BasicValue};
|
use inkwell::{types::IntType, values::BasicValue};
|
||||||
|
|
||||||
use super::types::ProxyType;
|
use super::types::ProxyType;
|
||||||
use crate::codegen::CodeGenerator;
|
|
||||||
pub use array::*;
|
pub use array::*;
|
||||||
pub use list::*;
|
pub use list::*;
|
||||||
pub use range::*;
|
pub use range::*;
|
||||||
@ -24,21 +23,8 @@ pub trait ProxyValue<'ctx>: Into<Self::Base> {
|
|||||||
type Type: ProxyType<'ctx, Value = Self>;
|
type Type: ProxyType<'ctx, Value = Self>;
|
||||||
|
|
||||||
/// Checks whether `value` can be represented by this [`ProxyValue`].
|
/// Checks whether `value` can be represented by this [`ProxyValue`].
|
||||||
fn is_instance<G: CodeGenerator + ?Sized>(
|
fn is_instance(value: impl BasicValue<'ctx>, llvm_usize: IntType<'ctx>) -> Result<(), String> {
|
||||||
generator: &G,
|
Self::Type::is_representable(value.as_basic_value_enum().get_type(), llvm_usize)
|
||||||
ctx: &'ctx Context,
|
|
||||||
value: impl BasicValue<'ctx>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
Self::Type::is_type(generator, ctx, value.as_basic_value_enum().get_type())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks whether `value` can be represented by this [`ProxyValue`].
|
|
||||||
fn is_representable<G: CodeGenerator + ?Sized>(
|
|
||||||
generator: &G,
|
|
||||||
ctx: &'ctx Context,
|
|
||||||
value: Self::Base,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
Self::is_instance(generator, ctx, value.as_basic_value_enum())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the [type][ProxyType] of this value.
|
/// Returns the [type][ProxyType] of this value.
|
||||||
|
@ -26,15 +26,6 @@ pub struct ShapeEntryValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ShapeEntryValue<'ctx> {
|
impl<'ctx> ShapeEntryValue<'ctx> {
|
||||||
/// Checks whether `value` is an instance of `ShapeEntry`, returning [Err] if `value` is
|
|
||||||
/// not an instance.
|
|
||||||
pub fn is_representable(
|
|
||||||
value: PointerValue<'ctx>,
|
|
||||||
llvm_usize: IntType<'ctx>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
<Self as ProxyValue<'ctx>>::Type::is_representable(value.get_type(), llvm_usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an [`ShapeEntryValue`] from a [`PointerValue`].
|
/// Creates an [`ShapeEntryValue`] from a [`PointerValue`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_pointer_value(
|
pub fn from_pointer_value(
|
||||||
@ -42,7 +33,7 @@ impl<'ctx> ShapeEntryValue<'ctx> {
|
|||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
debug_assert!(Self::is_representable(ptr, llvm_usize).is_ok());
|
debug_assert!(Self::is_instance(ptr, llvm_usize).is_ok());
|
||||||
|
|
||||||
Self { value: ptr, llvm_usize, name }
|
Self { value: ptr, llvm_usize, name }
|
||||||
}
|
}
|
||||||
|
@ -23,15 +23,6 @@ pub struct ContiguousNDArrayValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ContiguousNDArrayValue<'ctx> {
|
impl<'ctx> ContiguousNDArrayValue<'ctx> {
|
||||||
/// Checks whether `value` is an instance of `ContiguousNDArray`, returning [Err] if `value` is
|
|
||||||
/// not an instance.
|
|
||||||
pub fn is_representable(
|
|
||||||
value: PointerValue<'ctx>,
|
|
||||||
llvm_usize: IntType<'ctx>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
<Self as ProxyValue<'ctx>>::Type::is_representable(value.get_type(), llvm_usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an [`ContiguousNDArrayValue`] from a [`PointerValue`].
|
/// Creates an [`ContiguousNDArrayValue`] from a [`PointerValue`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_pointer_value(
|
pub fn from_pointer_value(
|
||||||
@ -40,7 +31,7 @@ impl<'ctx> ContiguousNDArrayValue<'ctx> {
|
|||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
debug_assert!(Self::is_representable(ptr, llvm_usize).is_ok());
|
debug_assert!(Self::is_instance(ptr, llvm_usize).is_ok());
|
||||||
|
|
||||||
Self { value: ptr, item: dtype, llvm_usize, name }
|
Self { value: ptr, item: dtype, llvm_usize, name }
|
||||||
}
|
}
|
||||||
|
@ -30,15 +30,6 @@ pub struct NDIndexValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> NDIndexValue<'ctx> {
|
impl<'ctx> NDIndexValue<'ctx> {
|
||||||
/// Checks whether `value` is an instance of `ndindex`, returning [Err] if `value` is not an
|
|
||||||
/// instance.
|
|
||||||
pub fn is_representable(
|
|
||||||
value: PointerValue<'ctx>,
|
|
||||||
llvm_usize: IntType<'ctx>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
<Self as ProxyValue<'ctx>>::Type::is_representable(value.get_type(), llvm_usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an [`NDIndexValue`] from a [`PointerValue`].
|
/// Creates an [`NDIndexValue`] from a [`PointerValue`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_pointer_value(
|
pub fn from_pointer_value(
|
||||||
@ -46,7 +37,7 @@ impl<'ctx> NDIndexValue<'ctx> {
|
|||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
debug_assert!(Self::is_representable(ptr, llvm_usize).is_ok());
|
debug_assert!(Self::is_instance(ptr, llvm_usize).is_ok());
|
||||||
|
|
||||||
Self { value: ptr, llvm_usize, name }
|
Self { value: ptr, llvm_usize, name }
|
||||||
}
|
}
|
||||||
|
@ -49,15 +49,6 @@ pub struct NDArrayValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> NDArrayValue<'ctx> {
|
impl<'ctx> NDArrayValue<'ctx> {
|
||||||
/// Checks whether `value` is an instance of `NDArray`, returning [Err] if `value` is not an
|
|
||||||
/// instance.
|
|
||||||
pub fn is_representable(
|
|
||||||
value: PointerValue<'ctx>,
|
|
||||||
llvm_usize: IntType<'ctx>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
NDArrayType::is_representable(value.get_type(), llvm_usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an [`NDArrayValue`] from a [`PointerValue`].
|
/// Creates an [`NDArrayValue`] from a [`PointerValue`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_pointer_value(
|
pub fn from_pointer_value(
|
||||||
@ -67,7 +58,7 @@ impl<'ctx> NDArrayValue<'ctx> {
|
|||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
debug_assert!(Self::is_representable(ptr, llvm_usize).is_ok());
|
debug_assert!(Self::is_instance(ptr, llvm_usize).is_ok());
|
||||||
|
|
||||||
NDArrayValue { value: ptr, dtype, ndims, llvm_usize, name }
|
NDArrayValue { value: ptr, dtype, ndims, llvm_usize, name }
|
||||||
}
|
}
|
||||||
|
@ -23,15 +23,6 @@ pub struct NDIterValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> NDIterValue<'ctx> {
|
impl<'ctx> NDIterValue<'ctx> {
|
||||||
/// Checks whether `value` is an instance of `NDArray`, returning [Err] if `value` is not an
|
|
||||||
/// instance.
|
|
||||||
pub fn is_representable(
|
|
||||||
value: PointerValue<'ctx>,
|
|
||||||
llvm_usize: IntType<'ctx>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
<Self as ProxyValue>::Type::is_representable(value.get_type(), llvm_usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an [`NDArrayValue`] from a [`PointerValue`].
|
/// Creates an [`NDArrayValue`] from a [`PointerValue`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_pointer_value(
|
pub fn from_pointer_value(
|
||||||
@ -41,7 +32,7 @@ impl<'ctx> NDIterValue<'ctx> {
|
|||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
debug_assert!(Self::is_representable(ptr, llvm_usize).is_ok());
|
debug_assert!(Self::is_instance(ptr, llvm_usize).is_ok());
|
||||||
|
|
||||||
Self { value: ptr, parent, indices, llvm_usize, name }
|
Self { value: ptr, parent, indices, llvm_usize, name }
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
use inkwell::values::{BasicValueEnum, IntValue, PointerValue};
|
use inkwell::{
|
||||||
|
types::IntType,
|
||||||
|
values::{BasicValueEnum, IntValue, PointerValue},
|
||||||
|
};
|
||||||
|
|
||||||
use super::ProxyValue;
|
use super::ProxyValue;
|
||||||
use crate::codegen::{types::RangeType, CodeGenContext};
|
use crate::codegen::{types::RangeType, CodeGenContext};
|
||||||
@ -7,21 +10,21 @@ use crate::codegen::{types::RangeType, CodeGenContext};
|
|||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct RangeValue<'ctx> {
|
pub struct RangeValue<'ctx> {
|
||||||
value: PointerValue<'ctx>,
|
value: PointerValue<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> RangeValue<'ctx> {
|
impl<'ctx> RangeValue<'ctx> {
|
||||||
/// Checks whether `value` is an instance of `range`, returning [Err] if `value` is not an instance.
|
|
||||||
pub fn is_representable(value: PointerValue<'ctx>) -> Result<(), String> {
|
|
||||||
RangeType::is_representable(value.get_type())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an [`RangeValue`] from a [`PointerValue`].
|
/// Creates an [`RangeValue`] from a [`PointerValue`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_pointer_value(ptr: PointerValue<'ctx>, name: Option<&'ctx str>) -> Self {
|
pub fn from_pointer_value(
|
||||||
debug_assert!(Self::is_representable(ptr).is_ok());
|
ptr: PointerValue<'ctx>,
|
||||||
|
llvm_usize: IntType<'ctx>,
|
||||||
|
name: Option<&'ctx str>,
|
||||||
|
) -> Self {
|
||||||
|
debug_assert!(Self::is_instance(ptr, llvm_usize).is_ok());
|
||||||
|
|
||||||
RangeValue { value: ptr, name }
|
RangeValue { value: ptr, llvm_usize, name }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ptr_to_start(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> {
|
fn ptr_to_start(&self, ctx: &CodeGenContext<'ctx, '_>) -> PointerValue<'ctx> {
|
||||||
@ -138,7 +141,7 @@ impl<'ctx> ProxyValue<'ctx> for RangeValue<'ctx> {
|
|||||||
type Type = RangeType<'ctx>;
|
type Type = RangeType<'ctx>;
|
||||||
|
|
||||||
fn get_type(&self) -> Self::Type {
|
fn get_type(&self) -> Self::Type {
|
||||||
RangeType::from_type(self.value.get_type())
|
RangeType::from_type(self.value.get_type(), self.llvm_usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_base_value(&self) -> Self::Base {
|
fn as_base_value(&self) -> Self::Base {
|
||||||
|
@ -14,15 +14,6 @@ pub struct TupleValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> TupleValue<'ctx> {
|
impl<'ctx> TupleValue<'ctx> {
|
||||||
/// Checks whether `value` is an instance of `tuple`, returning [Err] if `value` is not an
|
|
||||||
/// instance.
|
|
||||||
pub fn is_representable(
|
|
||||||
value: StructValue<'ctx>,
|
|
||||||
_llvm_usize: IntType<'ctx>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
TupleType::is_representable(value.get_type())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an [`TupleValue`] from a [`StructValue`].
|
/// Creates an [`TupleValue`] from a [`StructValue`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_struct_value(
|
pub fn from_struct_value(
|
||||||
@ -30,7 +21,7 @@ impl<'ctx> TupleValue<'ctx> {
|
|||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
debug_assert!(Self::is_representable(value, llvm_usize).is_ok());
|
debug_assert!(Self::is_instance(value, llvm_usize).is_ok());
|
||||||
|
|
||||||
Self { value, llvm_usize, name }
|
Self { value, llvm_usize, name }
|
||||||
}
|
}
|
||||||
|
@ -24,15 +24,6 @@ pub struct SliceValue<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> SliceValue<'ctx> {
|
impl<'ctx> SliceValue<'ctx> {
|
||||||
/// Checks whether `value` is an instance of `ContiguousNDArray`, returning [Err] if `value` is
|
|
||||||
/// not an instance.
|
|
||||||
pub fn is_representable(
|
|
||||||
value: PointerValue<'ctx>,
|
|
||||||
llvm_usize: IntType<'ctx>,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
<Self as ProxyValue<'ctx>>::Type::is_representable(value.get_type(), llvm_usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an [`SliceValue`] from a [`PointerValue`].
|
/// Creates an [`SliceValue`] from a [`PointerValue`].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn from_pointer_value(
|
pub fn from_pointer_value(
|
||||||
@ -41,7 +32,7 @@ impl<'ctx> SliceValue<'ctx> {
|
|||||||
llvm_usize: IntType<'ctx>,
|
llvm_usize: IntType<'ctx>,
|
||||||
name: Option<&'ctx str>,
|
name: Option<&'ctx str>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
debug_assert!(Self::is_representable(ptr, llvm_usize).is_ok());
|
debug_assert!(Self::is_instance(ptr, llvm_usize).is_ok());
|
||||||
|
|
||||||
Self { value: ptr, int_ty, llvm_usize, name }
|
Self { value: ptr, int_ty, llvm_usize, name }
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,10 @@ use crate::{
|
|||||||
builtin_fns,
|
builtin_fns,
|
||||||
numpy::*,
|
numpy::*,
|
||||||
stmt::{exn_constructor, gen_if_callback},
|
stmt::{exn_constructor, gen_if_callback},
|
||||||
types::ndarray::NDArrayType,
|
types::{ndarray::NDArrayType, RangeType},
|
||||||
values::{
|
values::{
|
||||||
ndarray::{shape::parse_numpy_int_sequence, ScalarOrNDArray},
|
ndarray::{shape::parse_numpy_int_sequence, ScalarOrNDArray},
|
||||||
ProxyValue, RangeValue,
|
ProxyValue,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
symbol_resolver::SymbolValue,
|
symbol_resolver::SymbolValue,
|
||||||
@ -577,7 +577,7 @@ impl<'a> BuiltinBuilder<'a> {
|
|||||||
let (zelf_ty, zelf) = obj.unwrap();
|
let (zelf_ty, zelf) = obj.unwrap();
|
||||||
let zelf =
|
let zelf =
|
||||||
zelf.to_basic_value_enum(ctx, generator, zelf_ty)?.into_pointer_value();
|
zelf.to_basic_value_enum(ctx, generator, zelf_ty)?.into_pointer_value();
|
||||||
let zelf = RangeValue::from_pointer_value(zelf, Some("range"));
|
let zelf = RangeType::new(ctx).map_value(zelf, Some("range"));
|
||||||
|
|
||||||
let mut start = None;
|
let mut start = None;
|
||||||
let mut stop = None;
|
let mut stop = None;
|
||||||
|
Loading…
Reference in New Issue
Block a user