diff --git a/compiler/gen_llvm/src/llvm/bitcode.rs b/compiler/gen_llvm/src/llvm/bitcode.rs index 6dfb4ab929..a2c9f5f079 100644 --- a/compiler/gen_llvm/src/llvm/bitcode.rs +++ b/compiler/gen_llvm/src/llvm/bitcode.rs @@ -1,6 +1,6 @@ /// Helpers for interacting with the zig that generates bitcode use crate::debug_info_init; -use crate::llvm::build::{struct_from_fields, Env, C_CALL_CONV, FAST_CALL_CONV}; +use crate::llvm::build::{struct_from_fields, Env, C_CALL_CONV, FAST_CALL_CONV, TAG_DATA_INDEX}; use crate::llvm::convert::basic_type_from_layout; use crate::llvm::refcounting::{ decrement_refcount_layout, increment_n_refcount_layout, increment_refcount_layout, @@ -155,7 +155,23 @@ fn build_has_tag_id_help<'a, 'ctx, 'env>( "compare", ); - let field_vals = [(0, answer.into()), (1, *tag_value_ptr)]; + let tag_data_ptr = { + let data_index = env + .context + .i64_type() + .const_int(TAG_DATA_INDEX as u64, false); + + let ptr = unsafe { + env.builder.build_gep( + tag_value_ptr.into_pointer_value(), + &[data_index], + "get_data_ptr", + ) + }; + env.builder.build_bitcast(ptr, i8_ptr_type, "to_opaque") + }; + + let field_vals = [(0, answer.into()), (1, tag_data_ptr)]; let output = struct_from_fields(env, output_type, field_vals.iter().copied()); diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index adee398ef8..853bd7daf3 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -19,8 +19,8 @@ use crate::llvm::build_str::{ }; use crate::llvm::compare::{generic_eq, generic_neq}; use crate::llvm::convert::{ - basic_type_from_builtin, basic_type_from_layout, basic_type_from_layout_old, block_of_memory, - block_of_memory_slices, ptr_int, + basic_type_from_builtin, basic_type_from_layout, block_of_memory, block_of_memory_slices, + ptr_int, }; use crate::llvm::refcounting::{ decrement_refcount_layout, increment_refcount_layout, PointerToRefcount, @@ -946,7 +946,6 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( Struct(sorted_fields) => { let ctx = env.context; - let builder = env.builder; // Determine types let num_fields = sorted_fields.len(); @@ -1068,8 +1067,6 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( tag_id, .. } => { - let tag_layout = Layout::Union(UnionLayout::NonRecursive(fields)); - debug_assert!(*union_size > 1); let ctx = env.context; @@ -1113,7 +1110,22 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( } // Create the struct_type - let data_ptr = reserve_with_refcount(env, &tag_layout); + let basic_type = block_of_memory_slices(env.context, fields, env.ptr_bytes); + + let stack_size = fields + .iter() + .map(|tag| tag.iter().map(|l| l.stack_size(env.ptr_bytes)).sum()) + .max() + .unwrap_or(0); + + let alignment_bytes = fields + .iter() + .map(|tag| tag.iter().map(|l| l.alignment_bytes(env.ptr_bytes))) + .flatten() + .max() + .unwrap_or(0); + + let data_ptr = reserve_with_refcount_help(env, basic_type, stack_size, alignment_bytes); let struct_type = ctx.struct_type(field_types.into_bump_slice(), false); let struct_ptr = env .builder @@ -1147,9 +1159,6 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( debug_assert_eq!(*tag_id, 0); debug_assert_eq!(arguments.len(), fields.len()); - let struct_layout = - Layout::Union(UnionLayout::NonRecursive(env.arena.alloc([*fields]))); - let ctx = env.context; let builder = env.builder; @@ -1188,7 +1197,14 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( } // Create the struct_type - let data_ptr = reserve_with_refcount(env, &struct_layout); + let basic_type = block_of_memory_slices(env.context, &[*fields], env.ptr_bytes); + + // layout we abuse to get the right stack size and alignment + let false_layout = Layout::Struct(fields); + let stack_size = false_layout.stack_size(env.ptr_bytes); + let alignment_bytes = false_layout.alignment_bytes(env.ptr_bytes); + let data_ptr = reserve_with_refcount_help(env, basic_type, stack_size, alignment_bytes); + let struct_type = ctx.struct_type(field_types.into_bump_slice(), false); let struct_ptr = env .builder @@ -1222,8 +1238,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( tag_id, .. } => { - let tag_layout = Layout::Union(UnionLayout::NonRecursive(fields)); - let tag_struct_type = basic_type_from_layout(env, &tag_layout); + let tag_struct_type = block_of_memory_slices(env.context, fields, env.ptr_bytes); if *tag_id == *nullable_id as u8 { let output_type = tag_struct_type.ptr_type(AddressSpace::Generic); @@ -1280,7 +1295,22 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( } // Create the struct_type - let data_ptr = reserve_with_refcount(env, &tag_layout); + let basic_type = block_of_memory_slices(env.context, fields, env.ptr_bytes); + + let stack_size = fields + .iter() + .map(|tag| tag.iter().map(|l| l.stack_size(env.ptr_bytes)).sum()) + .max() + .unwrap_or(0); + + let alignment_bytes = fields + .iter() + .map(|tag| tag.iter().map(|l| l.alignment_bytes(env.ptr_bytes))) + .flatten() + .max() + .unwrap_or(0); + + let data_ptr = reserve_with_refcount_help(env, basic_type, stack_size, alignment_bytes); let struct_type = ctx.struct_type(field_types.into_bump_slice(), false); let struct_ptr = env .builder @@ -1379,10 +1409,11 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( } // Create the struct_type - let data_ptr = reserve_with_refcount( - env, - &Layout::Union(UnionLayout::NonRecursive(&[other_fields])), - ); + let basic_type = block_of_memory_slices(env.context, &[other_fields], env.ptr_bytes); + let false_layout = Layout::Struct(other_fields); + let stack_size = false_layout.stack_size(env.ptr_bytes); + let alignment_bytes = false_layout.alignment_bytes(env.ptr_bytes); + let data_ptr = reserve_with_refcount_help(env, basic_type, stack_size, alignment_bytes); let struct_type = ctx.struct_type(field_types.into_bump_slice(), false); let struct_ptr = env @@ -1714,17 +1745,30 @@ fn lookup_at_index_ptr<'a, 'ctx, 'env>( pub fn reserve_with_refcount<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, layout: &Layout<'a>, +) -> PointerValue<'ctx> { + let stack_size = layout.stack_size(env.ptr_bytes); + let alignment_bytes = layout.alignment_bytes(env.ptr_bytes); + + let basic_type = basic_type_from_layout(env, layout); + + reserve_with_refcount_help(env, basic_type, stack_size, alignment_bytes) +} + +fn reserve_with_refcount_help<'a, 'ctx, 'env>( + env: &Env<'a, 'ctx, 'env>, + basic_type: impl BasicType<'ctx>, + stack_size: u32, + alignment_bytes: u32, ) -> PointerValue<'ctx> { let ctx = env.context; let len_type = env.ptr_int(); - let value_bytes = layout.stack_size(env.ptr_bytes); - let value_bytes_intvalue = len_type.const_int(value_bytes as u64, false); + let value_bytes_intvalue = len_type.const_int(stack_size as u64, false); let rc1 = crate::llvm::refcounting::refcount_1(ctx, env.ptr_bytes); - allocate_with_refcount_help(env, layout, value_bytes_intvalue, rc1) + allocate_with_refcount_help(env, basic_type, alignment_bytes, value_bytes_intvalue, rc1) } pub fn allocate_with_refcount<'a, 'ctx, 'env>( @@ -1742,17 +1786,17 @@ pub fn allocate_with_refcount<'a, 'ctx, 'env>( pub fn allocate_with_refcount_help<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, - layout: &Layout<'a>, + value_type: impl BasicType<'ctx>, + alignment_bytes: u32, number_of_data_bytes: IntValue<'ctx>, initial_refcount: IntValue<'ctx>, ) -> PointerValue<'ctx> { let builder = env.builder; let ctx = env.context; - let value_type = basic_type_from_layout_old(env, layout); let len_type = env.ptr_int(); - let extra_bytes = layout.alignment_bytes(env.ptr_bytes).max(env.ptr_bytes); + let extra_bytes = alignment_bytes.max(env.ptr_bytes); let ptr = { // number of bytes we will allocated @@ -1762,7 +1806,7 @@ pub fn allocate_with_refcount_help<'a, 'ctx, 'env>( "add_extra_bytes", ); - env.call_alloc(number_of_bytes, layout.alignment_bytes(env.ptr_bytes)) + env.call_alloc(number_of_bytes, alignment_bytes) }; // We must return a pointer to the first element: @@ -2640,6 +2684,13 @@ fn build_switch_ir<'a, 'ctx, 'env>( Layout::Union(variant) => { cond_layout = Layout::Builtin(Builtin::Int64); + /* + cond_layout = match variant { + UnionLayout::NonRecursive(_) => Layout::Builtin(Builtin::Int16), + _ => Layout::Builtin(Builtin::Int64), + }; + */ + extract_tag_discriminant(env, parent, variant, cond_value) } Layout::Builtin(_) => cond_value.into_int_value(), diff --git a/compiler/gen_llvm/src/llvm/build_list.rs b/compiler/gen_llvm/src/llvm/build_list.rs index f3e1dcc465..d1209a4937 100644 --- a/compiler/gen_llvm/src/llvm/build_list.rs +++ b/compiler/gen_llvm/src/llvm/build_list.rs @@ -741,7 +741,6 @@ pub fn list_map<'a, 'ctx, 'env>( element_layout: &Layout<'a>, return_layout: &Layout<'a>, ) -> BasicValueEnum<'ctx> { - dbg!(return_layout, layout_width(env, return_layout)); call_bitcode_fn_returns_list( env, &[ @@ -1114,7 +1113,9 @@ pub fn allocate_list<'a, 'ctx, 'env>( // we assume that the list is indeed used (dead variables are eliminated) let rc1 = crate::llvm::refcounting::refcount_1(ctx, env.ptr_bytes); - allocate_with_refcount_help(env, elem_layout, number_of_data_bytes, rc1) + let basic_type = basic_type_from_layout(env, elem_layout); + let alignment_bytes = elem_layout.alignment_bytes(env.ptr_bytes); + allocate_with_refcount_help(env, basic_type, alignment_bytes, number_of_data_bytes, rc1) } pub fn store_list<'a, 'ctx, 'env>( diff --git a/compiler/gen_llvm/src/llvm/convert.rs b/compiler/gen_llvm/src/llvm/convert.rs index acc93a9bf8..7665763f67 100644 --- a/compiler/gen_llvm/src/llvm/convert.rs +++ b/compiler/gen_llvm/src/llvm/convert.rs @@ -71,52 +71,6 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>( } } -pub fn basic_type_from_layout_old<'a, 'ctx, 'env>( - env: &crate::llvm::build::Env<'a, 'ctx, 'env>, - layout: &Layout<'_>, -) -> BasicTypeEnum<'ctx> { - use Layout::*; - - match layout { - Closure(_args, closure_layout, _ret_layout) => { - let closure_data_layout = closure_layout.runtime_representation(); - basic_type_from_layout(env, &closure_data_layout) - } - Struct(sorted_fields) => basic_type_from_record(env, sorted_fields), - Union(variant) => { - use UnionLayout::*; - match variant { - Recursive(tags) - | NullableWrapped { - other_tags: tags, .. - } => { - let block = block_of_memory_slices(env.context, tags, env.ptr_bytes); - block.ptr_type(AddressSpace::Generic).into() - } - NullableUnwrapped { other_fields, .. } => { - let block = - block_of_memory_slices(env.context, &[&other_fields[1..]], env.ptr_bytes); - block.ptr_type(AddressSpace::Generic).into() - } - NonNullableUnwrapped(fields) => { - let block = block_of_memory_slices(env.context, &[fields], env.ptr_bytes); - block.ptr_type(AddressSpace::Generic).into() - } - NonRecursive(_) => block_of_memory(env.context, layout, env.ptr_bytes), - } - } - RecursivePointer => { - // TODO make this dynamic - env.context - .i64_type() - .ptr_type(AddressSpace::Generic) - .as_basic_type_enum() - } - - Builtin(builtin) => basic_type_from_builtin(env, builtin), - } -} - pub fn basic_type_from_builtin<'a, 'ctx, 'env>( env: &crate::llvm::build::Env<'a, 'ctx, 'env>, builtin: &Builtin<'_>, diff --git a/compiler/gen_llvm/src/llvm/refcounting.rs b/compiler/gen_llvm/src/llvm/refcounting.rs index 83240e762d..79b029e7e3 100644 --- a/compiler/gen_llvm/src/llvm/refcounting.rs +++ b/compiler/gen_llvm/src/llvm/refcounting.rs @@ -4,9 +4,7 @@ use crate::llvm::build::{ LLVM_SADD_WITH_OVERFLOW_I64, TAG_DATA_INDEX, TAG_ID_INDEX, }; use crate::llvm::build_list::{incrementing_elem_loop, list_len, load_list}; -use crate::llvm::convert::{ - basic_type_from_layout, block_of_memory, block_of_memory_slices, ptr_int, -}; +use crate::llvm::convert::{basic_type_from_layout, block_of_memory_slices, ptr_int}; use bumpalo::collections::Vec; use inkwell::basic_block::BasicBlock; use inkwell::context::Context; diff --git a/compiler/test_gen/src/gen_tags.rs b/compiler/test_gen/src/gen_tags.rs index 03c4abbd05..b75fb4eb42 100644 --- a/compiler/test_gen/src/gen_tags.rs +++ b/compiler/test_gen/src/gen_tags.rs @@ -1007,10 +1007,10 @@ fn applied_tag_function_result() { "# ), RocList::from_slice(&[ - (1, RocStr::from_slice("a".as_bytes())), - (1, RocStr::from_slice("b".as_bytes())) + (RocStr::from_slice("a".as_bytes())), + (RocStr::from_slice("b".as_bytes())) ]), - RocList<(i64, RocStr)> + RocList ); }