mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 00:24:34 +00:00
recursive tag unions
This commit is contained in:
parent
ba186bfe09
commit
f9cf4ea371
8 changed files with 286 additions and 75 deletions
|
@ -107,37 +107,7 @@ pub fn basic_type_from_layout<'ctx>(
|
|||
.struct_type(field_types.into_bump_slice(), false)
|
||||
.as_basic_type_enum()
|
||||
}
|
||||
RecursiveUnion(_) | Union(_) => {
|
||||
// TODO make this dynamic
|
||||
let ptr_size = std::mem::size_of::<i64>();
|
||||
let union_size = layout.stack_size(ptr_size as u32);
|
||||
|
||||
// The memory layout of Union is a bit tricky.
|
||||
// We have tags with different memory layouts, that are part of the same type.
|
||||
// For llvm, all tags must have the same memory layout.
|
||||
//
|
||||
// So, we convert all tags to a layout of bytes of some size.
|
||||
// It turns out that encoding to i64 for as many elements as possible is
|
||||
// a nice optimization, the remainder is encoded as bytes.
|
||||
|
||||
let num_i64 = union_size / 8;
|
||||
let num_i8 = union_size % 8;
|
||||
|
||||
let i64_array_type = context.i64_type().array_type(num_i64).as_basic_type_enum();
|
||||
|
||||
if num_i8 == 0 {
|
||||
// the object fits perfectly in some number of i64's
|
||||
// (i.e. the size is a multiple of 8 bytes)
|
||||
context.struct_type(&[i64_array_type], false).into()
|
||||
} else {
|
||||
// there are some trailing bytes at the end
|
||||
let i8_array_type = context.i8_type().array_type(num_i8).as_basic_type_enum();
|
||||
|
||||
context
|
||||
.struct_type(&[i64_array_type, i8_array_type], false)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
RecursiveUnion(_) | Union(_) => block_of_memory(context, layout, ptr_bytes),
|
||||
RecursivePointer => {
|
||||
// TODO make this dynamic
|
||||
context
|
||||
|
@ -165,6 +135,41 @@ pub fn basic_type_from_layout<'ctx>(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn block_of_memory<'ctx>(
|
||||
context: &'ctx Context,
|
||||
layout: &Layout<'_>,
|
||||
ptr_bytes: u32,
|
||||
) -> BasicTypeEnum<'ctx> {
|
||||
// TODO make this dynamic
|
||||
let union_size = layout.stack_size(ptr_bytes as u32);
|
||||
|
||||
// The memory layout of Union is a bit tricky.
|
||||
// We have tags with different memory layouts, that are part of the same type.
|
||||
// For llvm, all tags must have the same memory layout.
|
||||
//
|
||||
// So, we convert all tags to a layout of bytes of some size.
|
||||
// It turns out that encoding to i64 for as many elements as possible is
|
||||
// a nice optimization, the remainder is encoded as bytes.
|
||||
|
||||
let num_i64 = union_size / 8;
|
||||
let num_i8 = union_size % 8;
|
||||
|
||||
let i64_array_type = context.i64_type().array_type(num_i64).as_basic_type_enum();
|
||||
|
||||
if num_i8 == 0 {
|
||||
// the object fits perfectly in some number of i64's
|
||||
// (i.e. the size is a multiple of 8 bytes)
|
||||
context.struct_type(&[i64_array_type], false).into()
|
||||
} else {
|
||||
// there are some trailing bytes at the end
|
||||
let i8_array_type = context.i8_type().array_type(num_i8).as_basic_type_enum();
|
||||
|
||||
context
|
||||
.struct_type(&[i64_array_type, i8_array_type], false)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
/// Two usize values. Could be a wrapper for a List or a Str.
|
||||
///
|
||||
/// It would be nicer if we could store this as a tuple containing one usize
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue