mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-22 00:09:33 +03:00
rework how tags are created
This commit is contained in:
parent
269d31b9ae
commit
84c6e741fe
@ -1012,7 +1012,7 @@ fn struct_pointer_from_fields<'a, 'ctx, 'env, I>(
|
||||
input_pointer: PointerValue<'ctx>,
|
||||
values: I,
|
||||
) where
|
||||
I: Iterator<Item = (usize, BasicValueEnum<'ctx>)>,
|
||||
I: Iterator<Item = (usize, (Layout<'a>, BasicValueEnum<'ctx>))>,
|
||||
{
|
||||
let struct_ptr = env
|
||||
.builder
|
||||
@ -1024,13 +1024,13 @@ fn struct_pointer_from_fields<'a, 'ctx, 'env, I>(
|
||||
.into_pointer_value();
|
||||
|
||||
// Insert field exprs into struct_val
|
||||
for (index, field_val) in values {
|
||||
for (index, (field_layout, field_value)) in values {
|
||||
let field_ptr = env
|
||||
.builder
|
||||
.build_struct_gep(struct_ptr, index as u32, "field_struct_gep")
|
||||
.unwrap();
|
||||
|
||||
env.builder.build_store(field_ptr, field_val);
|
||||
store_roc_value(env, field_layout, field_ptr, field_value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1405,53 +1405,11 @@ fn build_wrapped_tag<'a, 'ctx, 'env>(
|
||||
reuse_allocation: Option<PointerValue<'ctx>>,
|
||||
parent: FunctionValue<'ctx>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let ctx = env.context;
|
||||
let builder = env.builder;
|
||||
|
||||
let tag_id_layout = union_layout.tag_id_layout();
|
||||
|
||||
// Determine types
|
||||
let num_fields = arguments.len() + 1;
|
||||
let mut field_types = Vec::with_capacity_in(num_fields, env.arena);
|
||||
let mut field_vals = Vec::with_capacity_in(num_fields, env.arena);
|
||||
|
||||
for (field_symbol, tag_field_layout) in arguments.iter().zip(tag_field_layouts.iter()) {
|
||||
let (val, _val_layout) = load_symbol_and_layout(scope, field_symbol);
|
||||
|
||||
let field_type = basic_type_from_layout(env, tag_field_layout);
|
||||
|
||||
field_types.push(field_type);
|
||||
|
||||
if let Layout::RecursivePointer = tag_field_layout {
|
||||
debug_assert!(val.is_pointer_value());
|
||||
|
||||
// we store recursive pointers as `i64*`
|
||||
let ptr = env.builder.build_bitcast(
|
||||
val,
|
||||
ctx.i64_type().ptr_type(AddressSpace::Generic),
|
||||
"cast_recursive_pointer",
|
||||
);
|
||||
|
||||
field_vals.push(ptr);
|
||||
} else if matches!(
|
||||
tag_field_layout,
|
||||
Layout::Union(UnionLayout::NonRecursive(_))
|
||||
) {
|
||||
debug_assert!(val.is_pointer_value());
|
||||
|
||||
// We store non-recursive unions without any indirection.
|
||||
let reified = env
|
||||
.builder
|
||||
.build_load(val.into_pointer_value(), "load_non_recursive");
|
||||
|
||||
field_vals.push(reified);
|
||||
} else {
|
||||
// this check fails for recursive tag unions, but can be helpful while debugging
|
||||
// debug_assert_eq!(tag_field_layout, val_layout);
|
||||
|
||||
field_vals.push(val);
|
||||
}
|
||||
}
|
||||
let (field_types, field_values) = build_tag_fields(env, scope, tag_field_layouts, arguments);
|
||||
|
||||
// Create the struct_type
|
||||
let raw_data_ptr = allocate_tag(env, parent, reuse_allocation, union_layout, tags);
|
||||
@ -1475,7 +1433,7 @@ fn build_wrapped_tag<'a, 'ctx, 'env>(
|
||||
env,
|
||||
struct_type,
|
||||
opaque_struct_ptr,
|
||||
field_vals.into_iter().enumerate(),
|
||||
field_values.into_iter().enumerate(),
|
||||
);
|
||||
|
||||
raw_data_ptr.into()
|
||||
@ -1484,7 +1442,7 @@ fn build_wrapped_tag<'a, 'ctx, 'env>(
|
||||
env,
|
||||
struct_type,
|
||||
raw_data_ptr,
|
||||
field_vals.into_iter().enumerate(),
|
||||
field_values.into_iter().enumerate(),
|
||||
);
|
||||
|
||||
tag_pointer_set_tag_id(env, tag_id, raw_data_ptr).into()
|
||||
@ -1527,7 +1485,63 @@ pub fn entry_block_alloca_zerofill<'a, 'ctx, 'env>(
|
||||
result_alloca
|
||||
}
|
||||
|
||||
pub fn build_tag<'a, 'ctx, 'env>(
|
||||
fn build_tag_field_value<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
value: BasicValueEnum<'ctx>,
|
||||
tag_field_layout: Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
if let Layout::RecursivePointer = tag_field_layout {
|
||||
debug_assert!(value.is_pointer_value());
|
||||
|
||||
// we store recursive pointers as `i64*`
|
||||
env.builder.build_bitcast(
|
||||
value,
|
||||
env.context.i64_type().ptr_type(AddressSpace::Generic),
|
||||
"cast_recursive_pointer",
|
||||
)
|
||||
} else if tag_field_layout.is_passed_by_reference() {
|
||||
debug_assert!(value.is_pointer_value());
|
||||
|
||||
// NOTE: we rely on this being passed to `store_roc_value` so that
|
||||
// the value is memcpy'd
|
||||
value
|
||||
} else {
|
||||
// this check fails for recursive tag unions, but can be helpful while debugging
|
||||
// debug_assert_eq!(tag_field_layout, val_layout);
|
||||
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
fn build_tag_fields<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
scope: &Scope<'a, 'ctx>,
|
||||
fields: &[Layout<'a>],
|
||||
arguments: &[Symbol],
|
||||
) -> (
|
||||
Vec<'a, BasicTypeEnum<'ctx>>,
|
||||
Vec<'a, (Layout<'a>, BasicValueEnum<'ctx>)>,
|
||||
) {
|
||||
debug_assert_eq!(fields.len(), arguments.len());
|
||||
|
||||
let capacity = fields.len();
|
||||
let mut field_types = Vec::with_capacity_in(capacity, env.arena);
|
||||
let mut field_values = Vec::with_capacity_in(capacity, env.arena);
|
||||
|
||||
for (field_symbol, tag_field_layout) in arguments.iter().zip(fields.iter()) {
|
||||
let field_type = basic_type_from_layout(env, tag_field_layout);
|
||||
field_types.push(field_type);
|
||||
|
||||
let raw_value = load_symbol(scope, field_symbol);
|
||||
let field_value = build_tag_field_value(env, raw_value, *tag_field_layout);
|
||||
|
||||
field_values.push((*tag_field_layout, field_value));
|
||||
}
|
||||
|
||||
(field_types, field_values)
|
||||
}
|
||||
|
||||
fn build_tag<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
scope: &Scope<'a, 'ctx>,
|
||||
union_layout: &UnionLayout<'a>,
|
||||
@ -1678,49 +1692,21 @@ pub fn build_tag<'a, 'ctx, 'env>(
|
||||
debug_assert_eq!(tag_id, 0);
|
||||
debug_assert_eq!(arguments.len(), fields.len());
|
||||
|
||||
let ctx = env.context;
|
||||
|
||||
// Determine types
|
||||
let num_fields = arguments.len() + 1;
|
||||
let mut field_types = Vec::with_capacity_in(num_fields, env.arena);
|
||||
let mut field_vals = Vec::with_capacity_in(num_fields, env.arena);
|
||||
|
||||
for (field_symbol, tag_field_layout) in arguments.iter().zip(fields.iter()) {
|
||||
let val = load_symbol(scope, field_symbol);
|
||||
|
||||
let field_type = basic_type_from_layout(env, tag_field_layout);
|
||||
|
||||
field_types.push(field_type);
|
||||
|
||||
if let Layout::RecursivePointer = tag_field_layout {
|
||||
debug_assert!(val.is_pointer_value());
|
||||
|
||||
// we store recursive pointers as `i64*`
|
||||
let ptr = env.builder.build_bitcast(
|
||||
val,
|
||||
ctx.i64_type().ptr_type(AddressSpace::Generic),
|
||||
"cast_recursive_pointer",
|
||||
);
|
||||
|
||||
field_vals.push(ptr);
|
||||
} else {
|
||||
// this check fails for recursive tag unions, but can be helpful while debugging
|
||||
|
||||
field_vals.push(val);
|
||||
}
|
||||
}
|
||||
let (field_types, field_values) = build_tag_fields(env, scope, fields, arguments);
|
||||
|
||||
// Create the struct_type
|
||||
let data_ptr =
|
||||
reserve_with_refcount_union_as_block_of_memory(env, *union_layout, &[fields]);
|
||||
|
||||
let struct_type = ctx.struct_type(field_types.into_bump_slice(), false);
|
||||
let struct_type = env
|
||||
.context
|
||||
.struct_type(field_types.into_bump_slice(), false);
|
||||
|
||||
struct_pointer_from_fields(
|
||||
env,
|
||||
struct_type,
|
||||
data_ptr,
|
||||
field_vals.into_iter().enumerate(),
|
||||
field_values.into_iter().enumerate(),
|
||||
);
|
||||
|
||||
data_ptr.into()
|
||||
@ -1744,56 +1730,22 @@ pub fn build_tag<'a, 'ctx, 'env>(
|
||||
|
||||
debug_assert!(union_size == 2);
|
||||
|
||||
let ctx = env.context;
|
||||
|
||||
// Determine types
|
||||
let num_fields = arguments.len() + 1;
|
||||
let mut field_types = Vec::with_capacity_in(num_fields, env.arena);
|
||||
let mut field_vals = Vec::with_capacity_in(num_fields, env.arena);
|
||||
|
||||
debug_assert_eq!(arguments.len(), other_fields.len());
|
||||
|
||||
for (field_symbol, tag_field_layout) in arguments.iter().zip(other_fields.iter()) {
|
||||
let val = load_symbol(scope, field_symbol);
|
||||
|
||||
// Zero-sized fields have no runtime representation.
|
||||
// The layout of the struct expects them to be dropped!
|
||||
if !tag_field_layout.is_dropped_because_empty() {
|
||||
let field_type = basic_type_from_layout(env, tag_field_layout);
|
||||
|
||||
field_types.push(field_type);
|
||||
|
||||
if let Layout::RecursivePointer = tag_field_layout {
|
||||
debug_assert!(val.is_pointer_value());
|
||||
|
||||
// we store recursive pointers as `i64*`
|
||||
let ptr = env.builder.build_bitcast(
|
||||
val,
|
||||
ctx.i64_type().ptr_type(AddressSpace::Generic),
|
||||
"cast_recursive_pointer",
|
||||
);
|
||||
|
||||
field_vals.push(ptr);
|
||||
} else {
|
||||
// this check fails for recursive tag unions, but can be helpful while debugging
|
||||
// debug_assert_eq!(tag_field_layout, val_layout);
|
||||
|
||||
field_vals.push(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
let (field_types, field_values) = build_tag_fields(env, scope, other_fields, arguments);
|
||||
|
||||
// Create the struct_type
|
||||
let data_ptr =
|
||||
allocate_tag(env, parent, reuse_allocation, union_layout, &[other_fields]);
|
||||
|
||||
let struct_type = ctx.struct_type(field_types.into_bump_slice(), false);
|
||||
let struct_type = env
|
||||
.context
|
||||
.struct_type(field_types.into_bump_slice(), false);
|
||||
|
||||
struct_pointer_from_fields(
|
||||
env,
|
||||
struct_type,
|
||||
data_ptr,
|
||||
field_vals.into_iter().enumerate(),
|
||||
field_values.into_iter().enumerate(),
|
||||
);
|
||||
|
||||
data_ptr.into()
|
||||
@ -2491,6 +2443,8 @@ pub fn store_roc_value<'a, 'ctx, 'env>(
|
||||
value: BasicValueEnum<'ctx>,
|
||||
) {
|
||||
if layout.is_passed_by_reference() {
|
||||
debug_assert!(value.is_pointer_value());
|
||||
|
||||
let align_bytes = layout.alignment_bytes(env.target_info);
|
||||
|
||||
if align_bytes > 0 {
|
||||
|
Loading…
Reference in New Issue
Block a user