This commit is contained in:
Folkert 2023-06-18 14:21:48 +02:00
parent 4a9514d2c4
commit 0247237fe8
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
16 changed files with 625 additions and 163 deletions

View file

@ -23,7 +23,7 @@ use inkwell::passes::{PassManager, PassManagerBuilder};
use inkwell::types::{
AnyType, BasicMetadataTypeEnum, BasicType, BasicTypeEnum, FunctionType, IntType, StructType,
};
use inkwell::values::BasicValueEnum::{self};
use inkwell::values::BasicValueEnum;
use inkwell::values::{
BasicMetadataValueEnum, CallSiteValue, FunctionValue, InstructionValue, IntValue, PointerValue,
StructValue,
@ -1379,12 +1379,13 @@ pub(crate) fn build_exp_expr<'a, 'ctx>(
layout_interner.get_repr(layout),
);
lookup_at_index_ptr2(
lookup_at_index_ptr(
env,
layout_interner,
field_layouts,
*index as usize,
ptr,
None,
target_loaded_type,
)
}
@ -1404,7 +1405,7 @@ pub(crate) fn build_exp_expr<'a, 'ctx>(
field_layouts,
*index as usize,
argument.into_pointer_value(),
struct_type.into_struct_type(),
Some(struct_type.into_struct_type()),
target_loaded_type,
)
}
@ -1430,12 +1431,13 @@ pub(crate) fn build_exp_expr<'a, 'ctx>(
layout_interner.get_repr(layout),
);
lookup_at_index_ptr2(
lookup_at_index_ptr(
env,
layout_interner,
field_layouts,
*index as usize,
ptr,
None,
target_loaded_type,
)
}
@ -1463,13 +1465,117 @@ pub(crate) fn build_exp_expr<'a, 'ctx>(
// the tag id is not stored
*index as usize,
argument.into_pointer_value(),
struct_type.into_struct_type(),
Some(struct_type.into_struct_type()),
target_loaded_type,
)
}
}
}
UnionFieldPtrAtIndex {
tag_id,
structure,
index,
union_layout,
} => {
// cast the argument bytes into the desired shape for this tag
let (argument, structure_layout) = scope.load_symbol_and_layout(structure);
let ret_repr = layout_interner.get_repr(layout);
let pointer_value = match union_layout {
UnionLayout::NonRecursive(_) => unreachable!(),
UnionLayout::Recursive(tag_layouts) => {
debug_assert!(argument.is_pointer_value());
let field_layouts = tag_layouts[*tag_id as usize];
let ptr = tag_pointer_clear_tag_id(env, argument.into_pointer_value());
let target_loaded_type = basic_type_from_layout(env, layout_interner, ret_repr);
union_field_at_index(
env,
layout_interner,
field_layouts,
None,
*index as usize,
ptr,
target_loaded_type,
)
}
UnionLayout::NonNullableUnwrapped(field_layouts) => {
let struct_layout = LayoutRepr::struct_(field_layouts);
let struct_type = basic_type_from_layout(env, layout_interner, struct_layout);
let target_loaded_type = basic_type_from_layout(env, layout_interner, ret_repr);
union_field_at_index(
env,
layout_interner,
field_layouts,
Some(struct_type.into_struct_type()),
*index as usize,
argument.into_pointer_value(),
target_loaded_type,
)
}
UnionLayout::NullableWrapped {
nullable_id,
other_tags,
} => {
debug_assert!(argument.is_pointer_value());
debug_assert_ne!(*tag_id, *nullable_id);
let tag_index = if *tag_id < *nullable_id {
*tag_id
} else {
tag_id - 1
};
let field_layouts = other_tags[tag_index as usize];
let ptr = tag_pointer_clear_tag_id(env, argument.into_pointer_value());
let target_loaded_type = basic_type_from_layout(env, layout_interner, ret_repr);
union_field_at_index(
env,
layout_interner,
field_layouts,
None,
*index as usize,
ptr,
target_loaded_type,
)
.into()
}
UnionLayout::NullableUnwrapped {
nullable_id,
other_fields,
} => {
debug_assert!(argument.is_pointer_value());
debug_assert_ne!(*tag_id != 0, *nullable_id);
let field_layouts = other_fields;
let struct_layout = LayoutRepr::struct_(field_layouts);
let struct_type = basic_type_from_layout(env, layout_interner, struct_layout);
let target_loaded_type = basic_type_from_layout(env, layout_interner, ret_repr);
union_field_at_index(
env,
layout_interner,
field_layouts,
Some(struct_type.into_struct_type()),
// the tag id is not stored
*index as usize,
argument.into_pointer_value(),
target_loaded_type,
)
}
};
pointer_value.into()
}
GetTagId {
structure,
union_layout,
@ -2025,21 +2131,20 @@ fn lookup_at_index_ptr<'a, 'ctx>(
field_layouts: &[InLayout<'a>],
index: usize,
value: PointerValue<'ctx>,
struct_type: StructType<'ctx>,
struct_type: Option<StructType<'ctx>>,
target_loaded_type: BasicTypeEnum<'ctx>,
) -> BasicValueEnum<'ctx> {
let builder = env.builder;
let ptr = env.builder.build_pointer_cast(
let elem_ptr = union_field_at_index_help(
env,
layout_interner,
field_layouts,
struct_type,
index,
value,
struct_type.ptr_type(AddressSpace::default()),
"cast_lookup_at_index_ptr",
);
let elem_ptr = builder
.new_build_struct_gep(struct_type, ptr, index as u32, "at_index_struct_gep")
.unwrap();
let field_layout = field_layouts[index];
let result = load_roc_value(
env,
@ -2054,19 +2159,23 @@ fn lookup_at_index_ptr<'a, 'ctx>(
cast_if_necessary_for_opaque_recursive_pointers(env.builder, result, target_loaded_type)
}
fn lookup_at_index_ptr2<'a, 'ctx>(
fn union_field_at_index_help<'a, 'ctx>(
env: &Env<'a, 'ctx, '_>,
layout_interner: &STLayoutInterner<'a>,
field_layouts: &'a [InLayout<'a>],
opt_struct_type: Option<StructType<'ctx>>,
index: usize,
value: PointerValue<'ctx>,
target_loaded_type: BasicTypeEnum<'ctx>,
) -> BasicValueEnum<'ctx> {
) -> PointerValue<'ctx> {
let builder = env.builder;
let struct_layout = LayoutRepr::struct_(field_layouts);
let struct_type =
basic_type_from_layout(env, layout_interner, struct_layout).into_struct_type();
let struct_type = match opt_struct_type {
Some(st) => st,
None => {
let struct_layout = LayoutRepr::struct_(field_layouts);
basic_type_from_layout(env, layout_interner, struct_layout).into_struct_type()
}
};
let data_ptr = env.builder.build_pointer_cast(
value,
@ -2074,27 +2183,40 @@ fn lookup_at_index_ptr2<'a, 'ctx>(
"cast_lookup_at_index_ptr",
);
let elem_ptr = builder
builder
.new_build_struct_gep(
struct_type,
data_ptr,
index as u32,
"at_index_struct_gep_data",
)
.unwrap();
.unwrap()
}
let field_layout = field_layouts[index];
let result = load_roc_value(
fn union_field_at_index<'a, 'ctx>(
env: &Env<'a, 'ctx, '_>,
layout_interner: &STLayoutInterner<'a>,
field_layouts: &'a [InLayout<'a>],
opt_struct_type: Option<StructType<'ctx>>,
index: usize,
value: PointerValue<'ctx>,
target_loaded_type: BasicTypeEnum<'ctx>,
) -> PointerValue<'ctx> {
let result = union_field_at_index_help(
env,
layout_interner,
layout_interner.get_repr(field_layout),
elem_ptr,
"load_at_index_ptr",
field_layouts,
opt_struct_type,
index,
value,
);
// A recursive pointer in the loaded structure is stored as a `i64*`, but the loaded layout
// might want a more precise structure. As such, cast it to the refined type if needed.
cast_if_necessary_for_opaque_recursive_pointers(env.builder, result, target_loaded_type)
let from_value: BasicValueEnum = result.into();
let to_type: BasicTypeEnum = target_loaded_type;
cast_if_necessary_for_opaque_recursive_pointers(env.builder, from_value, to_type)
.into_pointer_value()
}
pub fn reserve_with_refcount<'a, 'ctx>(
@ -3071,7 +3193,7 @@ pub fn cast_if_necessary_for_opaque_recursive_pointers<'ctx>(
to_type: BasicTypeEnum<'ctx>,
) -> BasicValueEnum<'ctx> {
if from_value.get_type() != to_type
// Only perform the cast if the target types are transumatble.
// Only perform the cast if the target types are transmutable.
&& equivalent_type_constructors(&from_value.get_type(), &to_type)
{
complex_bitcast(

View file

@ -1304,8 +1304,28 @@ pub(crate) fn run_low_level<'a, 'ctx>(
.into()
}
PtrStore | PtrLoad | PtrToZeroed | RefCountIncRcPtr | RefCountDecRcPtr
| RefCountIncDataPtr | RefCountDecDataPtr => {
PtrStore => {
arguments!(ptr, value);
env.builder.build_store(ptr.into_pointer_value(), value);
// ptr
env.context.struct_type(&[], false).const_zero().into()
}
PtrLoad => {
arguments!(ptr);
let ret_repr = layout_interner.get_repr(layout);
let element_type = basic_type_from_layout(env, layout_interner, ret_repr);
env.builder
.new_build_load(element_type, ptr.into_pointer_value(), "ptr_load")
}
PtrToZeroed => todo!(),
RefCountIncRcPtr | RefCountDecRcPtr | RefCountIncDataPtr | RefCountDecDataPtr => {
unreachable!("Not used in LLVM backend: {:?}", op);
}