diff --git a/crates/compiler/gen_llvm/src/llvm/bitcode.rs b/crates/compiler/gen_llvm/src/llvm/bitcode.rs index 71471fee39..e91b029248 100644 --- a/crates/compiler/gen_llvm/src/llvm/bitcode.rs +++ b/crates/compiler/gen_llvm/src/llvm/bitcode.rs @@ -17,7 +17,7 @@ use inkwell::values::{ use inkwell::AddressSpace; use roc_error_macros::internal_error; use roc_module::symbol::Symbol; -use roc_mono::layout::{Builtin, LambdaSet, Layout, LayoutIds}; +use roc_mono::layout::{Builtin, LambdaSet, Layout, LayoutIds, STLayoutInterner}; use super::build::{create_entry_block_alloca, BuilderExt}; use super::convert::zig_list_type; @@ -95,13 +95,14 @@ fn call_bitcode_fn_help<'a, 'ctx, 'env>( pub fn call_bitcode_fn_fixing_for_convention<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, bitcode_return_type: StructType<'ctx>, args: &[BasicValueEnum<'ctx>], - return_layout: &Layout<'_>, + return_layout: &Layout<'a>, fn_name: &str, ) -> BasicValueEnum<'ctx> { // Calling zig bitcode, so we must follow C calling conventions. - let cc_return = to_cc_return(env, return_layout); + let cc_return = to_cc_return(env, layout_interner, return_layout); match cc_return { CCReturn::Return => { // We'll get a return value @@ -109,7 +110,7 @@ pub fn call_bitcode_fn_fixing_for_convention<'a, 'ctx, 'env>( } CCReturn::ByPointer => { // We need to pass the return value by pointer. - let roc_return_type = basic_type_from_layout(env, return_layout); + let roc_return_type = basic_type_from_layout(env, layout_interner, return_layout); let cc_return_type: BasicTypeEnum<'ctx> = bitcode_return_type.into(); @@ -164,6 +165,7 @@ const ARGUMENT_SYMBOLS: [Symbol; 8] = [ pub(crate) fn build_transform_caller<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, function: FunctionValue<'ctx>, closure_data_layout: LambdaSet<'a>, argument_layouts: &[Layout<'a>], @@ -178,6 +180,7 @@ pub(crate) fn build_transform_caller<'a, 'ctx, 'env>( Some(function_value) => function_value, None => build_transform_caller_help( env, + layout_interner, function, closure_data_layout, argument_layouts, @@ -189,6 +192,7 @@ pub(crate) fn build_transform_caller<'a, 'ctx, 'env>( fn build_transform_caller_help<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, roc_function: FunctionValue<'ctx>, closure_data_layout: LambdaSet<'a>, argument_layouts: &[Layout<'a>], @@ -237,7 +241,8 @@ fn build_transform_caller_help<'a, 'ctx, 'env>( bumpalo::collections::Vec::with_capacity_in(arguments.len(), env.arena); for (argument_ptr, layout) in arguments.iter().zip(argument_layouts) { - let basic_type = basic_type_from_layout(env, layout).ptr_type(AddressSpace::Generic); + let basic_type = + basic_type_from_layout(env, layout_interner, layout).ptr_type(AddressSpace::Generic); let cast_ptr = env.builder.build_pointer_cast( argument_ptr.into_pointer_value(), @@ -245,28 +250,36 @@ fn build_transform_caller_help<'a, 'ctx, 'env>( "cast_ptr_to_tag_build_transform_caller_help", ); - let argument = load_roc_value(env, *layout, cast_ptr, "zig_helper_load_opaque"); + let argument = load_roc_value( + env, + layout_interner, + *layout, + cast_ptr, + "zig_helper_load_opaque", + ); arguments_cast.push(argument); } match ( closure_data_layout - .is_represented(env.layout_interner) + .is_represented(layout_interner) .is_some(), - closure_data_layout.runtime_representation(env.layout_interner), + closure_data_layout.runtime_representation(layout_interner), ) { (false, _) => { // the function doesn't expect a closure argument, nothing to add } (true, layout) => { - let closure_type = basic_type_from_layout(env, &layout).ptr_type(AddressSpace::Generic); + let closure_type = basic_type_from_layout(env, layout_interner, &layout) + .ptr_type(AddressSpace::Generic); let closure_cast = env.builder .build_pointer_cast(closure_ptr, closure_type, "cast_opaque_closure"); - let closure_data = load_roc_value(env, layout, closure_cast, "load_closure"); + let closure_data = + load_roc_value(env, layout_interner, layout, closure_cast, "load_closure"); arguments_cast.push(closure_data); } @@ -274,6 +287,7 @@ fn build_transform_caller_help<'a, 'ctx, 'env>( let result = crate::llvm::build::call_roc_function( env, + layout_interner, roc_function, &result_layout, arguments_cast.as_slice(), @@ -284,7 +298,13 @@ fn build_transform_caller_help<'a, 'ctx, 'env>( .unwrap() .into_pointer_value(); - crate::llvm::build::store_roc_value_opaque(env, result_layout, result_u8_ptr, result); + crate::llvm::build::store_roc_value_opaque( + env, + layout_interner, + result_layout, + result_u8_ptr, + result, + ); env.builder.build_return(None); env.builder.position_at_end(block); @@ -303,31 +323,35 @@ enum Mode { /// a function that accepts two arguments: the value to increment, and an amount to increment by pub fn build_inc_n_wrapper<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, layout: &Layout<'a>, ) -> FunctionValue<'ctx> { - build_rc_wrapper(env, layout_ids, layout, Mode::IncN) + build_rc_wrapper(env, layout_interner, layout_ids, layout, Mode::IncN) } /// a function that accepts two arguments: the value to increment; increments by 1 pub fn build_inc_wrapper<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, layout: &Layout<'a>, ) -> FunctionValue<'ctx> { - build_rc_wrapper(env, layout_ids, layout, Mode::Inc) + build_rc_wrapper(env, layout_interner, layout_ids, layout, Mode::Inc) } pub fn build_dec_wrapper<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, layout: &Layout<'a>, ) -> FunctionValue<'ctx> { - build_rc_wrapper(env, layout_ids, layout, Mode::Dec) + build_rc_wrapper(env, layout_interner, layout_ids, layout, Mode::Dec) } fn build_rc_wrapper<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, layout: &Layout<'a>, rc_operation: Mode, @@ -384,7 +408,7 @@ fn build_rc_wrapper<'a, 'ctx, 'env>( generic_value_ptr.set_name(Symbol::ARG_1.as_str(&env.interns)); - let value_type = basic_type_from_layout(env, layout); + let value_type = basic_type_from_layout(env, layout_interner, layout); let value_ptr_type = value_type.ptr_type(AddressSpace::Generic); let value_ptr = env.builder @@ -393,7 +417,7 @@ fn build_rc_wrapper<'a, 'ctx, 'env>( // even though this looks like a `load_roc_value`, that gives segfaults in practice. // I suspect it has something to do with the lifetime of the alloca that is created by // `load_roc_value` - let value = if layout.is_passed_by_reference(env.layout_interner, env.target_info) { + let value = if layout.is_passed_by_reference(layout_interner, env.target_info) { value_ptr.into() } else { env.builder @@ -403,16 +427,16 @@ fn build_rc_wrapper<'a, 'ctx, 'env>( match rc_operation { Mode::Inc => { let n = 1; - increment_refcount_layout(env, layout_ids, n, value, layout); + increment_refcount_layout(env, layout_interner, layout_ids, n, value, layout); } Mode::IncN => { let n = it.next().unwrap().into_int_value(); n.set_name(Symbol::ARG_2.as_str(&env.interns)); - increment_n_refcount_layout(env, layout_ids, n, value, layout); + increment_n_refcount_layout(env, layout_interner, layout_ids, n, value, layout); } Mode::Dec => { - decrement_refcount_layout(env, layout_ids, value, layout); + decrement_refcount_layout(env, layout_interner, layout_ids, value, layout); } } @@ -431,6 +455,7 @@ fn build_rc_wrapper<'a, 'ctx, 'env>( pub fn build_eq_wrapper<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, layout: &Layout<'a>, ) -> FunctionValue<'ctx> { @@ -474,7 +499,8 @@ pub fn build_eq_wrapper<'a, 'ctx, 'env>( value_ptr1.set_name(Symbol::ARG_1.as_str(&env.interns)); value_ptr2.set_name(Symbol::ARG_2.as_str(&env.interns)); - let value_type = basic_type_from_layout(env, layout).ptr_type(AddressSpace::Generic); + let value_type = basic_type_from_layout(env, layout_interner, layout) + .ptr_type(AddressSpace::Generic); let value_cast1 = env .builder @@ -485,11 +511,18 @@ pub fn build_eq_wrapper<'a, 'ctx, 'env>( .build_pointer_cast(value_ptr2, value_type, "load_opaque"); // load_roc_value(env, *element_layout, elem_ptr, "get_elem") - let value1 = load_roc_value(env, *layout, value_cast1, "load_opaque"); - let value2 = load_roc_value(env, *layout, value_cast2, "load_opaque"); + let value1 = load_roc_value(env, layout_interner, *layout, value_cast1, "load_opaque"); + let value2 = load_roc_value(env, layout_interner, *layout, value_cast2, "load_opaque"); - let result = - crate::llvm::compare::generic_eq(env, layout_ids, value1, value2, layout, layout); + let result = crate::llvm::compare::generic_eq( + env, + layout_interner, + layout_ids, + value1, + value2, + layout, + layout, + ); env.builder.build_return(Some(&result)); @@ -506,6 +539,7 @@ pub fn build_eq_wrapper<'a, 'ctx, 'env>( pub fn build_compare_wrapper<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, roc_function: FunctionValue<'ctx>, closure_data_layout: LambdaSet<'a>, layout: &Layout<'a>, @@ -555,7 +589,7 @@ pub fn build_compare_wrapper<'a, 'ctx, 'env>( value_ptr1.set_name(Symbol::ARG_2.as_str(&env.interns)); value_ptr2.set_name(Symbol::ARG_3.as_str(&env.interns)); - let value_type = basic_type_from_layout(env, layout); + let value_type = basic_type_from_layout(env, layout_interner, layout); let value_ptr_type = value_type.ptr_type(AddressSpace::Generic); let value_cast1 = @@ -575,33 +609,32 @@ pub fn build_compare_wrapper<'a, 'ctx, 'env>( let default = [value1.into(), value2.into()]; - let arguments_cast = - match closure_data_layout.runtime_representation(env.layout_interner) { - Layout::Struct { - field_layouts: &[], .. - } => { - // nothing to add - &default - } - other => { - let closure_type = basic_type_from_layout(env, &other); - let closure_ptr_type = closure_type.ptr_type(AddressSpace::Generic); + let arguments_cast = match closure_data_layout.runtime_representation(layout_interner) { + Layout::Struct { + field_layouts: &[], .. + } => { + // nothing to add + &default + } + other => { + let closure_type = basic_type_from_layout(env, layout_interner, &other); + let closure_ptr_type = closure_type.ptr_type(AddressSpace::Generic); - let closure_cast = env.builder.build_pointer_cast( - closure_ptr, - closure_ptr_type, - "load_opaque", - ); + let closure_cast = env.builder.build_pointer_cast( + closure_ptr, + closure_ptr_type, + "load_opaque", + ); - let closure_data = - env.builder - .new_build_load(closure_type, closure_cast, "load_opaque"); + let closure_data = + env.builder + .new_build_load(closure_type, closure_cast, "load_opaque"); - env.arena - .alloc([value1.into(), value2.into(), closure_data.into()]) - as &[_] - } - }; + env.arena + .alloc([value1.into(), value2.into(), closure_data.into()]) + as &[_] + } + }; let call = env.builder.build_call( roc_function, diff --git a/crates/compiler/gen_llvm/src/llvm/build.rs b/crates/compiler/gen_llvm/src/llvm/build.rs index fbb55a5f72..f726f1aa2a 100644 --- a/crates/compiler/gen_llvm/src/llvm/build.rs +++ b/crates/compiler/gen_llvm/src/llvm/build.rs @@ -38,6 +38,7 @@ use roc_debug_flags::dbg_do; #[cfg(debug_assertions)] use roc_debug_flags::ROC_PRINT_LLVM_FN_VERIFICATION; use roc_error_macros::internal_error; +use roc_intern::Interner; use roc_module::symbol::{Interns, ModuleId, Symbol}; use roc_mono::ir::{ BranchInfo, CallType, CrashTag, EntryPoint, JoinPointId, ListLiteralElement, ModifyRc, @@ -241,7 +242,6 @@ impl LlvmBackendMode { pub struct Env<'a, 'ctx, 'env> { pub arena: &'a Bump, - pub layout_interner: &'env STLayoutInterner<'a>, pub context: &'ctx Context, pub builder: &'env Builder<'ctx>, pub dibuilder: &'env DebugInfoBuilder<'ctx>, @@ -333,8 +333,12 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> { self.alignment_type().const_int(alignment as u64, false) } - pub fn alignment_intvalue(&self, element_layout: &Layout<'a>) -> BasicValueEnum<'ctx> { - let alignment = element_layout.alignment_bytes(self.layout_interner, self.target_info); + pub fn alignment_intvalue( + &self, + layout_interner: &mut STLayoutInterner<'a>, + element_layout: &Layout<'a>, + ) -> BasicValueEnum<'ctx> { + let alignment = element_layout.alignment_bytes(layout_interner, self.target_info); let alignment_iv = self.alignment_const(alignment); alignment_iv.into() @@ -610,6 +614,7 @@ pub fn construct_optimization_passes<'a>( fn promote_to_main_function<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, mod_solutions: &'a ModSolutions, symbol: Symbol, top_level: ProcLayout<'a>, @@ -646,6 +651,7 @@ fn promote_to_main_function<'a, 'ctx, 'env>( // Add main to the module. let main_fn = expose_function_to_host_help_c_abi( env, + layout_interner, main_fn_name, roc_main_fn, top_level.arguments, @@ -658,6 +664,7 @@ fn promote_to_main_function<'a, 'ctx, 'env>( fn promote_to_wasm_test_wrapper<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, mod_solutions: &'a ModSolutions, symbol: Symbol, top_level: ProcLayout<'a>, @@ -733,18 +740,25 @@ fn promote_to_wasm_test_wrapper<'a, 'ctx, 'env>( let entry = context.append_basic_block(c_function, "entry"); builder.position_at_end(entry); - let roc_main_fn_result = call_roc_function(env, roc_main_fn, &top_level.result, &[]); + let roc_main_fn_result = + call_roc_function(env, layout_interner, roc_main_fn, &top_level.result, &[]); // For consistency, we always return with a heap-allocated value let (size, alignment) = top_level .result - .stack_size_and_alignment(env.layout_interner, env.target_info); + .stack_size_and_alignment(layout_interner, env.target_info); let number_of_bytes = env.ptr_int().const_int(size as _, false); let void_ptr = env.call_alloc(number_of_bytes, alignment); let ptr = builder.build_pointer_cast(void_ptr, output_type.into_pointer_type(), "cast_ptr"); - store_roc_value(env, top_level.result, ptr, roc_main_fn_result); + store_roc_value( + env, + layout_interner, + top_level.result, + ptr, + roc_main_fn_result, + ); builder.build_return(Some(&ptr)); @@ -930,6 +944,7 @@ fn small_str_ptr_width_4<'a, 'ctx, 'env>( pub fn build_exp_call<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, func_spec_solutions: &FuncSpecSolutions, scope: &mut Scope<'a, 'ctx>, @@ -963,6 +978,7 @@ pub fn build_exp_call<'a, 'ctx, 'env>( roc_call_with_args( env, + layout_interner, arg_layouts, ret_layout, *name, @@ -980,6 +996,7 @@ pub fn build_exp_call<'a, 'ctx, 'env>( crate::llvm::lowlevel::run_low_level( env, + layout_interner, layout_ids, scope, parent, @@ -995,13 +1012,28 @@ pub fn build_exp_call<'a, 'ctx, 'env>( let callee_var = CalleeSpecVar(&bytes); let func_spec = func_spec_solutions.callee_spec(callee_var).unwrap(); - run_higher_order_low_level(env, layout_ids, scope, layout, func_spec, higher_order) + run_higher_order_low_level( + env, + layout_interner, + layout_ids, + scope, + layout, + func_spec, + higher_order, + ) } CallType::Foreign { foreign_symbol, ret_layout, - } => build_foreign_symbol(env, scope, foreign_symbol, arguments, ret_layout), + } => build_foreign_symbol( + env, + layout_interner, + scope, + foreign_symbol, + arguments, + ret_layout, + ), } } @@ -1030,6 +1062,7 @@ where fn struct_pointer_from_fields<'a, 'ctx, 'env, I>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, struct_type: StructType<'ctx>, input_pointer: PointerValue<'ctx>, values: I, @@ -1052,12 +1085,13 @@ fn struct_pointer_from_fields<'a, 'ctx, 'env, I>( .new_build_struct_gep(struct_type, struct_ptr, index as u32, "field_struct_gep") .unwrap(); - store_roc_value(env, field_layout, field_ptr, field_value); + store_roc_value(env, layout_interner, field_layout, field_ptr, field_value); } } pub fn build_exp_expr<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, func_spec_solutions: &FuncSpecSolutions, scope: &mut Scope<'a, 'ctx>, @@ -1072,6 +1106,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( Call(call) => build_exp_call( env, + layout_interner, layout_ids, func_spec_solutions, scope, @@ -1080,7 +1115,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( call, ), - Struct(sorted_fields) => build_struct(env, scope, sorted_fields).into(), + Struct(sorted_fields) => build_struct(env, layout_interner, scope, sorted_fields).into(), Reuse { arguments, @@ -1092,6 +1127,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( let reset = load_symbol(scope, symbol).into_pointer_value(); build_tag( env, + layout_interner, scope, union_layout, *tag_id, @@ -1106,19 +1142,28 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( tag_layout: union_layout, tag_id, .. - } => build_tag(env, scope, union_layout, *tag_id, arguments, None, parent), + } => build_tag( + env, + layout_interner, + scope, + union_layout, + *tag_id, + arguments, + None, + parent, + ), ExprBox { symbol } => { let (value, layout) = load_symbol_and_layout(scope, symbol); - let basic_type = basic_type_from_layout(env, layout); + let basic_type = basic_type_from_layout(env, layout_interner, layout); let allocation = reserve_with_refcount_help( env, basic_type, - layout.stack_size(env.layout_interner, env.target_info), - layout.alignment_bytes(env.layout_interner, env.target_info), + layout.stack_size(layout_interner, env.target_info), + layout.alignment_bytes(layout_interner, env.target_info), ); - store_roc_value(env, *layout, allocation, value); + store_roc_value(env, layout_interner, *layout, allocation, value); allocation.into() } @@ -1128,7 +1173,13 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( debug_assert!(value.is_pointer_value()); - load_roc_value(env, *layout, value.into_pointer_value(), "load_boxed_value") + load_roc_value( + env, + layout_interner, + *layout, + value.into_pointer_value(), + "load_boxed_value", + ) } Reset { @@ -1171,7 +1222,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( // referenced value, and returns the location of the now-invalid cell env.builder.position_at_end(then_block); - let reset_function = build_reset(env, layout_ids, *union_layout); + let reset_function = build_reset(env, layout_interner, layout_ids, *union_layout); let call = env .builder .build_call(reset_function, &[tag_ptr.into()], "call_reset"); @@ -1186,7 +1237,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( // If reset is used on a shared, non-reusable reference, it behaves // like dec and returns NULL, which instructs reuse to behave like ctor env.builder.position_at_end(else_block); - refcount_ptr.decrement(env, layout); + refcount_ptr.decrement(env, layout_interner, layout); env.builder.build_unconditional_branch(cont_block); } { @@ -1206,7 +1257,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( let (value, layout) = load_symbol_and_layout(scope, structure); let layout = if let Layout::LambdaSet(lambda_set) = layout { - lambda_set.runtime_representation(env.layout_interner) + lambda_set.runtime_representation(layout_interner) } else { *layout }; @@ -1227,7 +1278,13 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( .unwrap(); let field_layout = field_layouts[*index as usize]; - use_roc_value(env, field_layout, field_value, "struct_field_tag") + use_roc_value( + env, + layout_interner, + field_layout, + field_value, + "struct_field_tag", + ) } (other, layout) => { // potential cause: indexing into an unwrapped 1-element record/tag? @@ -1240,7 +1297,9 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( } EmptyArray => empty_polymorphic_list(env), - Array { elem_layout, elems } => list_literal(env, parent, scope, elem_layout, elems), + Array { elem_layout, elems } => { + list_literal(env, layout_interner, parent, scope, elem_layout, elems) + } RuntimeErrorFunction(_) => todo!(), UnionAtIndex { @@ -1259,12 +1318,13 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( let field_layouts = tag_layouts[*tag_id as usize]; let struct_layout = Layout::struct_no_name_order(field_layouts); - let struct_type = basic_type_from_layout(env, &struct_layout); + let struct_type = basic_type_from_layout(env, layout_interner, &struct_layout); let opaque_data_ptr = env .builder .new_build_struct_gep( - basic_type_from_layout(env, structure_layout).into_struct_type(), + basic_type_from_layout(env, layout_interner, structure_layout) + .into_struct_type(), argument.into_pointer_value(), RocUnion::TAG_DATA_INDEX, "get_opaque_data_ptr", @@ -1289,6 +1349,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( load_roc_value( env, + layout_interner, field_layouts[*index as usize], element_ptr, "load_element", @@ -1301,15 +1362,23 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( let ptr = tag_pointer_clear_tag_id(env, argument.into_pointer_value()); - lookup_at_index_ptr2(env, union_layout, field_layouts, *index as usize, ptr) + lookup_at_index_ptr2( + env, + layout_interner, + union_layout, + field_layouts, + *index as usize, + ptr, + ) } UnionLayout::NonNullableUnwrapped(field_layouts) => { let struct_layout = Layout::struct_no_name_order(field_layouts); - let struct_type = basic_type_from_layout(env, &struct_layout); + let struct_type = basic_type_from_layout(env, layout_interner, &struct_layout); lookup_at_index_ptr( env, + layout_interner, union_layout, field_layouts, *index as usize, @@ -1333,7 +1402,14 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( let field_layouts = other_tags[tag_index as usize]; let ptr = tag_pointer_clear_tag_id(env, argument.into_pointer_value()); - lookup_at_index_ptr2(env, union_layout, field_layouts, *index as usize, ptr) + lookup_at_index_ptr2( + env, + layout_interner, + union_layout, + field_layouts, + *index as usize, + ptr, + ) } UnionLayout::NullableUnwrapped { nullable_id, @@ -1345,10 +1421,11 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( let field_layouts = other_fields; let struct_layout = Layout::struct_no_name_order(field_layouts); - let struct_type = basic_type_from_layout(env, &struct_layout); + let struct_type = basic_type_from_layout(env, layout_interner, &struct_layout); lookup_at_index_ptr( env, + layout_interner, union_layout, field_layouts, // the tag id is not stored @@ -1367,7 +1444,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( // cast the argument bytes into the desired shape for this tag let (argument, _structure_layout) = load_symbol_and_layout(scope, structure); - get_tag_id(env, parent, union_layout, argument).into() + get_tag_id(env, layout_interner, parent, union_layout, argument).into() } } } @@ -1375,6 +1452,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( #[allow(clippy::too_many_arguments)] fn build_wrapped_tag<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, scope: &Scope<'a, 'ctx>, union_layout: &UnionLayout<'a>, tag_id: u8, @@ -1388,12 +1466,20 @@ fn build_wrapped_tag<'a, 'ctx, 'env>( let tag_id_layout = union_layout.tag_id_layout(); - let (field_types, field_values) = build_tag_fields(env, scope, tag_field_layouts, arguments); + let (field_types, field_values) = + build_tag_fields(env, layout_interner, scope, tag_field_layouts, arguments); - let union_struct_type = struct_type_from_union_layout(env, union_layout); + let union_struct_type = struct_type_from_union_layout(env, layout_interner, union_layout); // Create the struct_type - let raw_data_ptr = allocate_tag(env, parent, reuse_allocation, union_layout, tags); + let raw_data_ptr = allocate_tag( + env, + layout_interner, + parent, + reuse_allocation, + union_layout, + tags, + ); let struct_type = env.context.struct_type(&field_types, false); if union_layout.stores_tag_id_as_data(env.target_info) { @@ -1406,7 +1492,8 @@ fn build_wrapped_tag<'a, 'ctx, 'env>( ) .unwrap(); - let tag_id_type = basic_type_from_layout(env, &tag_id_layout).into_int_type(); + let tag_id_type = + basic_type_from_layout(env, layout_interner, &tag_id_layout).into_int_type(); env.builder .build_store(tag_id_ptr, tag_id_type.const_int(tag_id as u64, false)); @@ -1422,6 +1509,7 @@ fn build_wrapped_tag<'a, 'ctx, 'env>( struct_pointer_from_fields( env, + layout_interner, struct_type, opaque_struct_ptr, field_values.into_iter().enumerate(), @@ -1431,6 +1519,7 @@ fn build_wrapped_tag<'a, 'ctx, 'env>( } else { struct_pointer_from_fields( env, + layout_interner, struct_type, raw_data_ptr, field_values.into_iter().enumerate(), @@ -1457,6 +1546,7 @@ pub fn entry_block_alloca_zerofill<'a, 'ctx, 'env>( fn build_tag_field_value<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, value: BasicValueEnum<'ctx>, tag_field_layout: Layout<'a>, ) -> BasicValueEnum<'ctx> { @@ -1471,7 +1561,7 @@ fn build_tag_field_value<'a, 'ctx, 'env>( "cast_recursive_pointer", ) .into() - } else if tag_field_layout.is_passed_by_reference(env.layout_interner, env.target_info) { + } else if tag_field_layout.is_passed_by_reference(layout_interner, env.target_info) { debug_assert!(value.is_pointer_value()); // NOTE: we rely on this being passed to `store_roc_value` so that @@ -1487,6 +1577,7 @@ fn build_tag_field_value<'a, 'ctx, 'env>( fn build_tag_fields<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, scope: &Scope<'a, 'ctx>, fields: &[Layout<'a>], arguments: &[Symbol], @@ -1501,11 +1592,11 @@ fn build_tag_fields<'a, 'ctx, 'env>( 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); + let field_type = basic_type_from_layout(env, layout_interner, 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); + let field_value = build_tag_field_value(env, layout_interner, raw_value, *tag_field_layout); field_values.push((*tag_field_layout, field_value)); } @@ -1515,6 +1606,7 @@ fn build_tag_fields<'a, 'ctx, 'env>( fn build_struct<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, scope: &Scope<'a, 'ctx>, sorted_fields: &[Symbol], ) -> StructValue<'ctx> { @@ -1530,10 +1622,10 @@ fn build_struct<'a, 'ctx, 'env>( // The layout of the struct expects them to be dropped! let (field_expr, field_layout) = load_symbol_and_layout(scope, symbol); if !field_layout.is_dropped_because_empty() { - let field_type = basic_type_from_layout(env, field_layout); + let field_type = basic_type_from_layout(env, layout_interner, field_layout); field_types.push(field_type); - if field_layout.is_passed_by_reference(env.layout_interner, env.target_info) { + if field_layout.is_passed_by_reference(layout_interner, env.target_info) { let field_value = env.builder.new_build_load( field_type, field_expr.into_pointer_value(), @@ -1556,6 +1648,7 @@ fn build_struct<'a, 'ctx, 'env>( fn build_tag<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, scope: &Scope<'a, 'ctx>, union_layout: &UnionLayout<'a>, tag_id: TagIdIntType, @@ -1569,14 +1662,10 @@ fn build_tag<'a, 'ctx, 'env>( UnionLayout::NonRecursive(tags) => { debug_assert!(union_size > 1); - let data = build_struct(env, scope, arguments); + let data = build_struct(env, layout_interner, scope, arguments); - let roc_union = RocUnion::tagged_from_slices( - env.layout_interner, - env.context, - tags, - env.target_info, - ); + let roc_union = + RocUnion::tagged_from_slices(layout_interner, env.context, tags, env.target_info); let value = roc_union.as_struct_value(env, data, Some(tag_id as _)); let alloca = create_entry_block_alloca( @@ -1597,6 +1686,7 @@ fn build_tag<'a, 'ctx, 'env>( build_wrapped_tag( env, + layout_interner, scope, union_layout, tag_id as _, @@ -1617,7 +1707,7 @@ fn build_tag<'a, 'ctx, 'env>( Equal => { let layout = Layout::Union(*union_layout); - return basic_type_from_layout(env, &layout) + return basic_type_from_layout(env, layout_interner, &layout) .into_pointer_type() .const_null() .into(); @@ -1629,6 +1719,7 @@ fn build_tag<'a, 'ctx, 'env>( build_wrapped_tag( env, + layout_interner, scope, union_layout, tag_id as _, @@ -1644,11 +1735,16 @@ fn build_tag<'a, 'ctx, 'env>( debug_assert_eq!(tag_id, 0); debug_assert_eq!(arguments.len(), fields.len()); - let (field_types, field_values) = build_tag_fields(env, scope, fields, arguments); + let (field_types, field_values) = + build_tag_fields(env, layout_interner, scope, fields, arguments); // Create the struct_type - let data_ptr = - reserve_with_refcount_union_as_block_of_memory(env, *union_layout, &[fields]); + let data_ptr = reserve_with_refcount_union_as_block_of_memory( + env, + layout_interner, + *union_layout, + &[fields], + ); let struct_type = env .context @@ -1656,6 +1752,7 @@ fn build_tag<'a, 'ctx, 'env>( struct_pointer_from_fields( env, + layout_interner, struct_type, data_ptr, field_values.into_iter().enumerate(), @@ -1668,7 +1765,7 @@ fn build_tag<'a, 'ctx, 'env>( other_fields, } => { let roc_union = RocUnion::untagged_from_slices( - env.layout_interner, + layout_interner, env.context, &[other_fields], env.target_info, @@ -1687,10 +1784,16 @@ fn build_tag<'a, 'ctx, 'env>( debug_assert!(union_size == 2); // Create the struct_type - let data_ptr = - allocate_tag(env, parent, reuse_allocation, union_layout, &[other_fields]); + let data_ptr = allocate_tag( + env, + layout_interner, + parent, + reuse_allocation, + union_layout, + &[other_fields], + ); - let data = build_struct(env, scope, arguments); + let data = build_struct(env, layout_interner, scope, arguments); let value = roc_union.as_struct_value(env, data, None); @@ -1767,6 +1870,7 @@ pub fn tag_pointer_clear_tag_id<'a, 'ctx, 'env>( fn allocate_tag<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, parent: FunctionValue<'ctx>, reuse_allocation: Option>, union_layout: &UnionLayout<'a>, @@ -1786,8 +1890,12 @@ fn allocate_tag<'a, 'ctx, 'env>( let raw_ptr = { env.builder.position_at_end(then_block); - let raw_ptr = - reserve_with_refcount_union_as_block_of_memory(env, *union_layout, tags); + let raw_ptr = reserve_with_refcount_union_as_block_of_memory( + env, + layout_interner, + *union_layout, + tags, + ); env.builder.build_unconditional_branch(cont_block); raw_ptr }; @@ -1811,12 +1919,18 @@ fn allocate_tag<'a, 'ctx, 'env>( phi.as_basic_value().into_pointer_value() } } - None => reserve_with_refcount_union_as_block_of_memory(env, *union_layout, tags), + None => reserve_with_refcount_union_as_block_of_memory( + env, + layout_interner, + *union_layout, + tags, + ), } } pub fn get_tag_id<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, parent: FunctionValue<'ctx>, union_layout: &UnionLayout<'a>, argument: BasicValueEnum<'ctx>, @@ -1824,20 +1938,21 @@ pub fn get_tag_id<'a, 'ctx, 'env>( let builder = env.builder; let tag_id_layout = union_layout.tag_id_layout(); - let tag_id_int_type = basic_type_from_layout(env, &tag_id_layout).into_int_type(); + let tag_id_int_type = + basic_type_from_layout(env, layout_interner, &tag_id_layout).into_int_type(); match union_layout { UnionLayout::NonRecursive(_) => { debug_assert!(argument.is_pointer_value(), "{:?}", argument); let argument_ptr = argument.into_pointer_value(); - get_tag_id_wrapped(env, *union_layout, argument_ptr) + get_tag_id_wrapped(env, layout_interner, *union_layout, argument_ptr) } UnionLayout::Recursive(_) => { let argument_ptr = argument.into_pointer_value(); if union_layout.stores_tag_id_as_data(env.target_info) { - get_tag_id_wrapped(env, *union_layout, argument_ptr) + get_tag_id_wrapped(env, layout_interner, *union_layout, argument_ptr) } else { tag_pointer_read_tag_id(env, argument_ptr) } @@ -1868,7 +1983,7 @@ pub fn get_tag_id<'a, 'ctx, 'env>( env.builder.position_at_end(else_block); let tag_id = if union_layout.stores_tag_id_as_data(env.target_info) { - get_tag_id_wrapped(env, *union_layout, argument_ptr) + get_tag_id_wrapped(env, layout_interner, *union_layout, argument_ptr) } else { tag_pointer_read_tag_id(env, argument_ptr) }; @@ -1898,8 +2013,9 @@ pub fn get_tag_id<'a, 'ctx, 'env>( fn lookup_at_index_ptr<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, union_layout: &UnionLayout<'a>, - field_layouts: &[Layout<'_>], + field_layouts: &[Layout<'a>], index: usize, value: PointerValue<'ctx>, struct_type: StructType<'ctx>, @@ -1917,12 +2033,19 @@ fn lookup_at_index_ptr<'a, 'ctx, 'env>( .unwrap(); let field_layout = field_layouts[index]; - let result = load_roc_value(env, field_layout, elem_ptr, "load_at_index_ptr_old"); + let result = load_roc_value( + env, + layout_interner, + field_layout, + elem_ptr, + "load_at_index_ptr_old", + ); if let Some(Layout::RecursivePointer) = field_layouts.get(index as usize) { // a recursive field is stored as a `i64*`, to use it we must cast it to // a pointer to the block of memory representation - let actual_type = basic_type_from_layout(env, &Layout::Union(*union_layout)); + let actual_type = + basic_type_from_layout(env, layout_interner, &Layout::Union(*union_layout)); debug_assert!(actual_type.is_pointer_type()); builder @@ -1939,15 +2062,17 @@ fn lookup_at_index_ptr<'a, 'ctx, 'env>( fn lookup_at_index_ptr2<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, union_layout: &UnionLayout<'a>, - field_layouts: &[Layout<'_>], + field_layouts: &[Layout<'a>], index: usize, value: PointerValue<'ctx>, ) -> BasicValueEnum<'ctx> { let builder = env.builder; let struct_layout = Layout::struct_no_name_order(field_layouts); - let struct_type = basic_type_from_layout(env, &struct_layout).into_struct_type(); + let struct_type = + basic_type_from_layout(env, layout_interner, &struct_layout).into_struct_type(); let data_ptr = env.builder.build_pointer_cast( value, @@ -1965,13 +2090,20 @@ fn lookup_at_index_ptr2<'a, 'ctx, 'env>( .unwrap(); let field_layout = field_layouts[index]; - let result = load_roc_value(env, field_layout, elem_ptr, "load_at_index_ptr"); + let result = load_roc_value( + env, + layout_interner, + field_layout, + elem_ptr, + "load_at_index_ptr", + ); if let Some(Layout::RecursivePointer) = field_layouts.get(index as usize) { // a recursive field is stored as a `i64*`, to use it we must cast it to // a pointer to the block of memory representation - let actual_type = basic_type_from_layout(env, &Layout::Union(*union_layout)); + let actual_type = + basic_type_from_layout(env, layout_interner, &Layout::Union(*union_layout)); debug_assert!(actual_type.is_pointer_type()); builder @@ -1988,27 +2120,29 @@ fn lookup_at_index_ptr2<'a, 'ctx, 'env>( pub fn reserve_with_refcount<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout: &Layout<'a>, ) -> PointerValue<'ctx> { - let stack_size = layout.stack_size(env.layout_interner, env.target_info); - let alignment_bytes = layout.alignment_bytes(env.layout_interner, env.target_info); + let stack_size = layout.stack_size(layout_interner, env.target_info); + let alignment_bytes = layout.alignment_bytes(layout_interner, env.target_info); - let basic_type = basic_type_from_layout(env, layout); + let basic_type = basic_type_from_layout(env, layout_interner, layout); reserve_with_refcount_help(env, basic_type, stack_size, alignment_bytes) } fn reserve_with_refcount_union_as_block_of_memory<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, union_layout: UnionLayout<'a>, fields: &[&[Layout<'a>]], ) -> PointerValue<'ctx> { let ptr_bytes = env.target_info; let roc_union = if union_layout.stores_tag_id_as_data(ptr_bytes) { - RocUnion::tagged_from_slices(env.layout_interner, env.context, fields, env.target_info) + RocUnion::tagged_from_slices(layout_interner, env.context, fields, env.target_info) } else { - RocUnion::untagged_from_slices(env.layout_interner, env.context, fields, env.target_info) + RocUnion::untagged_from_slices(layout_interner, env.context, fields, env.target_info) }; reserve_with_refcount_help( @@ -2034,10 +2168,11 @@ fn reserve_with_refcount_help<'a, 'ctx, 'env>( pub fn allocate_with_refcount<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout: &Layout<'a>, value: BasicValueEnum<'ctx>, ) -> PointerValue<'ctx> { - let data_ptr = reserve_with_refcount(env, layout); + let data_ptr = reserve_with_refcount(env, layout_interner, layout); // store the value in the pointer env.builder.build_store(data_ptr, value); @@ -2069,6 +2204,7 @@ pub fn allocate_with_refcount_help<'a, 'ctx, 'env>( fn list_literal<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, parent: FunctionValue<'ctx>, scope: &Scope<'a, 'ctx>, element_layout: &Layout<'a>, @@ -2077,7 +2213,7 @@ fn list_literal<'a, 'ctx, 'env>( let ctx = env.context; let builder = env.builder; - let element_type = basic_type_from_layout(env, element_layout); + let element_type = basic_type_from_layout(env, layout_interner, element_layout); let list_length = elems.len(); let list_length_intval = env.ptr_int().const_int(list_length as _, false); @@ -2087,10 +2223,10 @@ fn list_literal<'a, 'ctx, 'env>( // if element_type.is_int_type() { if false { let element_type = element_type.into_int_type(); - let element_width = element_layout.stack_size(env.layout_interner, env.target_info); + let element_width = element_layout.stack_size(layout_interner, env.target_info); let size = list_length * element_width as usize; let alignment = element_layout - .alignment_bytes(env.layout_interner, env.target_info) + .alignment_bytes(layout_interner, env.target_info) .max(env.target_info.ptr_width() as u32); let mut is_all_constant = true; @@ -2181,7 +2317,7 @@ fn list_literal<'a, 'ctx, 'env>( super::build_list::store_list(env, ptr, list_length_intval).into() } else { // some of our elements are non-constant, so we must allocate space on the heap - let ptr = allocate_list(env, element_layout, list_length_intval); + let ptr = allocate_list(env, layout_interner, element_layout, list_length_intval); // then, copy the relevant segment from the constant section into the heap env.builder @@ -2207,7 +2343,7 @@ fn list_literal<'a, 'ctx, 'env>( super::build_list::store_list(env, ptr, list_length_intval).into() } } else { - let ptr = allocate_list(env, element_layout, list_length_intval); + let ptr = allocate_list(env, layout_interner, element_layout, list_length_intval); // Copy the elements from the list literal into the array for (index, element) in elems.iter().enumerate() { @@ -2222,7 +2358,7 @@ fn list_literal<'a, 'ctx, 'env>( builder.new_build_in_bounds_gep(element_type, ptr, &[index_val], "index") }; - store_roc_value(env, *element_layout, elem_ptr, val); + store_roc_value(env, layout_interner, *element_layout, elem_ptr, val); } super::build_list::store_list(env, ptr, list_length_intval).into() @@ -2231,16 +2367,17 @@ fn list_literal<'a, 'ctx, 'env>( pub fn load_roc_value<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout: Layout<'a>, source: PointerValue<'ctx>, name: &str, ) -> BasicValueEnum<'ctx> { - let basic_type = basic_type_from_layout(env, &layout); + let basic_type = basic_type_from_layout(env, layout_interner, &layout); - if layout.is_passed_by_reference(env.layout_interner, env.target_info) { + if layout.is_passed_by_reference(layout_interner, env.target_info) { let alloca = entry_block_alloca_zerofill(env, basic_type, name); - store_roc_value(env, layout, alloca, source.into()); + store_roc_value(env, layout_interner, layout, alloca, source.into()); alloca.into() } else { @@ -2250,12 +2387,17 @@ pub fn load_roc_value<'a, 'ctx, 'env>( pub fn use_roc_value<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout: Layout<'a>, source: BasicValueEnum<'ctx>, name: &str, ) -> BasicValueEnum<'ctx> { - if layout.is_passed_by_reference(env.layout_interner, env.target_info) { - let alloca = entry_block_alloca_zerofill(env, basic_type_from_layout(env, &layout), name); + if layout.is_passed_by_reference(layout_interner, env.target_info) { + let alloca = entry_block_alloca_zerofill( + env, + basic_type_from_layout(env, layout_interner, &layout), + name, + ); env.builder.build_store(alloca, source); @@ -2267,32 +2409,35 @@ pub fn use_roc_value<'a, 'ctx, 'env>( pub fn store_roc_value_opaque<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout: Layout<'a>, opaque_destination: PointerValue<'ctx>, value: BasicValueEnum<'ctx>, ) { - let target_type = basic_type_from_layout(env, &layout).ptr_type(AddressSpace::Generic); + let target_type = + basic_type_from_layout(env, layout_interner, &layout).ptr_type(AddressSpace::Generic); let destination = env.builder .build_pointer_cast(opaque_destination, target_type, "store_roc_value_opaque"); - store_roc_value(env, layout, destination, value) + store_roc_value(env, layout_interner, layout, destination, value) } pub fn store_roc_value<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout: Layout<'a>, destination: PointerValue<'ctx>, value: BasicValueEnum<'ctx>, ) { - if layout.is_passed_by_reference(env.layout_interner, env.target_info) { + if layout.is_passed_by_reference(layout_interner, env.target_info) { debug_assert!(value.is_pointer_value()); - let align_bytes = layout.alignment_bytes(env.layout_interner, env.target_info); + let align_bytes = layout.alignment_bytes(layout_interner, env.target_info); if align_bytes > 0 { let size = env.ptr_int().const_int( - layout.stack_size(env.layout_interner, env.target_info) as u64, + layout.stack_size(layout_interner, env.target_info) as u64, false, ); @@ -2322,6 +2467,7 @@ pub fn store_roc_value<'a, 'ctx, 'env>( pub fn build_exp_stmt<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, func_spec_solutions: &FuncSpecSolutions, scope: &mut Scope<'a, 'ctx>, @@ -2349,6 +2495,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( let val = build_exp_expr( env, + layout_interner, layout_ids, func_spec_solutions, scope, @@ -2368,7 +2515,15 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( stack.push(*symbol); } - let result = build_exp_stmt(env, layout_ids, func_spec_solutions, scope, parent, cont); + let result = build_exp_stmt( + env, + layout_interner, + layout_ids, + func_spec_solutions, + scope, + parent, + cont, + ); for symbol in stack { scope.remove(&symbol); @@ -2379,7 +2534,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( Ret(symbol) => { let (value, layout) = load_symbol_and_layout(scope, symbol); - match RocReturn::from_layout(env, layout) { + match RocReturn::from_layout(env, layout_interner, layout) { RocReturn::Return => { if let Some(block) = env.builder.get_insert_block() { if block.get_terminator().is_none() { @@ -2398,9 +2553,8 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( // store_roc_value(env, *layout, out_parameter.into_pointer_value(), value); let destination = out_parameter.into_pointer_value(); - if layout.is_passed_by_reference(env.layout_interner, env.target_info) { - let align_bytes = - layout.alignment_bytes(env.layout_interner, env.target_info); + if layout.is_passed_by_reference(layout_interner, env.target_info) { + let align_bytes = layout.alignment_bytes(layout_interner, env.target_info); if align_bytes > 0 { debug_assert!( @@ -2431,7 +2585,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( // Hence, we explicitly memcpy source to destination, and rely on // LLVM optimizing away any inefficiencies. let target_info = env.target_info; - let width = layout.stack_size(env.layout_interner, target_info); + let width = layout.stack_size(layout_interner, target_info); let size = env.ptr_int().const_int(width as _, false); env.builder @@ -2472,7 +2626,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( cond_layout, cond_symbol, } => { - let ret_type = basic_type_from_layout(env, ret_layout); + let ret_type = basic_type_from_layout(env, layout_interner, ret_layout); let switch_args = SwitchArgsIr { cond_layout: *cond_layout, @@ -2484,6 +2638,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( build_switch_ir( env, + layout_interner, layout_ids, func_spec_solutions, scope, @@ -2509,11 +2664,11 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( builder.position_at_end(cont_block); for param in parameters.iter() { - let basic_type = basic_type_from_layout(env, ¶m.layout); + let basic_type = basic_type_from_layout(env, layout_interner, ¶m.layout); let phi_type = if param .layout - .is_passed_by_reference(env.layout_interner, env.target_info) + .is_passed_by_reference(layout_interner, env.target_info) { basic_type.ptr_type(AddressSpace::Generic).into() } else { @@ -2534,6 +2689,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( // construct the blocks that may jump to this join point build_exp_stmt( env, + layout_interner, layout_ids, func_spec_solutions, scope, @@ -2555,6 +2711,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( // put the continuation in let result = build_exp_stmt( env, + layout_interner, layout_ids, func_spec_solutions, scope, @@ -2597,20 +2754,43 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( let (value, layout) = load_symbol_and_layout(scope, symbol); let layout = *layout; - if layout.contains_refcounted(env.layout_interner) { - increment_refcount_layout(env, layout_ids, *inc_amount, value, &layout); + if layout.contains_refcounted(layout_interner) { + increment_refcount_layout( + env, + layout_interner, + layout_ids, + *inc_amount, + value, + &layout, + ); } - build_exp_stmt(env, layout_ids, func_spec_solutions, scope, parent, cont) + build_exp_stmt( + env, + layout_interner, + layout_ids, + func_spec_solutions, + scope, + parent, + cont, + ) } Dec(symbol) => { let (value, layout) = load_symbol_and_layout(scope, symbol); - if layout.contains_refcounted(env.layout_interner) { - decrement_refcount_layout(env, layout_ids, value, layout); + if layout.contains_refcounted(layout_interner) { + decrement_refcount_layout(env, layout_interner, layout_ids, value, layout); } - build_exp_stmt(env, layout_ids, func_spec_solutions, scope, parent, cont) + build_exp_stmt( + env, + layout_interner, + layout_ids, + func_spec_solutions, + scope, + parent, + cont, + ) } DecRef(symbol) => { let (value, layout) = load_symbol_and_layout(scope, symbol); @@ -2619,8 +2799,9 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( Layout::Builtin(Builtin::Str) => todo!(), Layout::Builtin(Builtin::List(element_layout)) => { debug_assert!(value.is_struct_value()); - let alignment = element_layout - .alignment_bytes(env.layout_interner, env.target_info); + let element_layout = layout_interner.get(*element_layout); + let alignment = + element_layout.alignment_bytes(layout_interner, env.target_info); build_list::decref(env, value.into_struct_value(), alignment); } @@ -2641,7 +2822,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( env.builder.position_at_end(then_block); let refcount_ptr = PointerToRefcount::from_ptr_to_data(env, value_ptr); - refcount_ptr.decrement(env, layout); + refcount_ptr.decrement(env, layout_interner, layout); env.builder.build_unconditional_branch(done_block); } @@ -2656,7 +2837,15 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( } } - build_exp_stmt(env, layout_ids, func_spec_solutions, scope, parent, cont) + build_exp_stmt( + env, + layout_interner, + layout_ids, + func_spec_solutions, + scope, + parent, + cont, + ) } } } @@ -2672,6 +2861,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( crate::llvm::expect::clone_to_shared_memory( env, + layout_interner, scope, layout_ids, &shared_memory, @@ -2686,6 +2876,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( build_exp_stmt( env, + layout_interner, layout_ids, func_spec_solutions, scope, @@ -2727,6 +2918,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( clone_to_shared_memory( env, + layout_interner, scope, layout_ids, &shared_memory, @@ -2756,6 +2948,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( build_exp_stmt( env, + layout_interner, layout_ids, func_spec_solutions, scope, @@ -2797,6 +2990,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( clone_to_shared_memory( env, + layout_interner, scope, layout_ids, &shared_memory, @@ -2822,6 +3016,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>( build_exp_stmt( env, + layout_interner, layout_ids, func_spec_solutions, scope, @@ -3057,11 +3252,12 @@ fn complex_bitcast_to_bigger_than_from<'ctx>( /// get the tag id out of a pointer to a wrapped (i.e. stores the tag id at runtime) layout fn get_tag_id_wrapped<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, union_layout: UnionLayout<'a>, from_value: PointerValue<'ctx>, ) -> IntValue<'ctx> { - let union_struct_type = struct_type_from_union_layout(env, &union_layout); - let tag_id_type = basic_type_from_layout(env, &union_layout.tag_id_layout()); + let union_struct_type = struct_type_from_union_layout(env, layout_interner, &union_layout); + let tag_id_type = basic_type_from_layout(env, layout_interner, &union_layout.tag_id_layout()); let tag_id_ptr = env .builder @@ -3124,6 +3320,7 @@ fn const_u128<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>, value: u128) -> IntValu fn build_switch_ir<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, func_spec_solutions: &FuncSpecSolutions, scope: &Scope<'a, 'ctx>, @@ -3149,8 +3346,8 @@ fn build_switch_ir<'a, 'ctx, 'env>( let (cond_value, stored_layout) = load_symbol_and_layout(scope, cond_symbol); debug_assert_eq!( - basic_type_from_layout(env, &cond_layout), - basic_type_from_layout(env, stored_layout), + basic_type_from_layout(env, layout_interner, &cond_layout), + basic_type_from_layout(env, layout_interner, stored_layout), "This switch matches on {:?}, but the matched-on symbol {:?} has layout {:?}", cond_layout, cond_symbol, @@ -3177,7 +3374,7 @@ fn build_switch_ir<'a, 'ctx, 'env>( Layout::Union(variant) => { cond_layout = variant.tag_id_layout(); - get_tag_id(env, parent, &variant, cond_value) + get_tag_id(env, layout_interner, parent, &variant, cond_value) } Layout::Builtin(_) => cond_value.into_int_value(), other => todo!("Build switch value from layout: {:?}", other), @@ -3199,6 +3396,7 @@ fn build_switch_ir<'a, 'ctx, 'env>( let branch_val = build_exp_stmt( env, + layout_interner, layout_ids, func_spec_solutions, scope, @@ -3217,6 +3415,7 @@ fn build_switch_ir<'a, 'ctx, 'env>( let branch_val = build_exp_stmt( env, + layout_interner, layout_ids, func_spec_solutions, scope, @@ -3270,6 +3469,7 @@ fn build_switch_ir<'a, 'ctx, 'env>( let branch_val = build_exp_stmt( env, + layout_interner, layout_ids, func_spec_solutions, scope, @@ -3288,6 +3488,7 @@ fn build_switch_ir<'a, 'ctx, 'env>( let default_val = build_exp_stmt( env, + layout_interner, layout_ids, func_spec_solutions, scope, @@ -3341,6 +3542,7 @@ pub fn create_entry_block_alloca<'a, 'ctx>( fn expose_function_to_host<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, symbol: Symbol, roc_function: FunctionValue<'ctx>, arguments: &'a [Layout<'a>], @@ -3362,6 +3564,7 @@ fn expose_function_to_host<'a, 'ctx, 'env>( expose_function_to_host_help_c_abi( env, + layout_interner, ident_string, roc_function, arguments, @@ -3372,6 +3575,7 @@ fn expose_function_to_host<'a, 'ctx, 'env>( fn expose_function_to_host_help_c_abi_generic<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, roc_function: FunctionValue<'ctx>, arguments: &[Layout<'a>], return_layout: Layout<'a>, @@ -3381,7 +3585,7 @@ fn expose_function_to_host_help_c_abi_generic<'a, 'ctx, 'env>( let mut cc_argument_types = Vec::with_capacity_in(arguments.len(), env.arena); for layout in arguments { - cc_argument_types.push(to_cc_type(env, layout)); + cc_argument_types.push(to_cc_type(env, layout_interner, layout)); } // STEP 1: turn `f : a,b,c -> d` into `f : a,b,c, &d -> {}` @@ -3471,7 +3675,8 @@ fn expose_function_to_host_help_c_abi_generic<'a, 'ctx, 'env>( let call_result = if env.mode.returns_roc_result() { debug_assert_eq!(args.len(), roc_function.get_params().len()); - let roc_wrapper_function = make_exception_catcher(env, roc_function, return_layout); + let roc_wrapper_function = + make_exception_catcher(env, layout_interner, roc_function, return_layout); debug_assert_eq!( arguments_for_call.len(), roc_wrapper_function.get_params().len() @@ -3480,9 +3685,21 @@ fn expose_function_to_host_help_c_abi_generic<'a, 'ctx, 'env>( builder.position_at_end(entry); let wrapped_layout = roc_call_result_layout(env.arena, return_layout, env.target_info); - call_roc_function(env, roc_function, &wrapped_layout, arguments_for_call) + call_roc_function( + env, + layout_interner, + roc_function, + &wrapped_layout, + arguments_for_call, + ) } else { - call_roc_function(env, roc_function, &return_layout, arguments_for_call) + call_roc_function( + env, + layout_interner, + roc_function, + &return_layout, + arguments_for_call, + ) }; let output_arg_index = 0; @@ -3492,7 +3709,7 @@ fn expose_function_to_host_help_c_abi_generic<'a, 'ctx, 'env>( .unwrap() .into_pointer_value(); - store_roc_value(env, return_layout, output_arg, call_result); + store_roc_value(env, layout_interner, return_layout, output_arg, call_result); builder.build_return(None); c_function @@ -3500,6 +3717,7 @@ fn expose_function_to_host_help_c_abi_generic<'a, 'ctx, 'env>( fn expose_function_to_host_help_c_abi_gen_test<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, ident_string: &str, roc_function: FunctionValue<'ctx>, arguments: &[Layout<'a>], @@ -3509,12 +3727,14 @@ fn expose_function_to_host_help_c_abi_gen_test<'a, 'ctx, 'env>( // a tagged union to indicate to the test loader that a panic occurred. // especially when running 32-bit binaries on a 64-bit machine, there // does not seem to be a smarter solution - let wrapper_return_type = - roc_call_result_type(env, basic_type_from_layout(env, &return_layout)); + let wrapper_return_type = roc_call_result_type( + env, + basic_type_from_layout(env, layout_interner, &return_layout), + ); let mut cc_argument_types = Vec::with_capacity_in(arguments.len(), env.arena); for layout in arguments { - cc_argument_types.push(to_cc_type(env, layout)); + cc_argument_types.push(to_cc_type(env, layout_interner, layout)); } // STEP 1: turn `f : a,b,c -> d` into `f : a,b,c, &d -> {}` if the C abi demands it @@ -3592,14 +3812,16 @@ fn expose_function_to_host_help_c_abi_gen_test<'a, 'ctx, 'env>( let call_result = { let last_block = builder.get_insert_block().unwrap(); - let roc_wrapper_function = make_exception_catcher(env, roc_function, return_layout); + let roc_wrapper_function = + make_exception_catcher(env, layout_interner, roc_function, return_layout); builder.position_at_end(last_block); call_roc_function( env, + layout_interner, roc_wrapper_function, - &Layout::struct_no_name_order(&[Layout::u64(), return_layout]), + &Layout::struct_no_name_order(env.arena.alloc([Layout::u64(), return_layout])), arguments_for_call, ) }; @@ -3648,18 +3870,21 @@ fn expose_function_to_host_help_c_abi_gen_test<'a, 'ctx, 'env>( fn expose_function_to_host_help_c_abi_v2<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, roc_function: FunctionValue<'ctx>, arguments: &[Layout<'a>], return_layout: Layout<'a>, c_function_name: &str, ) -> FunctionValue<'ctx> { - let it = arguments.iter().map(|l| to_cc_type(env, l)); + let it = arguments + .iter() + .map(|l| to_cc_type(env, layout_interner, l)); let argument_types = Vec::from_iter_in(it, env.arena); - let return_type = basic_type_from_layout(env, &return_layout); + let return_type = basic_type_from_layout(env, layout_interner, &return_layout); - let cc_return = to_cc_return(env, &return_layout); - let roc_return = RocReturn::from_layout(env, &return_layout); + let cc_return = to_cc_return(env, layout_interner, &return_layout); + let roc_return = RocReturn::from_layout(env, layout_interner, &return_layout); let c_function_spec = FunctionSpec::cconv(env, cc_return, Some(return_type), &argument_types); @@ -3806,7 +4031,13 @@ fn expose_function_to_host_help_c_abi_v2<'a, 'ctx, 'env>( let arguments = Vec::from_iter_in(it, env.arena); - let value = call_roc_function(env, roc_function, &return_layout, arguments.as_slice()); + let value = call_roc_function( + env, + layout_interner, + roc_function, + &return_layout, + arguments.as_slice(), + ); match cc_return { CCReturn::Return => match roc_return { @@ -3852,6 +4083,7 @@ fn expose_function_to_host_help_c_abi_v2<'a, 'ctx, 'env>( fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, ident_string: &str, roc_function: FunctionValue<'ctx>, arguments: &[Layout<'a>], @@ -3862,6 +4094,7 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>( LlvmBackendMode::GenTest | LlvmBackendMode::WasmGenTest | LlvmBackendMode::CliTest => { return expose_function_to_host_help_c_abi_gen_test( env, + layout_interner, ident_string, roc_function, arguments, @@ -3876,6 +4109,7 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>( // a generic version that writes the result into a passed *u8 pointer expose_function_to_host_help_c_abi_generic( env, + layout_interner, roc_function, arguments, return_layout, @@ -3884,6 +4118,7 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>( let c_function = expose_function_to_host_help_c_abi_v2( env, + layout_interner, roc_function, arguments, return_layout, @@ -3922,7 +4157,7 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>( } LlvmBackendMode::Binary | LlvmBackendMode::BinaryDev => { - basic_type_from_layout(env, &return_layout) + basic_type_from_layout(env, layout_interner, &return_layout) } }; @@ -4061,6 +4296,7 @@ pub fn get_panic_tag_ptr<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> PointerVa fn set_jump_and_catch_long_jump<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, parent: FunctionValue<'ctx>, roc_function: FunctionValue<'ctx>, arguments: &[BasicValueEnum<'ctx>], @@ -4069,7 +4305,7 @@ fn set_jump_and_catch_long_jump<'a, 'ctx, 'env>( let context = env.context; let builder = env.builder; - let return_type = basic_type_from_layout(env, &return_layout); + let return_type = basic_type_from_layout(env, layout_interner, &return_layout); let call_result_type = roc_call_result_type(env, return_type.as_basic_type_enum()); let result_alloca = builder.build_alloca(call_result_type, "result"); @@ -4092,9 +4328,15 @@ fn set_jump_and_catch_long_jump<'a, 'ctx, 'env>( { builder.position_at_end(then_block); - let call_result = call_roc_function(env, roc_function, &return_layout, arguments); + let call_result = call_roc_function( + env, + layout_interner, + roc_function, + &return_layout, + arguments, + ); - let return_value = make_good_roc_result(env, return_layout, call_result); + let return_value = make_good_roc_result(env, layout_interner, return_layout, call_result); builder.build_store(result_alloca, return_value); @@ -4141,13 +4383,19 @@ fn set_jump_and_catch_long_jump<'a, 'ctx, 'env>( fn make_exception_catcher<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, roc_function: FunctionValue<'ctx>, return_layout: Layout<'a>, ) -> FunctionValue<'ctx> { let wrapper_function_name = format!("{}_catcher", roc_function.get_name().to_str().unwrap()); - let function_value = - make_exception_catching_wrapper(env, roc_function, return_layout, &wrapper_function_name); + let function_value = make_exception_catching_wrapper( + env, + layout_interner, + roc_function, + return_layout, + &wrapper_function_name, + ); function_value.set_linkage(Linkage::Internal); @@ -4180,21 +4428,26 @@ fn roc_call_result_type<'a, 'ctx, 'env>( fn make_good_roc_result<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, return_layout: Layout<'a>, return_value: BasicValueEnum<'ctx>, ) -> BasicValueEnum<'ctx> { let context = env.context; let builder = env.builder; - let return_type = basic_type_from_layout(env, &return_layout); + let return_type = basic_type_from_layout(env, layout_interner, &return_layout); - let v1 = roc_call_result_type(env, basic_type_from_layout(env, &return_layout)).const_zero(); + let v1 = roc_call_result_type( + env, + basic_type_from_layout(env, layout_interner, &return_layout), + ) + .const_zero(); let v2 = builder .build_insert_value(v1, context.i64_type().const_zero(), 0, "set_no_error") .unwrap(); - let v3 = if return_layout.is_passed_by_reference(env.layout_interner, env.target_info) { + let v3 = if return_layout.is_passed_by_reference(layout_interner, env.target_info) { let loaded = env.builder.new_build_load( return_type, return_value.into_pointer_value(), @@ -4214,6 +4467,7 @@ fn make_good_roc_result<'a, 'ctx, 'env>( fn make_exception_catching_wrapper<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, roc_function: FunctionValue<'ctx>, return_layout: Layout<'a>, wrapper_function_name: &str, @@ -4224,7 +4478,7 @@ fn make_exception_catching_wrapper<'a, 'ctx, 'env>( let builder = env.builder; let roc_function_type = roc_function.get_type(); - let argument_types = match RocReturn::from_layout(env, &return_layout) { + let argument_types = match RocReturn::from_layout(env, layout_interner, &return_layout) { RocReturn::Return => roc_function_type.get_param_types(), RocReturn::ByPointer => { // Our fastcc passes the return pointer as the last parameter. @@ -4236,8 +4490,10 @@ fn make_exception_catching_wrapper<'a, 'ctx, 'env>( } }; - let wrapper_return_type = - roc_call_result_type(env, basic_type_from_layout(env, &return_layout)); + let wrapper_return_type = roc_call_result_type( + env, + basic_type_from_layout(env, layout_interner, &return_layout), + ); // argument_types.push(wrapper_return_type.ptr_type(AddressSpace::Generic).into()); @@ -4274,6 +4530,7 @@ fn make_exception_catching_wrapper<'a, 'ctx, 'env>( let result = set_jump_and_catch_long_jump( env, + layout_interner, wrapper_function, roc_function, &arguments, @@ -4287,6 +4544,7 @@ fn make_exception_catching_wrapper<'a, 'ctx, 'env>( pub fn build_proc_headers<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, mod_solutions: &'a ModSolutions, procedures: MutMap<(Symbol, ProcLayout<'a>), roc_mono::ir::Proc<'a>>, scope: &mut Scope<'a, 'ctx>, @@ -4310,7 +4568,14 @@ pub fn build_proc_headers<'a, 'ctx, 'env>( let it = func_solutions.specs(); let mut function_values = Vec::with_capacity_in(it.size_hint().0, env.arena); for specialization in it { - let fn_val = build_proc_header(env, *specialization, symbol, &proc, layout_ids); + let fn_val = build_proc_header( + env, + layout_interner, + *specialization, + symbol, + &proc, + layout_ids, + ); if proc.args.is_empty() { // this is a 0-argument thunk, i.e. a top-level constant definition @@ -4330,50 +4595,75 @@ pub fn build_proc_headers<'a, 'ctx, 'env>( pub fn build_procedures<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, opt_level: OptLevel, procedures: MutMap<(Symbol, ProcLayout<'a>), roc_mono::ir::Proc<'a>>, entry_point: EntryPoint<'a>, debug_output_file: Option<&Path>, ) { - build_procedures_help(env, opt_level, procedures, entry_point, debug_output_file); + build_procedures_help( + env, + layout_interner, + opt_level, + procedures, + entry_point, + debug_output_file, + ); } pub fn build_wasm_test_wrapper<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, opt_level: OptLevel, procedures: MutMap<(Symbol, ProcLayout<'a>), roc_mono::ir::Proc<'a>>, entry_point: SingleEntryPoint<'a>, ) -> (&'static str, FunctionValue<'ctx>) { let mod_solutions = build_procedures_help( env, + layout_interner, opt_level, procedures, EntryPoint::Single(entry_point), Some(&std::env::temp_dir().join("test.ll")), ); - promote_to_wasm_test_wrapper(env, mod_solutions, entry_point.symbol, entry_point.layout) + promote_to_wasm_test_wrapper( + env, + layout_interner, + mod_solutions, + entry_point.symbol, + entry_point.layout, + ) } pub fn build_procedures_return_main<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, opt_level: OptLevel, procedures: MutMap<(Symbol, ProcLayout<'a>), roc_mono::ir::Proc<'a>>, entry_point: SingleEntryPoint<'a>, ) -> (&'static str, FunctionValue<'ctx>) { let mod_solutions = build_procedures_help( env, + layout_interner, opt_level, procedures, EntryPoint::Single(entry_point), Some(&std::env::temp_dir().join("test.ll")), ); - promote_to_main_function(env, mod_solutions, entry_point.symbol, entry_point.layout) + promote_to_main_function( + env, + layout_interner, + mod_solutions, + entry_point.symbol, + entry_point.layout, + ) } pub fn build_procedures_expose_expects<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, opt_level: OptLevel, expects: &[Symbol], procedures: MutMap<(Symbol, ProcLayout<'a>), roc_mono::ir::Proc<'a>>, @@ -4382,6 +4672,7 @@ pub fn build_procedures_expose_expects<'a, 'ctx, 'env>( let mod_solutions = build_procedures_help( env, + layout_interner, opt_level, procedures, entry_point, @@ -4435,6 +4726,7 @@ pub fn build_procedures_expose_expects<'a, 'ctx, 'env>( // Add main to the module. let _ = expose_function_to_host_help_c_abi( env, + layout_interner, name, roc_main_fn, top_level.arguments, @@ -4448,6 +4740,7 @@ pub fn build_procedures_expose_expects<'a, 'ctx, 'env>( fn build_procedures_help<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, opt_level: OptLevel, procedures: MutMap<(Symbol, ProcLayout<'a>), roc_mono::ir::Proc<'a>>, entry_point: EntryPoint<'a>, @@ -4460,7 +4753,7 @@ fn build_procedures_help<'a, 'ctx, 'env>( let solutions = match roc_alias_analysis::spec_program( env.arena, - env.layout_interner, + layout_interner, opt_level, entry_point, it, @@ -4478,7 +4771,14 @@ fn build_procedures_help<'a, 'ctx, 'env>( // Add all the Proc headers to the module. // We have to do this in a separate pass first, // because their bodies may reference each other. - let headers = build_proc_headers(env, mod_solutions, procedures, &mut scope, &mut layout_ids); + let headers = build_proc_headers( + env, + layout_interner, + mod_solutions, + procedures, + &mut scope, + &mut layout_ids, + ); let (_, function_pass) = construct_optimization_passes(env.module, opt_level); @@ -4493,6 +4793,7 @@ fn build_procedures_help<'a, 'ctx, 'env>( build_proc( env, + layout_interner, mod_solutions, &mut layout_ids, func_spec_solutions, @@ -4564,6 +4865,7 @@ fn func_spec_name<'a>( fn build_proc_header<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, func_spec: FuncSpec, symbol: Symbol, proc: &roc_mono::ir::Proc<'a>, @@ -4574,16 +4876,16 @@ fn build_proc_header<'a, 'ctx, 'env>( let fn_name = func_spec_name(env.arena, &env.interns, symbol, func_spec); - let ret_type = basic_type_from_layout(env, &proc.ret_layout); + let ret_type = basic_type_from_layout(env, layout_interner, &proc.ret_layout); let mut arg_basic_types = Vec::with_capacity_in(args.len(), arena); for (layout, _) in args.iter() { - let arg_type = argument_type_from_layout(env, layout); + let arg_type = argument_type_from_layout(env, layout_interner, layout); arg_basic_types.push(arg_type); } - let roc_return = RocReturn::from_layout(env, &proc.ret_layout); + let roc_return = RocReturn::from_layout(env, layout_interner, &proc.ret_layout); let fn_spec = FunctionSpec::fastcc(env, roc_return, ret_type, arg_basic_types); let fn_val = add_func( @@ -4601,6 +4903,7 @@ fn build_proc_header<'a, 'ctx, 'env>( let arguments = Vec::from_iter_in(proc.args.iter().map(|(layout, _)| *layout), env.arena); expose_function_to_host( env, + layout_interner, symbol, fn_val, arguments.into_bump_slice(), @@ -4630,6 +4933,7 @@ fn build_proc_header<'a, 'ctx, 'env>( #[allow(clippy::too_many_arguments)] fn expose_alias_to_host<'a, 'ctx, 'env>( env: &'a Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, mod_solutions: &'a ModSolutions, proc_name: LambdaName, alias_symbol: Symbol, @@ -4684,6 +4988,7 @@ fn expose_alias_to_host<'a, 'ctx, 'env>( build_closure_caller( env, + layout_interner, &fn_name, evaluator, alias_symbol, @@ -4699,7 +5004,7 @@ fn expose_alias_to_host<'a, 'ctx, 'env>( // // * roc__mainForHost_1_Update_result_size() -> i64 - let result_type = basic_type_from_layout(env, &result); + let result_type = basic_type_from_layout(env, layout_interner, &result); build_host_exposed_alias_size_help( env, @@ -4715,6 +5020,7 @@ fn expose_alias_to_host<'a, 'ctx, 'env>( #[allow(clippy::too_many_arguments)] fn build_closure_caller<'a, 'ctx, 'env>( env: &'a Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, def_name: &str, evaluator: FunctionValue<'ctx>, alias_symbol: Symbol, @@ -4726,15 +5032,18 @@ fn build_closure_caller<'a, 'ctx, 'env>( let mut argument_types = Vec::with_capacity_in(arguments.len() + 3, env.arena); for layout in arguments { - let arg_type = basic_type_from_layout(env, layout); + let arg_type = basic_type_from_layout(env, layout_interner, layout); let arg_ptr_type = arg_type.ptr_type(AddressSpace::Generic); argument_types.push(arg_ptr_type.into()); } let closure_argument_type = { - let basic_type = - basic_type_from_layout(env, &lambda_set.runtime_representation(env.layout_interner)); + let basic_type = basic_type_from_layout( + env, + layout_interner, + &lambda_set.runtime_representation(layout_interner), + ); basic_type.ptr_type(AddressSpace::Generic) }; @@ -4743,7 +5052,7 @@ fn build_closure_caller<'a, 'ctx, 'env>( let context = &env.context; let builder = env.builder; - let result_type = basic_type_from_layout(env, result); + let result_type = basic_type_from_layout(env, layout_interner, result); let output_type = { result_type.ptr_type(AddressSpace::Generic) }; argument_types.push(output_type.into()); @@ -4781,13 +5090,13 @@ fn build_closure_caller<'a, 'ctx, 'env>( // NOTE this may be incorrect in the long run // here we load any argument that is a pointer - let closure_layout = lambda_set.runtime_representation(env.layout_interner); + let closure_layout = lambda_set.runtime_representation(layout_interner); let layouts_it = arguments.iter().chain(std::iter::once(&closure_layout)); for (param, layout) in evaluator_arguments.iter_mut().zip(layouts_it) { if param.is_pointer_value() - && !layout.is_passed_by_reference(env.layout_interner, env.target_info) + && !layout.is_passed_by_reference(layout_interner, env.target_info) { - let basic_type = basic_type_from_layout(env, layout); + let basic_type = basic_type_from_layout(env, layout_interner, layout); *param = builder.new_build_load(basic_type, param.into_pointer_value(), "load_param"); } } @@ -4795,6 +5104,7 @@ fn build_closure_caller<'a, 'ctx, 'env>( if env.mode.returns_roc_result() { let call_result = set_jump_and_catch_long_jump( env, + layout_interner, function_value, evaluator, &evaluator_arguments, @@ -4803,14 +5113,20 @@ fn build_closure_caller<'a, 'ctx, 'env>( builder.build_store(output, call_result); } else { - let call_result = call_roc_function(env, evaluator, return_layout, &evaluator_arguments); + let call_result = call_roc_function( + env, + layout_interner, + evaluator, + return_layout, + &evaluator_arguments, + ); - if return_layout.is_passed_by_reference(env.layout_interner, env.target_info) { - let align_bytes = return_layout.alignment_bytes(env.layout_interner, env.target_info); + if return_layout.is_passed_by_reference(layout_interner, env.target_info) { + let align_bytes = return_layout.alignment_bytes(layout_interner, env.target_info); if align_bytes > 0 { let size = env.ptr_int().const_int( - return_layout.stack_size(env.layout_interner, env.target_info) as u64, + return_layout.stack_size(layout_interner, env.target_info) as u64, false, ); @@ -4837,14 +5153,16 @@ fn build_closure_caller<'a, 'ctx, 'env>( // STEP 4: build a {} -> u64 function that gives the size of the closure build_host_exposed_alias_size( env, + layout_interner, def_name, alias_symbol, - lambda_set.runtime_representation(env.layout_interner), + lambda_set.runtime_representation(layout_interner), ); } fn build_host_exposed_alias_size<'a, 'ctx, 'env>( env: &'a Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, def_name: &str, alias_symbol: Symbol, layout: Layout<'a>, @@ -4854,7 +5172,7 @@ fn build_host_exposed_alias_size<'a, 'ctx, 'env>( def_name, alias_symbol, None, - basic_type_from_layout(env, &layout), + basic_type_from_layout(env, layout_interner, &layout), ) } @@ -4905,6 +5223,7 @@ fn build_host_exposed_alias_size_help<'a, 'ctx, 'env>( pub fn build_proc<'a, 'ctx, 'env>( env: &'a Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, mod_solutions: &'a ModSolutions, layout_ids: &mut LayoutIds<'a>, func_spec_solutions: &FuncSpecSolutions, @@ -4927,6 +5246,7 @@ pub fn build_proc<'a, 'ctx, 'env>( for (alias_name, (generated_function, top_level, layout)) in aliases.iter() { expose_alias_to_host( env, + layout_interner, mod_solutions, proc.name, *alias_name, @@ -4959,6 +5279,7 @@ pub fn build_proc<'a, 'ctx, 'env>( let body = build_exp_stmt( env, + layout_interner, layout_ids, func_spec_solutions, &mut scope, @@ -5040,6 +5361,7 @@ fn function_value_by_name_help<'a, 'ctx, 'env>( #[inline(always)] fn roc_call_with_args<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, argument_layouts: &[Layout<'a>], result_layout: &Layout<'a>, name: LambdaName<'a>, @@ -5055,25 +5377,26 @@ fn roc_call_with_args<'a, 'ctx, 'env>( result_layout, ); - call_roc_function(env, fn_val, result_layout, arguments) + call_roc_function(env, layout_interner, fn_val, result_layout, arguments) } pub fn call_roc_function<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, roc_function: FunctionValue<'ctx>, result_layout: &Layout<'a>, arguments: &[BasicValueEnum<'ctx>], ) -> BasicValueEnum<'ctx> { let pass_by_pointer = roc_function.get_type().get_param_types().len() == arguments.len() + 1; - match RocReturn::from_layout(env, result_layout) { + match RocReturn::from_layout(env, layout_interner, result_layout) { RocReturn::ByPointer if !pass_by_pointer => { // WARNING this is a hack!! let it = arguments.iter().map(|x| (*x).into()); let mut arguments = Vec::from_iter_in(it, env.arena); arguments.pop(); - let result_type = basic_type_from_layout(env, result_layout); + let result_type = basic_type_from_layout(env, layout_interner, result_layout); let result_alloca = env.builder.build_alloca(result_type, "result_value"); arguments.push(result_alloca.into()); @@ -5095,7 +5418,7 @@ pub fn call_roc_function<'a, 'ctx, 'env>( let it = arguments.iter().map(|x| (*x).into()); let mut arguments = Vec::from_iter_in(it, env.arena); - let result_type = basic_type_from_layout(env, result_layout); + let result_type = basic_type_from_layout(env, layout_interner, result_layout); let result_alloca = entry_block_alloca_zerofill(env, result_type, "result_value"); arguments.push(result_alloca.into()); @@ -5110,7 +5433,7 @@ pub fn call_roc_function<'a, 'ctx, 'env>( debug_assert_eq!(roc_function.get_call_conventions(), FAST_CALL_CONV); call.set_call_convention(FAST_CALL_CONV); - if result_layout.is_passed_by_reference(env.layout_interner, env.target_info) { + if result_layout.is_passed_by_reference(layout_interner, env.target_info) { result_alloca.into() } else { env.builder.new_build_load( @@ -5175,6 +5498,7 @@ pub struct RocFunctionCall<'ctx> { #[allow(clippy::too_many_arguments)] pub(crate) fn roc_function_call<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, transform: FunctionValue<'ctx>, closure_data: BasicValueEnum<'ctx>, @@ -5190,15 +5514,22 @@ pub(crate) fn roc_function_call<'a, 'ctx, 'env>( .build_alloca(closure_data.get_type(), "closure_data_ptr"); env.builder.build_store(closure_data_ptr, closure_data); - let stepper_caller = - build_transform_caller(env, transform, lambda_set, argument_layouts, result_layout) - .as_global_value() - .as_pointer_value(); + let stepper_caller = build_transform_caller( + env, + layout_interner, + transform, + lambda_set, + argument_layouts, + result_layout, + ) + .as_global_value() + .as_pointer_value(); let inc_closure_data = build_inc_n_wrapper( env, + layout_interner, layout_ids, - &lambda_set.runtime_representation(env.layout_interner), + &lambda_set.runtime_representation(layout_interner), ) .as_global_value() .as_pointer_value(); @@ -5222,13 +5553,14 @@ pub(crate) fn roc_function_call<'a, 'ctx, 'env>( /// (this does not currently happen here) be coerced to that integer type. fn to_cc_type<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout: &Layout<'a>, ) -> BasicTypeEnum<'ctx> { - match layout.runtime_representation(env.layout_interner) { + match layout.runtime_representation(layout_interner) { Layout::Builtin(builtin) => to_cc_type_builtin(env, &builtin), layout => { // TODO this is almost certainly incorrect for bigger structs - basic_type_from_layout(env, &layout) + basic_type_from_layout(env, layout_interner, &layout) } } } @@ -5296,9 +5628,10 @@ impl RocReturn { pub(crate) fn from_layout<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout: &Layout<'a>, ) -> Self { - if Self::roc_return_by_pointer(env.layout_interner, env.target_info, *layout) { + if Self::roc_return_by_pointer(layout_interner, env.target_info, *layout) { RocReturn::ByPointer } else { RocReturn::Return @@ -5432,8 +5765,12 @@ impl<'ctx> FunctionSpec<'ctx> { } /// According to the C ABI, how should we return a value with the given layout? -pub fn to_cc_return<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>, layout: &Layout<'a>) -> CCReturn { - let return_size = layout.stack_size(env.layout_interner, env.target_info); +pub fn to_cc_return<'a, 'ctx, 'env>( + env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, + layout: &Layout<'a>, +) -> CCReturn { + let return_size = layout.stack_size(layout_interner, env.target_info); let pass_result_by_pointer = match env.target_info.operating_system { roc_target::OperatingSystem::Windows => { return_size >= 2 * env.target_info.ptr_width() as u32 @@ -5461,6 +5798,7 @@ fn function_arguments<'a, 'ctx, 'env>( fn build_foreign_symbol<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, scope: &mut Scope<'a, 'ctx>, foreign: &roc_module::ident::ForeignSymbol, argument_symbols: &[Symbol], @@ -5492,9 +5830,9 @@ fn build_foreign_symbol<'a, 'ctx, 'env>( // and can use in the wrapper // - a FAST_CALL_CONV wrapper that we make here, e.g. `roc_fx_putLine_fastcc_wrapper` - let return_type = basic_type_from_layout(env, ret_layout); - let roc_return = RocReturn::from_layout(env, ret_layout); - let cc_return = to_cc_return(env, ret_layout); + let return_type = basic_type_from_layout(env, layout_interner, ret_layout); + let roc_return = RocReturn::from_layout(env, layout_interner, ret_layout); + let cc_return = to_cc_return(env, layout_interner, ret_layout); let mut cc_argument_types = Vec::with_capacity_in(argument_symbols.len() + 1, env.arena); @@ -5505,9 +5843,9 @@ fn build_foreign_symbol<'a, 'ctx, 'env>( for symbol in argument_symbols { let (value, layout) = load_symbol_and_layout(scope, symbol); - cc_argument_types.push(to_cc_type(env, layout)); + cc_argument_types.push(to_cc_type(env, layout_interner, layout)); - let basic_type = argument_type_from_layout(env, layout); + let basic_type = argument_type_from_layout(env, layout_interner, layout); fastcc_argument_types.push(basic_type); arguments.push(value); @@ -5624,7 +5962,13 @@ fn build_foreign_symbol<'a, 'ctx, 'env>( } }; - call_roc_function(env, fastcc_function, ret_layout, &arguments) + call_roc_function( + env, + layout_interner, + fastcc_function, + ret_layout, + &arguments, + ) } fn define_global_str_literal_ptr<'a, 'ctx, 'env>( diff --git a/crates/compiler/gen_llvm/src/llvm/build_list.rs b/crates/compiler/gen_llvm/src/llvm/build_list.rs index de125e4d4c..1ed5e30c6f 100644 --- a/crates/compiler/gen_llvm/src/llvm/build_list.rs +++ b/crates/compiler/gen_llvm/src/llvm/build_list.rs @@ -13,7 +13,7 @@ use morphic_lib::UpdateMode; use roc_builtins::bitcode; use roc_intern::Interner; use roc_module::symbol::Symbol; -use roc_mono::layout::{Builtin, InLayout, Layout, LayoutIds}; +use roc_mono::layout::{Builtin, InLayout, Layout, LayoutIds, STLayoutInterner}; use super::bitcode::{call_list_bitcode_fn, BitcodeReturns}; use super::build::{ @@ -63,14 +63,15 @@ pub(crate) fn pass_update_mode<'a, 'ctx, 'env>( fn pass_element_as_opaque<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, element: BasicValueEnum<'ctx>, layout: Layout<'a>, ) -> BasicValueEnum<'ctx> { - let element_type = basic_type_from_layout(env, &layout); + let element_type = basic_type_from_layout(env, layout_interner, &layout); let element_ptr = env .builder .build_alloca(element_type, "element_to_pass_as_opaque"); - store_roc_value(env, layout, element_ptr, element); + store_roc_value(env, layout_interner, layout, element_ptr, element); env.builder .build_pointer_cast( @@ -83,11 +84,12 @@ fn pass_element_as_opaque<'a, 'ctx, 'env>( pub(crate) fn layout_width<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout: &Layout<'a>, ) -> BasicValueEnum<'ctx> { env.ptr_int() .const_int( - layout.stack_size(env.layout_interner, env.target_info) as u64, + layout.stack_size(layout_interner, env.target_info) as u64, false, ) .into() @@ -108,17 +110,18 @@ pub(crate) fn pass_as_opaque<'a, 'ctx, 'env>( pub(crate) fn list_with_capacity<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, capacity: IntValue<'ctx>, element_layout: InLayout<'a>, ) -> BasicValueEnum<'ctx> { - let element_layout = env.layout_interner.get(element_layout); + let element_layout = layout_interner.get(element_layout); call_list_bitcode_fn( env, &[], &[ capacity.into(), - env.alignment_intvalue(element_layout), - layout_width(env, element_layout), + env.alignment_intvalue(layout_interner, element_layout), + layout_width(env, layout_interner, element_layout), ], BitcodeReturns::List, bitcode::LIST_WITH_CAPACITY, @@ -127,6 +130,7 @@ pub(crate) fn list_with_capacity<'a, 'ctx, 'env>( pub(crate) fn list_get_unsafe<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, element_layout: InLayout<'a>, elem_index: IntValue<'ctx>, @@ -134,8 +138,8 @@ pub(crate) fn list_get_unsafe<'a, 'ctx, 'env>( ) -> BasicValueEnum<'ctx> { let builder = env.builder; - let element_layout = env.layout_interner.get(element_layout); - let elem_type = basic_type_from_layout(env, element_layout); + let element_layout = layout_interner.get(element_layout); + let elem_type = basic_type_from_layout(env, layout_interner, element_layout); let ptr_type = elem_type.ptr_type(AddressSpace::Generic); // Load the pointer to the array data let array_data_ptr = load_list_ptr(builder, wrapper_struct, ptr_type); @@ -151,9 +155,15 @@ pub(crate) fn list_get_unsafe<'a, 'ctx, 'env>( ) }; - let result = load_roc_value(env, *element_layout, elem_ptr, "list_get_load_element"); + let result = load_roc_value( + env, + layout_interner, + *element_layout, + elem_ptr, + "list_get_load_element", + ); - increment_refcount_layout(env, layout_ids, 1, result, element_layout); + increment_refcount_layout(env, layout_interner, layout_ids, 1, result, element_layout); result } @@ -161,19 +171,20 @@ pub(crate) fn list_get_unsafe<'a, 'ctx, 'env>( /// List.reserve : List elem, Nat -> List elem pub(crate) fn list_reserve<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, list: BasicValueEnum<'ctx>, spare: BasicValueEnum<'ctx>, element_layout: InLayout<'a>, update_mode: UpdateMode, ) -> BasicValueEnum<'ctx> { - let element_layout = env.layout_interner.get(element_layout); + let element_layout = layout_interner.get(element_layout); call_list_bitcode_fn_1( env, list.into_struct_value(), &[ - env.alignment_intvalue(element_layout), + env.alignment_intvalue(layout_interner, element_layout), spare, - layout_width(env, element_layout), + layout_width(env, layout_interner, element_layout), pass_update_mode(env, update_mode), ], bitcode::LIST_RESERVE, @@ -183,6 +194,7 @@ pub(crate) fn list_reserve<'a, 'ctx, 'env>( /// List.appendUnsafe : List elem, elem -> List elem pub(crate) fn list_append_unsafe<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, original_wrapper: StructValue<'ctx>, element: BasicValueEnum<'ctx>, element_layout: &Layout<'a>, @@ -191,8 +203,8 @@ pub(crate) fn list_append_unsafe<'a, 'ctx, 'env>( env, original_wrapper, &[ - pass_element_as_opaque(env, element, *element_layout), - layout_width(env, element_layout), + pass_element_as_opaque(env, layout_interner, element, *element_layout), + layout_width(env, layout_interner, element_layout), ], bitcode::LIST_APPEND_UNSAFE, ) @@ -201,6 +213,7 @@ pub(crate) fn list_append_unsafe<'a, 'ctx, 'env>( /// List.prepend : List elem, elem -> List elem pub(crate) fn list_prepend<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, original_wrapper: StructValue<'ctx>, element: BasicValueEnum<'ctx>, element_layout: &Layout<'a>, @@ -209,9 +222,9 @@ pub(crate) fn list_prepend<'a, 'ctx, 'env>( env, original_wrapper, &[ - env.alignment_intvalue(element_layout), - pass_element_as_opaque(env, element, *element_layout), - layout_width(env, element_layout), + env.alignment_intvalue(layout_interner, element_layout), + pass_element_as_opaque(env, layout_interner, element, *element_layout), + layout_width(env, layout_interner, element_layout), ], bitcode::LIST_PREPEND, ) @@ -220,19 +233,20 @@ pub(crate) fn list_prepend<'a, 'ctx, 'env>( /// List.swap : List elem, Nat, Nat -> List elem pub(crate) fn list_swap<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, original_wrapper: StructValue<'ctx>, index_1: IntValue<'ctx>, index_2: IntValue<'ctx>, element_layout: InLayout<'a>, update_mode: UpdateMode, ) -> BasicValueEnum<'ctx> { - let element_layout = env.layout_interner.get(element_layout); + let element_layout = layout_interner.get(element_layout); call_list_bitcode_fn_1( env, original_wrapper, &[ - env.alignment_intvalue(element_layout), - layout_width(env, element_layout), + env.alignment_intvalue(layout_interner, element_layout), + layout_width(env, layout_interner, element_layout), index_1.into(), index_2.into(), pass_update_mode(env, update_mode), @@ -244,20 +258,21 @@ pub(crate) fn list_swap<'a, 'ctx, 'env>( /// List.sublist : List elem, { start : Nat, len : Nat } -> List elem pub(crate) fn list_sublist<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, original_wrapper: StructValue<'ctx>, start: IntValue<'ctx>, len: IntValue<'ctx>, element_layout: InLayout<'a>, ) -> BasicValueEnum<'ctx> { - let element_layout = env.layout_interner.get(element_layout); - let dec_element_fn = build_dec_wrapper(env, layout_ids, element_layout); + let element_layout = layout_interner.get(element_layout); + let dec_element_fn = build_dec_wrapper(env, layout_interner, layout_ids, element_layout); call_list_bitcode_fn_1( env, original_wrapper, &[ - env.alignment_intvalue(element_layout), - layout_width(env, element_layout), + env.alignment_intvalue(layout_interner, element_layout), + layout_width(env, layout_interner, element_layout), start.into(), len.into(), dec_element_fn.as_global_value().as_pointer_value().into(), @@ -269,19 +284,20 @@ pub(crate) fn list_sublist<'a, 'ctx, 'env>( /// List.dropAt : List elem, Nat -> List elem pub(crate) fn list_drop_at<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, original_wrapper: StructValue<'ctx>, count: IntValue<'ctx>, element_layout: InLayout<'a>, ) -> BasicValueEnum<'ctx> { - let element_layout = env.layout_interner.get(element_layout); - let dec_element_fn = build_dec_wrapper(env, layout_ids, element_layout); + let element_layout = layout_interner.get(element_layout); + let dec_element_fn = build_dec_wrapper(env, layout_interner, layout_ids, element_layout); call_list_bitcode_fn_1( env, original_wrapper, &[ - env.alignment_intvalue(element_layout), - layout_width(env, element_layout), + env.alignment_intvalue(layout_interner, element_layout), + layout_width(env, layout_interner, element_layout), count.into(), dec_element_fn.as_global_value().as_pointer_value().into(), ], @@ -292,6 +308,7 @@ pub(crate) fn list_drop_at<'a, 'ctx, 'env>( /// List.replace_unsafe : List elem, Nat, elem -> { list: List elem, value: elem } pub(crate) fn list_replace_unsafe<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, _layout_ids: &mut LayoutIds<'a>, list: BasicValueEnum<'ctx>, index: IntValue<'ctx>, @@ -299,7 +316,7 @@ pub(crate) fn list_replace_unsafe<'a, 'ctx, 'env>( element_layout: &Layout<'a>, update_mode: UpdateMode, ) -> BasicValueEnum<'ctx> { - let element_type = basic_type_from_layout(env, element_layout); + let element_type = basic_type_from_layout(env, layout_interner, element_layout); let element_ptr = env .builder .build_alloca(element_type, "output_element_as_opaque"); @@ -312,8 +329,8 @@ pub(crate) fn list_replace_unsafe<'a, 'ctx, 'env>( list.into_struct_value(), &[ index.into(), - pass_element_as_opaque(env, element, *element_layout), - layout_width(env, element_layout), + pass_element_as_opaque(env, layout_interner, element, *element_layout), + layout_width(env, layout_interner, element_layout), pass_as_opaque(env, element_ptr), ], bitcode::LIST_REPLACE_IN_PLACE, @@ -322,10 +339,10 @@ pub(crate) fn list_replace_unsafe<'a, 'ctx, 'env>( env, list.into_struct_value(), &[ - env.alignment_intvalue(element_layout), + env.alignment_intvalue(layout_interner, element_layout), index.into(), - pass_element_as_opaque(env, element, *element_layout), - layout_width(env, element_layout), + pass_element_as_opaque(env, layout_interner, element, *element_layout), + layout_width(env, layout_interner, element_layout), pass_as_opaque(env, element_ptr), ], bitcode::LIST_REPLACE, @@ -339,7 +356,7 @@ pub(crate) fn list_replace_unsafe<'a, 'ctx, 'env>( // the list has the same alignment as a usize / ptr. The element comes first in the struct if // its alignment is bigger than that of a list. - let element_align = element_layout.alignment_bytes(env.layout_interner, env.target_info); + let element_align = element_layout.alignment_bytes(layout_interner, env.target_info); let element_first = element_align > env.target_info.ptr_width() as u32; let fields = if element_first { @@ -424,6 +441,7 @@ pub(crate) fn destructure<'ctx>( /// List.sortWith : List a, (a, a -> Ordering) -> List a pub(crate) fn list_sort_with<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, roc_function_call: RocFunctionCall<'ctx>, compare_wrapper: PointerValue<'ctx>, list: BasicValueEnum<'ctx>, @@ -437,8 +455,8 @@ pub(crate) fn list_sort_with<'a, 'ctx, 'env>( pass_as_opaque(env, roc_function_call.data), roc_function_call.inc_n_data.into(), roc_function_call.data_is_owned.into(), - env.alignment_intvalue(element_layout), - layout_width(env, element_layout), + env.alignment_intvalue(layout_interner, element_layout), + layout_width(env, layout_interner, element_layout), ], bitcode::LIST_SORT_WITH, ) @@ -447,6 +465,7 @@ pub(crate) fn list_sort_with<'a, 'ctx, 'env>( /// List.map : List before, (before -> after) -> List after pub(crate) fn list_map<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, roc_function_call: RocFunctionCall<'ctx>, list: BasicValueEnum<'ctx>, element_layout: &Layout<'a>, @@ -460,9 +479,9 @@ pub(crate) fn list_map<'a, 'ctx, 'env>( pass_as_opaque(env, roc_function_call.data), roc_function_call.inc_n_data.into(), roc_function_call.data_is_owned.into(), - env.alignment_intvalue(return_layout), - layout_width(env, element_layout), - layout_width(env, return_layout), + env.alignment_intvalue(layout_interner, return_layout), + layout_width(env, layout_interner, element_layout), + layout_width(env, layout_interner, return_layout), ], bitcode::LIST_MAP, ) @@ -470,6 +489,7 @@ pub(crate) fn list_map<'a, 'ctx, 'env>( pub(crate) fn list_map2<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, roc_function_call: RocFunctionCall<'ctx>, list1: BasicValueEnum<'ctx>, @@ -478,8 +498,8 @@ pub(crate) fn list_map2<'a, 'ctx, 'env>( element2_layout: &Layout<'a>, return_layout: &Layout<'a>, ) -> BasicValueEnum<'ctx> { - let dec_a = build_dec_wrapper(env, layout_ids, element1_layout); - let dec_b = build_dec_wrapper(env, layout_ids, element2_layout); + let dec_a = build_dec_wrapper(env, layout_interner, layout_ids, element1_layout); + let dec_b = build_dec_wrapper(env, layout_interner, layout_ids, element2_layout); call_list_bitcode_fn( env, @@ -489,10 +509,10 @@ pub(crate) fn list_map2<'a, 'ctx, 'env>( pass_as_opaque(env, roc_function_call.data), roc_function_call.inc_n_data.into(), roc_function_call.data_is_owned.into(), - env.alignment_intvalue(return_layout), - layout_width(env, element1_layout), - layout_width(env, element2_layout), - layout_width(env, return_layout), + env.alignment_intvalue(layout_interner, return_layout), + layout_width(env, layout_interner, element1_layout), + layout_width(env, layout_interner, element2_layout), + layout_width(env, layout_interner, return_layout), dec_a.as_global_value().as_pointer_value().into(), dec_b.as_global_value().as_pointer_value().into(), ], @@ -503,6 +523,7 @@ pub(crate) fn list_map2<'a, 'ctx, 'env>( pub(crate) fn list_map3<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, roc_function_call: RocFunctionCall<'ctx>, list1: BasicValueEnum<'ctx>, @@ -513,9 +534,9 @@ pub(crate) fn list_map3<'a, 'ctx, 'env>( element3_layout: &Layout<'a>, result_layout: &Layout<'a>, ) -> BasicValueEnum<'ctx> { - let dec_a = build_dec_wrapper(env, layout_ids, element1_layout); - let dec_b = build_dec_wrapper(env, layout_ids, element2_layout); - let dec_c = build_dec_wrapper(env, layout_ids, element3_layout); + let dec_a = build_dec_wrapper(env, layout_interner, layout_ids, element1_layout); + let dec_b = build_dec_wrapper(env, layout_interner, layout_ids, element2_layout); + let dec_c = build_dec_wrapper(env, layout_interner, layout_ids, element3_layout); call_list_bitcode_fn( env, @@ -529,11 +550,11 @@ pub(crate) fn list_map3<'a, 'ctx, 'env>( pass_as_opaque(env, roc_function_call.data), roc_function_call.inc_n_data.into(), roc_function_call.data_is_owned.into(), - env.alignment_intvalue(result_layout), - layout_width(env, element1_layout), - layout_width(env, element2_layout), - layout_width(env, element3_layout), - layout_width(env, result_layout), + env.alignment_intvalue(layout_interner, result_layout), + layout_width(env, layout_interner, element1_layout), + layout_width(env, layout_interner, element2_layout), + layout_width(env, layout_interner, element3_layout), + layout_width(env, layout_interner, result_layout), dec_a.as_global_value().as_pointer_value().into(), dec_b.as_global_value().as_pointer_value().into(), dec_c.as_global_value().as_pointer_value().into(), @@ -545,6 +566,7 @@ pub(crate) fn list_map3<'a, 'ctx, 'env>( pub(crate) fn list_map4<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, roc_function_call: RocFunctionCall<'ctx>, list1: BasicValueEnum<'ctx>, @@ -557,10 +579,10 @@ pub(crate) fn list_map4<'a, 'ctx, 'env>( element4_layout: &Layout<'a>, result_layout: &Layout<'a>, ) -> BasicValueEnum<'ctx> { - let dec_a = build_dec_wrapper(env, layout_ids, element1_layout); - let dec_b = build_dec_wrapper(env, layout_ids, element2_layout); - let dec_c = build_dec_wrapper(env, layout_ids, element3_layout); - let dec_d = build_dec_wrapper(env, layout_ids, element4_layout); + let dec_a = build_dec_wrapper(env, layout_interner, layout_ids, element1_layout); + let dec_b = build_dec_wrapper(env, layout_interner, layout_ids, element2_layout); + let dec_c = build_dec_wrapper(env, layout_interner, layout_ids, element3_layout); + let dec_d = build_dec_wrapper(env, layout_interner, layout_ids, element4_layout); call_list_bitcode_fn( env, @@ -575,12 +597,12 @@ pub(crate) fn list_map4<'a, 'ctx, 'env>( pass_as_opaque(env, roc_function_call.data), roc_function_call.inc_n_data.into(), roc_function_call.data_is_owned.into(), - env.alignment_intvalue(result_layout), - layout_width(env, element1_layout), - layout_width(env, element2_layout), - layout_width(env, element3_layout), - layout_width(env, element4_layout), - layout_width(env, result_layout), + env.alignment_intvalue(layout_interner, result_layout), + layout_width(env, layout_interner, element1_layout), + layout_width(env, layout_interner, element2_layout), + layout_width(env, layout_interner, element3_layout), + layout_width(env, layout_interner, element4_layout), + layout_width(env, layout_interner, result_layout), dec_a.as_global_value().as_pointer_value().into(), dec_b.as_global_value().as_pointer_value().into(), dec_c.as_global_value().as_pointer_value().into(), @@ -594,25 +616,27 @@ pub(crate) fn list_map4<'a, 'ctx, 'env>( /// List.concat : List elem, List elem -> List elem pub(crate) fn list_concat<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, list1: BasicValueEnum<'ctx>, list2: BasicValueEnum<'ctx>, element_layout: InLayout<'a>, ) -> BasicValueEnum<'ctx> { - let element_layout = env.layout_interner.get(element_layout); + let element_layout = layout_interner.get(element_layout); call_list_bitcode_fn( env, &[list1.into_struct_value(), list2.into_struct_value()], &[ - env.alignment_intvalue(element_layout), - layout_width(env, element_layout), + env.alignment_intvalue(layout_interner, element_layout), + layout_width(env, layout_interner, element_layout), ], BitcodeReturns::List, bitcode::LIST_CONCAT, ) } -pub(crate) fn incrementing_elem_loop<'a, 'ctx, 'env, LoopFn>( +pub(crate) fn incrementing_elem_loop<'a, 'r, 'ctx, 'env, LoopFn>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &'r mut STLayoutInterner<'a>, parent: FunctionValue<'ctx>, element_layout: Layout<'a>, ptr: PointerValue<'ctx>, @@ -621,39 +645,49 @@ pub(crate) fn incrementing_elem_loop<'a, 'ctx, 'env, LoopFn>( mut loop_fn: LoopFn, ) -> PointerValue<'ctx> where - LoopFn: FnMut(IntValue<'ctx>, BasicValueEnum<'ctx>), + LoopFn: FnMut(&'r mut STLayoutInterner<'a>, IntValue<'ctx>, BasicValueEnum<'ctx>), { let builder = env.builder; - let element_type = basic_type_from_layout(env, &element_layout); + let element_type = basic_type_from_layout(env, layout_interner, &element_layout); - incrementing_index_loop(env, parent, len, index_name, |index| { - // The pointer to the element in the list - let element_ptr = - unsafe { builder.new_build_in_bounds_gep(element_type, ptr, &[index], "load_index") }; + incrementing_index_loop( + env, + layout_interner, + parent, + len, + index_name, + |layout_interner, index| { + // The pointer to the element in the list + let element_ptr = unsafe { + builder.new_build_in_bounds_gep(element_type, ptr, &[index], "load_index") + }; - let elem = load_roc_value( - env, - element_layout, - element_ptr, - "incrementing_element_loop_load", - ); + let elem = load_roc_value( + env, + layout_interner, + element_layout, + element_ptr, + "incrementing_element_loop_load", + ); - loop_fn(index, elem); - }) + loop_fn(layout_interner, index, elem); + }, + ) } // This helper simulates a basic for loop, where // and index increments up from 0 to some end value -pub(crate) fn incrementing_index_loop<'a, 'ctx, 'env, LoopFn>( +pub(crate) fn incrementing_index_loop<'a, 'r, 'ctx, 'env, LoopFn>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &'r mut STLayoutInterner<'a>, parent: FunctionValue<'ctx>, end: IntValue<'ctx>, index_name: &str, mut loop_fn: LoopFn, ) -> PointerValue<'ctx> where - LoopFn: FnMut(IntValue<'ctx>), + LoopFn: FnMut(&'r mut STLayoutInterner<'a>, IntValue<'ctx>), { let ctx = env.context; let builder = env.builder; @@ -682,7 +716,7 @@ where builder.build_store(index_alloca, next_index); // The body of the loop - loop_fn(current_index); + loop_fn(layout_interner, current_index); // #index < end let loop_end_cond = bounds_check_comparison(builder, next_index, end); @@ -737,19 +771,20 @@ pub(crate) fn load_list_ptr<'ctx>( pub(crate) fn allocate_list<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, elem_layout: &Layout<'a>, number_of_elements: IntValue<'ctx>, ) -> PointerValue<'ctx> { let builder = env.builder; let len_type = env.ptr_int(); - let elem_bytes = elem_layout.stack_size(env.layout_interner, env.target_info) as u64; + let elem_bytes = elem_layout.stack_size(layout_interner, env.target_info) as u64; let bytes_per_element = len_type.const_int(elem_bytes, false); let number_of_data_bytes = builder.build_int_mul(bytes_per_element, number_of_elements, "data_length"); - let basic_type = basic_type_from_layout(env, elem_layout); - let alignment_bytes = elem_layout.alignment_bytes(env.layout_interner, env.target_info); + let basic_type = basic_type_from_layout(env, layout_interner, elem_layout); + let alignment_bytes = elem_layout.alignment_bytes(layout_interner, env.target_info); allocate_with_refcount_help(env, basic_type, alignment_bytes, number_of_data_bytes) } diff --git a/crates/compiler/gen_llvm/src/llvm/compare.rs b/crates/compiler/gen_llvm/src/llvm/compare.rs index 2d0dde1009..0870c4f2ff 100644 --- a/crates/compiler/gen_llvm/src/llvm/compare.rs +++ b/crates/compiler/gen_llvm/src/llvm/compare.rs @@ -14,7 +14,7 @@ use roc_builtins::bitcode; use roc_builtins::bitcode::{FloatWidth, IntWidth}; use roc_intern::Interner; use roc_module::symbol::Symbol; -use roc_mono::layout::{Builtin, InLayout, Layout, LayoutIds, UnionLayout}; +use roc_mono::layout::{Builtin, InLayout, Layout, LayoutIds, STLayoutInterner, UnionLayout}; use super::build::{load_roc_value, use_roc_value, BuilderExt}; use super::convert::argument_type_from_union_layout; @@ -22,6 +22,7 @@ use super::lowlevel::dec_binop_with_unchecked; pub fn generic_eq<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, lhs_val: BasicValueEnum<'ctx>, rhs_val: BasicValueEnum<'ctx>, @@ -30,6 +31,7 @@ pub fn generic_eq<'a, 'ctx, 'env>( ) -> BasicValueEnum<'ctx> { build_eq( env, + layout_interner, layout_ids, lhs_val, rhs_val, @@ -41,6 +43,7 @@ pub fn generic_eq<'a, 'ctx, 'env>( pub fn generic_neq<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, lhs_val: BasicValueEnum<'ctx>, rhs_val: BasicValueEnum<'ctx>, @@ -49,6 +52,7 @@ pub fn generic_neq<'a, 'ctx, 'env>( ) -> BasicValueEnum<'ctx> { build_neq( env, + layout_interner, layout_ids, lhs_val, rhs_val, @@ -60,6 +64,7 @@ pub fn generic_neq<'a, 'ctx, 'env>( fn build_eq_builtin<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, lhs_val: BasicValueEnum<'ctx>, rhs_val: BasicValueEnum<'ctx>, @@ -125,6 +130,7 @@ fn build_eq_builtin<'a, 'ctx, 'env>( Builtin::Str => str_equal(env, lhs_val, rhs_val), Builtin::List(elem) => build_list_eq( env, + layout_interner, layout_ids, &Layout::Builtin(*builtin), *elem, @@ -137,6 +143,7 @@ fn build_eq_builtin<'a, 'ctx, 'env>( fn build_eq<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, lhs_val: BasicValueEnum<'ctx>, rhs_val: BasicValueEnum<'ctx>, @@ -144,8 +151,8 @@ fn build_eq<'a, 'ctx, 'env>( rhs_layout: &Layout<'a>, when_recursive: WhenRecursive<'a>, ) -> BasicValueEnum<'ctx> { - let lhs_layout = &lhs_layout.runtime_representation(env.layout_interner); - let rhs_layout = &rhs_layout.runtime_representation(env.layout_interner); + let lhs_layout = &lhs_layout.runtime_representation(layout_interner); + let rhs_layout = &rhs_layout.runtime_representation(layout_interner); if lhs_layout != rhs_layout { panic!( "Equality of different layouts; did you have a type mismatch?\n{:?} == {:?}", @@ -154,12 +161,19 @@ fn build_eq<'a, 'ctx, 'env>( } match lhs_layout { - Layout::Builtin(builtin) => { - build_eq_builtin(env, layout_ids, lhs_val, rhs_val, builtin, when_recursive) - } + Layout::Builtin(builtin) => build_eq_builtin( + env, + layout_interner, + layout_ids, + lhs_val, + rhs_val, + builtin, + when_recursive, + ), Layout::Struct { field_layouts, .. } => build_struct_eq( env, + layout_interner, layout_ids, field_layouts, when_recursive, @@ -171,6 +185,7 @@ fn build_eq<'a, 'ctx, 'env>( Layout::Union(union_layout) => build_tag_eq( env, + layout_interner, layout_ids, when_recursive, union_layout, @@ -180,6 +195,7 @@ fn build_eq<'a, 'ctx, 'env>( Layout::Boxed(inner_layout) => build_box_eq( env, + layout_interner, layout_ids, when_recursive, lhs_layout, @@ -196,7 +212,7 @@ fn build_eq<'a, 'ctx, 'env>( WhenRecursive::Loop(union_layout) => { let layout = Layout::Union(union_layout); - let bt = basic_type_from_layout(env, &layout); + let bt = basic_type_from_layout(env, layout_interner, &layout); // cast the i64 pointer to a pointer to block of memory let field1_cast = env.builder.build_pointer_cast( @@ -213,6 +229,7 @@ fn build_eq<'a, 'ctx, 'env>( build_tag_eq( env, + layout_interner, layout_ids, WhenRecursive::Loop(union_layout), &union_layout, @@ -226,6 +243,7 @@ fn build_eq<'a, 'ctx, 'env>( fn build_neq_builtin<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, lhs_val: BasicValueEnum<'ctx>, rhs_val: BasicValueEnum<'ctx>, @@ -297,6 +315,7 @@ fn build_neq_builtin<'a, 'ctx, 'env>( Builtin::List(elem) => { let is_equal = build_list_eq( env, + layout_interner, layout_ids, &Layout::Builtin(*builtin), *elem, @@ -315,6 +334,7 @@ fn build_neq_builtin<'a, 'ctx, 'env>( fn build_neq<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, lhs_val: BasicValueEnum<'ctx>, rhs_val: BasicValueEnum<'ctx>, @@ -330,13 +350,20 @@ fn build_neq<'a, 'ctx, 'env>( } match lhs_layout { - Layout::Builtin(builtin) => { - build_neq_builtin(env, layout_ids, lhs_val, rhs_val, builtin, when_recursive) - } + Layout::Builtin(builtin) => build_neq_builtin( + env, + layout_interner, + layout_ids, + lhs_val, + rhs_val, + builtin, + when_recursive, + ), Layout::Struct { field_layouts, .. } => { let is_equal = build_struct_eq( env, + layout_interner, layout_ids, field_layouts, when_recursive, @@ -353,6 +380,7 @@ fn build_neq<'a, 'ctx, 'env>( Layout::Union(union_layout) => { let is_equal = build_tag_eq( env, + layout_interner, layout_ids, when_recursive, union_layout, @@ -369,6 +397,7 @@ fn build_neq<'a, 'ctx, 'env>( Layout::Boxed(inner_layout) => { let is_equal = build_box_eq( env, + layout_interner, layout_ids, when_recursive, lhs_layout, @@ -392,6 +421,7 @@ fn build_neq<'a, 'ctx, 'env>( fn build_list_eq<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, list_layout: &Layout<'a>, element_layout: InLayout<'a>, @@ -403,7 +433,7 @@ fn build_list_eq<'a, 'ctx, 'env>( let di_location = env.builder.get_current_debug_location().unwrap(); let symbol = Symbol::LIST_EQ; - let element_layout = env.layout_interner.get(element_layout); + let element_layout = layout_interner.get(element_layout); let element_layout = when_recursive.unwrap_recursive_pointer(*element_layout); let fn_name = layout_ids .get(symbol, &element_layout) @@ -412,7 +442,7 @@ fn build_list_eq<'a, 'ctx, 'env>( let function = match env.module.get_function(fn_name.as_str()) { Some(function_value) => function_value, None => { - let arg_type = basic_type_from_layout(env, list_layout); + let arg_type = basic_type_from_layout(env, layout_interner, list_layout); let function_value = crate::llvm::refcounting::build_header_help( env, @@ -423,6 +453,7 @@ fn build_list_eq<'a, 'ctx, 'env>( build_list_eq_help( env, + layout_interner, layout_ids, when_recursive, function_value, @@ -447,6 +478,7 @@ fn build_list_eq<'a, 'ctx, 'env>( fn build_list_eq_help<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, when_recursive: WhenRecursive<'a>, parent: FunctionValue<'ctx>, @@ -509,7 +541,7 @@ fn build_list_eq_help<'a, 'ctx, 'env>( env.builder.position_at_end(then_block); let builder = env.builder; - let element_type = basic_type_from_layout(env, element_layout); + let element_type = basic_type_from_layout(env, layout_interner, element_layout); let ptr_type = element_type.ptr_type(AddressSpace::Generic); let ptr1 = load_list_ptr(env.builder, list1, ptr_type); let ptr2 = load_list_ptr(env.builder, list2, ptr_type); @@ -549,18 +581,19 @@ fn build_list_eq_help<'a, 'ctx, 'env>( let elem_ptr = unsafe { builder.new_build_in_bounds_gep(element_type, ptr1, &[curr_index], "load_index") }; - load_roc_value(env, *element_layout, elem_ptr, "get_elem") + load_roc_value(env, layout_interner, *element_layout, elem_ptr, "get_elem") }; let elem2 = { let elem_ptr = unsafe { builder.new_build_in_bounds_gep(element_type, ptr2, &[curr_index], "load_index") }; - load_roc_value(env, *element_layout, elem_ptr, "get_elem") + load_roc_value(env, layout_interner, *element_layout, elem_ptr, "get_elem") }; let are_equal = build_eq( env, + layout_interner, layout_ids, elem1, elem2, @@ -605,6 +638,7 @@ fn build_list_eq_help<'a, 'ctx, 'env>( fn build_struct_eq<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, field_layouts: &'a [Layout<'a>], when_recursive: WhenRecursive<'a>, @@ -624,7 +658,7 @@ fn build_struct_eq<'a, 'ctx, 'env>( let function = match env.module.get_function(fn_name.as_str()) { Some(function_value) => function_value, None => { - let arg_type = basic_type_from_layout(env, &struct_layout); + let arg_type = basic_type_from_layout(env, layout_interner, &struct_layout); let function_value = crate::llvm::refcounting::build_header_help( env, @@ -635,6 +669,7 @@ fn build_struct_eq<'a, 'ctx, 'env>( build_struct_eq_help( env, + layout_interner, layout_ids, function_value, when_recursive, @@ -659,6 +694,7 @@ fn build_struct_eq<'a, 'ctx, 'env>( fn build_struct_eq_help<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, parent: FunctionValue<'ctx>, when_recursive: WhenRecursive<'a>, @@ -727,7 +763,7 @@ fn build_struct_eq_help<'a, 'ctx, 'env>( WhenRecursive::Loop(union_layout) => { let field_layout = Layout::Union(*union_layout); - let bt = basic_type_from_layout(env, &field_layout); + let bt = basic_type_from_layout(env, layout_interner, &field_layout); // cast the i64 pointer to a pointer to block of memory let field1_cast = env.builder.build_pointer_cast( @@ -744,6 +780,7 @@ fn build_struct_eq_help<'a, 'ctx, 'env>( build_eq( env, + layout_interner, layout_ids, field1_cast.into(), field2_cast.into(), @@ -755,11 +792,14 @@ fn build_struct_eq_help<'a, 'ctx, 'env>( } } } else { + let lhs = use_roc_value(env, layout_interner, *field_layout, field1, "field1"); + let rhs = use_roc_value(env, layout_interner, *field_layout, field2, "field2"); build_eq( env, + layout_interner, layout_ids, - use_roc_value(env, *field_layout, field1, "field1"), - use_roc_value(env, *field_layout, field2, "field2"), + lhs, + rhs, field_layout, field_layout, when_recursive, @@ -791,6 +831,7 @@ fn build_struct_eq_help<'a, 'ctx, 'env>( fn build_tag_eq<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, when_recursive: WhenRecursive<'a>, union_layout: &UnionLayout<'a>, @@ -809,7 +850,7 @@ fn build_tag_eq<'a, 'ctx, 'env>( let function = match env.module.get_function(fn_name.as_str()) { Some(function_value) => function_value, None => { - let arg_type = argument_type_from_union_layout(env, union_layout); + let arg_type = argument_type_from_union_layout(env, layout_interner, union_layout); let function_value = crate::llvm::refcounting::build_header_help( env, @@ -820,6 +861,7 @@ fn build_tag_eq<'a, 'ctx, 'env>( build_tag_eq_help( env, + layout_interner, layout_ids, when_recursive, function_value, @@ -844,6 +886,7 @@ fn build_tag_eq<'a, 'ctx, 'env>( fn build_tag_eq_help<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, when_recursive: WhenRecursive<'a>, parent: FunctionValue<'ctx>, @@ -924,8 +967,8 @@ fn build_tag_eq_help<'a, 'ctx, 'env>( env.builder.position_at_end(compare_tag_ids); - let id1 = get_tag_id(env, parent, union_layout, tag1); - let id2 = get_tag_id(env, parent, union_layout, tag2); + let id1 = get_tag_id(env, layout_interner, parent, union_layout, tag1); + let id2 = get_tag_id(env, layout_interner, parent, union_layout, tag2); // clear the tag_id so we get a pointer to the actual data let tag1 = tag1.into_pointer_value(); @@ -952,6 +995,7 @@ fn build_tag_eq_help<'a, 'ctx, 'env>( let answer = eq_ptr_to_struct( env, + layout_interner, layout_ids, union_layout, Some(when_recursive), @@ -994,8 +1038,8 @@ fn build_tag_eq_help<'a, 'ctx, 'env>( env.builder.position_at_end(compare_tag_ids); - let id1 = get_tag_id(env, parent, union_layout, tag1); - let id2 = get_tag_id(env, parent, union_layout, tag2); + let id1 = get_tag_id(env, layout_interner, parent, union_layout, tag1); + let id2 = get_tag_id(env, layout_interner, parent, union_layout, tag2); // clear the tag_id so we get a pointer to the actual data let tag1 = tag_pointer_clear_tag_id(env, tag1.into_pointer_value()); @@ -1022,6 +1066,7 @@ fn build_tag_eq_help<'a, 'ctx, 'env>( let answer = eq_ptr_to_struct( env, + layout_interner, layout_ids, union_layout, None, @@ -1082,6 +1127,7 @@ fn build_tag_eq_help<'a, 'ctx, 'env>( let answer = eq_ptr_to_struct( env, + layout_interner, layout_ids, union_layout, None, @@ -1150,8 +1196,8 @@ fn build_tag_eq_help<'a, 'ctx, 'env>( env.builder.position_at_end(compare_other); - let id1 = get_tag_id(env, parent, union_layout, tag1); - let id2 = get_tag_id(env, parent, union_layout, tag2); + let id1 = get_tag_id(env, layout_interner, parent, union_layout, tag1); + let id2 = get_tag_id(env, layout_interner, parent, union_layout, tag2); // clear the tag_id so we get a pointer to the actual data let tag1 = tag_pointer_clear_tag_id(env, tag1.into_pointer_value()); @@ -1179,6 +1225,7 @@ fn build_tag_eq_help<'a, 'ctx, 'env>( let answer = eq_ptr_to_struct( env, + layout_interner, layout_ids, union_layout, None, @@ -1217,6 +1264,7 @@ fn build_tag_eq_help<'a, 'ctx, 'env>( let answer = eq_ptr_to_struct( env, + layout_interner, layout_ids, union_layout, None, @@ -1232,6 +1280,7 @@ fn build_tag_eq_help<'a, 'ctx, 'env>( fn eq_ptr_to_struct<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, union_layout: &UnionLayout<'a>, opt_when_recursive: Option>, @@ -1241,7 +1290,7 @@ fn eq_ptr_to_struct<'a, 'ctx, 'env>( ) -> IntValue<'ctx> { let struct_layout = Layout::struct_no_name_order(field_layouts); - let wrapper_type = basic_type_from_layout(env, &struct_layout); + let wrapper_type = basic_type_from_layout(env, layout_interner, &struct_layout); debug_assert!(wrapper_type.is_struct_type()); // cast the opaque pointer to a pointer of the correct shape @@ -1269,6 +1318,7 @@ fn eq_ptr_to_struct<'a, 'ctx, 'env>( build_struct_eq( env, + layout_interner, layout_ids, field_layouts, opt_when_recursive.unwrap_or(WhenRecursive::Loop(*union_layout)), @@ -1282,6 +1332,7 @@ fn eq_ptr_to_struct<'a, 'ctx, 'env>( fn build_box_eq<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, when_recursive: WhenRecursive<'a>, box_layout: &Layout<'a>, @@ -1300,7 +1351,7 @@ fn build_box_eq<'a, 'ctx, 'env>( let function = match env.module.get_function(fn_name.as_str()) { Some(function_value) => function_value, None => { - let arg_type = basic_type_from_layout(env, box_layout); + let arg_type = basic_type_from_layout(env, layout_interner, box_layout); let function_value = crate::llvm::refcounting::build_header_help( env, @@ -1311,6 +1362,7 @@ fn build_box_eq<'a, 'ctx, 'env>( build_box_eq_help( env, + layout_interner, layout_ids, when_recursive, function_value, @@ -1335,6 +1387,7 @@ fn build_box_eq<'a, 'ctx, 'env>( fn build_box_eq_help<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, when_recursive: WhenRecursive<'a>, parent: FunctionValue<'ctx>, @@ -1402,13 +1455,14 @@ fn build_box_eq_help<'a, 'ctx, 'env>( let box1 = box1.into_pointer_value(); let box2 = box2.into_pointer_value(); - let inner_layout = env.layout_interner.get(inner_layout); + let inner_layout = layout_interner.get(inner_layout); - let value1 = load_roc_value(env, *inner_layout, box1, "load_box1"); - let value2 = load_roc_value(env, *inner_layout, box2, "load_box2"); + let value1 = load_roc_value(env, layout_interner, *inner_layout, box1, "load_box1"); + let value2 = load_roc_value(env, layout_interner, *inner_layout, box2, "load_box2"); let is_equal = build_eq( env, + layout_interner, layout_ids, value1, value2, diff --git a/crates/compiler/gen_llvm/src/llvm/convert.rs b/crates/compiler/gen_llvm/src/llvm/convert.rs index c9e44e43fe..70d7a15fbd 100644 --- a/crates/compiler/gen_llvm/src/llvm/convert.rs +++ b/crates/compiler/gen_llvm/src/llvm/convert.rs @@ -11,12 +11,13 @@ use roc_target::TargetInfo; fn basic_type_from_record<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, fields: &[Layout<'_>], ) -> BasicTypeEnum<'ctx> { let mut field_types = Vec::with_capacity_in(fields.len(), env.arena); for field_layout in fields.iter() { - field_types.push(basic_type_from_layout(env, field_layout)); + field_types.push(basic_type_from_layout(env, layout_interner, field_layout)); } env.context @@ -26,6 +27,7 @@ fn basic_type_from_record<'a, 'ctx, 'env>( pub fn basic_type_from_layout<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &'env mut STLayoutInterner<'a>, layout: &Layout<'_>, ) -> BasicTypeEnum<'ctx> { use Layout::*; @@ -34,17 +36,19 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>( Struct { field_layouts: sorted_fields, .. - } => basic_type_from_record(env, sorted_fields), - LambdaSet(lambda_set) => { - basic_type_from_layout(env, &lambda_set.runtime_representation(env.layout_interner)) - } + } => basic_type_from_record(env, layout_interner, sorted_fields), + LambdaSet(lambda_set) => basic_type_from_layout( + env, + layout_interner, + &lambda_set.runtime_representation(layout_interner), + ), Boxed(inner_layout) => { - let inner_layout = env.layout_interner.get(*inner_layout); - let inner_type = basic_type_from_layout(env, inner_layout); + let inner_layout = layout_interner.get(*inner_layout); + let inner_type = basic_type_from_layout(env, layout_interner, inner_layout); inner_type.ptr_type(AddressSpace::Generic).into() } - Union(union_layout) => basic_type_from_union_layout(env, union_layout), + Union(union_layout) => basic_type_from_union_layout(env, layout_interner, union_layout), RecursivePointer => env .context .i64_type() @@ -57,13 +61,14 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>( pub fn struct_type_from_union_layout<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, union_layout: &UnionLayout<'_>, ) -> StructType<'ctx> { use UnionLayout::*; match union_layout { NonRecursive(tags) => { - RocUnion::tagged_from_slices(env.layout_interner, env.context, tags, env.target_info) + RocUnion::tagged_from_slices(layout_interner, env.context, tags, env.target_info) .struct_type() } Recursive(tags) @@ -71,47 +76,35 @@ pub fn struct_type_from_union_layout<'a, 'ctx, 'env>( other_tags: tags, .. } => { if union_layout.stores_tag_id_as_data(env.target_info) { - RocUnion::tagged_from_slices( - env.layout_interner, - env.context, - tags, - env.target_info, - ) - .struct_type() + RocUnion::tagged_from_slices(layout_interner, env.context, tags, env.target_info) + .struct_type() } else { - RocUnion::untagged_from_slices( - env.layout_interner, - env.context, - tags, - env.target_info, - ) - .struct_type() + RocUnion::untagged_from_slices(layout_interner, env.context, tags, env.target_info) + .struct_type() } } NullableUnwrapped { other_fields, .. } => RocUnion::untagged_from_slices( - env.layout_interner, + layout_interner, env.context, &[other_fields], env.target_info, ) .struct_type(), - NonNullableUnwrapped(fields) => RocUnion::untagged_from_slices( - env.layout_interner, - env.context, - &[fields], - env.target_info, - ) - .struct_type(), + NonNullableUnwrapped(fields) => { + RocUnion::untagged_from_slices(layout_interner, env.context, &[fields], env.target_info) + .struct_type() + } } } pub fn basic_type_from_union_layout<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, union_layout: &UnionLayout<'_>, ) -> BasicTypeEnum<'ctx> { use UnionLayout::*; - let struct_type = struct_type_from_union_layout(env, union_layout); + let struct_type = struct_type_from_union_layout(env, layout_interner, union_layout); match union_layout { NonRecursive(_) => struct_type.into(), @@ -153,34 +146,38 @@ pub fn basic_type_from_builtin<'a, 'ctx, 'env>( /// is not currently implemented pub fn argument_type_from_layout<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout: &Layout<'_>, ) -> BasicTypeEnum<'ctx> { use Layout::*; match layout { - LambdaSet(lambda_set) => { - argument_type_from_layout(env, &lambda_set.runtime_representation(env.layout_interner)) - } - Union(union_layout) => argument_type_from_union_layout(env, union_layout), + LambdaSet(lambda_set) => argument_type_from_layout( + env, + layout_interner, + &lambda_set.runtime_representation(layout_interner), + ), + Union(union_layout) => argument_type_from_union_layout(env, layout_interner, union_layout), Builtin(_) => { - let base = basic_type_from_layout(env, layout); + let base = basic_type_from_layout(env, layout_interner, layout); - if layout.is_passed_by_reference(env.layout_interner, env.target_info) { + if layout.is_passed_by_reference(layout_interner, env.target_info) { base.ptr_type(AddressSpace::Generic).into() } else { base } } - other => basic_type_from_layout(env, other), + other => basic_type_from_layout(env, layout_interner, other), } } /// Non-recursive tag unions are stored on the stack, but passed by-reference pub fn argument_type_from_union_layout<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, union_layout: &UnionLayout<'_>, ) -> BasicTypeEnum<'ctx> { - let heap_type = basic_type_from_union_layout(env, union_layout); + let heap_type = basic_type_from_union_layout(env, layout_interner, union_layout); if let UnionLayout::NonRecursive(_) = union_layout { heap_type.ptr_type(AddressSpace::Generic).into() diff --git a/crates/compiler/gen_llvm/src/llvm/expect.rs b/crates/compiler/gen_llvm/src/llvm/expect.rs index a0d4c968ac..44d86fbf96 100644 --- a/crates/compiler/gen_llvm/src/llvm/expect.rs +++ b/crates/compiler/gen_llvm/src/llvm/expect.rs @@ -12,7 +12,7 @@ use roc_builtins::bitcode; use roc_intern::Interner; use roc_module::symbol::Symbol; use roc_mono::ir::LookupType; -use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout}; +use roc_mono::layout::{Builtin, Layout, LayoutIds, STLayoutInterner, UnionLayout}; use roc_region::all::Region; use super::build::BuilderExt; @@ -167,6 +167,7 @@ pub(crate) fn notify_parent_dbg(env: &Env, shared_memory: &SharedMemoryPointer) #[allow(clippy::too_many_arguments)] pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, scope: &Scope<'a, 'ctx>, layout_ids: &mut LayoutIds<'a>, shared_memory: &SharedMemoryPointer<'ctx>, @@ -201,7 +202,7 @@ pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>( let (value, layout) = load_symbol_and_layout(scope, lookup); let stack_size = env.ptr_int().const_int( - layout.stack_size(env.layout_interner, env.target_info) as u64, + layout.stack_size(layout_interner, env.target_info) as u64, false, ); @@ -214,6 +215,7 @@ pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>( extra_offset = build_clone( env, + layout_interner, layout_ids, original_ptr, cursors, @@ -280,6 +282,7 @@ pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>( #[allow(clippy::too_many_arguments)] fn build_clone<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, ptr: PointerValue<'ctx>, cursors: Cursors<'ctx>, @@ -290,6 +293,7 @@ fn build_clone<'a, 'ctx, 'env>( match layout { Layout::Builtin(builtin) => build_clone_builtin( env, + layout_interner, layout_ids, ptr, cursors, @@ -300,6 +304,7 @@ fn build_clone<'a, 'ctx, 'env>( Layout::Struct { field_layouts, .. } => build_clone_struct( env, + layout_interner, layout_ids, ptr, cursors, @@ -313,7 +318,7 @@ fn build_clone<'a, 'ctx, 'env>( Layout::LambdaSet(_) => cursors.extra_offset, Layout::Union(union_layout) => { - if layout.safe_to_memcpy(env.layout_interner) { + if layout.safe_to_memcpy(layout_interner) { let ptr = unsafe { env.builder.new_build_in_bounds_gep( env.context.i8_type(), @@ -328,12 +333,13 @@ fn build_clone<'a, 'ctx, 'env>( .builder .build_pointer_cast(ptr, ptr_type, "cast_ptr_type"); - store_roc_value(env, layout, ptr, value); + store_roc_value(env, layout_interner, layout, ptr, value); cursors.extra_offset } else { build_clone_tag( env, + layout_interner, layout_ids, ptr, cursors, @@ -349,11 +355,11 @@ fn build_clone<'a, 'ctx, 'env>( build_copy(env, ptr, cursors.offset, cursors.extra_offset.into()); let source = value.into_pointer_value(); - let inner_layout = env.layout_interner.get(inner_layout); - let value = load_roc_value(env, *inner_layout, source, "inner"); + let inner_layout = layout_interner.get(inner_layout); + let value = load_roc_value(env, layout_interner, *inner_layout, source, "inner"); let inner_width = env.ptr_int().const_int( - inner_layout.stack_size(env.layout_interner, env.target_info) as u64, + inner_layout.stack_size(layout_interner, env.target_info) as u64, false, ); @@ -368,6 +374,7 @@ fn build_clone<'a, 'ctx, 'env>( build_clone( env, + layout_interner, layout_ids, ptr, cursors, @@ -385,7 +392,7 @@ fn build_clone<'a, 'ctx, 'env>( WhenRecursive::Loop(union_layout) => { let layout = Layout::Union(union_layout); - let bt = basic_type_from_layout(env, &layout); + let bt = basic_type_from_layout(env, layout_interner, &layout); // cast the i64 pointer to a pointer to block of memory let field1_cast = env.builder.build_pointer_cast( @@ -396,6 +403,7 @@ fn build_clone<'a, 'ctx, 'env>( build_clone_tag( env, + layout_interner, layout_ids, ptr, cursors, @@ -411,6 +419,7 @@ fn build_clone<'a, 'ctx, 'env>( #[allow(clippy::too_many_arguments)] fn build_clone_struct<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, ptr: PointerValue<'ctx>, cursors: Cursors<'ctx>, @@ -420,7 +429,7 @@ fn build_clone_struct<'a, 'ctx, 'env>( ) -> IntValue<'ctx> { let layout = Layout::struct_no_name_order(field_layouts); - if layout.safe_to_memcpy(env.layout_interner) { + if layout.safe_to_memcpy(layout_interner) { build_copy(env, ptr, cursors.offset, value) } else { let mut cursors = cursors; @@ -433,10 +442,11 @@ fn build_clone_struct<'a, 'ctx, 'env>( .build_extract_value(structure, i as _, "extract") .unwrap(); - let field = use_roc_value(env, *field_layout, field, "field"); + let field = use_roc_value(env, layout_interner, *field_layout, field, "field"); let new_extra = build_clone( env, + layout_interner, layout_ids, ptr, cursors, @@ -446,7 +456,7 @@ fn build_clone_struct<'a, 'ctx, 'env>( ); let field_width = env.ptr_int().const_int( - field_layout.stack_size(env.layout_interner, env.target_info) as u64, + field_layout.stack_size(layout_interner, env.target_info) as u64, false, ); @@ -463,6 +473,7 @@ fn build_clone_struct<'a, 'ctx, 'env>( #[allow(clippy::too_many_arguments)] fn build_clone_tag<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, ptr: PointerValue<'ctx>, cursors: Cursors<'ctx>, @@ -505,6 +516,7 @@ fn build_clone_tag<'a, 'ctx, 'env>( build_clone_tag_help( env, + layout_interner, layout_ids, union_layout, when_recursive, @@ -539,11 +551,12 @@ fn build_clone_tag<'a, 'ctx, 'env>( fn load_tag_data<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, union_layout: UnionLayout<'a>, tag_value: PointerValue<'ctx>, tag_type: BasicTypeEnum<'ctx>, ) -> BasicValueEnum<'ctx> { - let union_struct_type = struct_type_from_union_layout(env, &union_layout); + let union_struct_type = struct_type_from_union_layout(env, layout_interner, &union_layout); let raw_data_ptr = env .builder @@ -567,6 +580,7 @@ fn load_tag_data<'a, 'ctx, 'env>( #[allow(clippy::too_many_arguments)] fn build_clone_tag_help<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, union_layout: UnionLayout<'a>, when_recursive: WhenRecursive<'a>, @@ -612,7 +626,7 @@ fn build_clone_tag_help<'a, 'ctx, 'env>( env.builder.build_unreachable(); } NonRecursive(tags) => { - let id = get_tag_id(env, parent, &union_layout, tag_value); + let id = get_tag_id(env, layout_interner, parent, &union_layout, tag_value); let switch_block = env.context.append_basic_block(parent, "switch_block"); env.builder.build_unconditional_branch(switch_block); @@ -628,16 +642,25 @@ fn build_clone_tag_help<'a, 'ctx, 'env>( env.arena.alloc([layout, union_layout.tag_id_layout()]), ); - let basic_type = basic_type_from_layout(env, &layout); + let basic_type = basic_type_from_layout(env, layout_interner, &layout); let data = load_tag_data( env, + layout_interner, union_layout, tag_value.into_pointer_value(), basic_type, ); - let answer = - build_clone(env, layout_ids, ptr, cursors, data, layout, when_recursive); + let answer = build_clone( + env, + layout_interner, + layout_ids, + ptr, + cursors, + data, + layout, + when_recursive, + ); env.builder.build_return(Some(&answer)); @@ -657,7 +680,7 @@ fn build_clone_tag_help<'a, 'ctx, 'env>( } } Recursive(tags) => { - let id = get_tag_id(env, parent, &union_layout, tag_value); + let id = get_tag_id(env, layout_interner, parent, &union_layout, tag_value); let switch_block = env.context.append_basic_block(parent, "switch_block"); env.builder.build_unconditional_branch(switch_block); @@ -682,11 +705,11 @@ fn build_clone_tag_help<'a, 'ctx, 'env>( ) }; - let basic_type = basic_type_from_layout(env, &layout); - let data = load_tag_data(env, union_layout, tag_value, basic_type); + let basic_type = basic_type_from_layout(env, layout_interner, &layout); + let data = load_tag_data(env, layout_interner, union_layout, tag_value, basic_type); let (width, _) = - union_layout.data_size_and_alignment(env.layout_interner, env.target_info); + union_layout.data_size_and_alignment(layout_interner, env.target_info); let cursors = Cursors { offset: extra_offset, @@ -698,8 +721,16 @@ fn build_clone_tag_help<'a, 'ctx, 'env>( }; let when_recursive = WhenRecursive::Loop(union_layout); - let answer = - build_clone(env, layout_ids, ptr, cursors, data, layout, when_recursive); + let answer = build_clone( + env, + layout_interner, + layout_ids, + ptr, + cursors, + data, + layout, + when_recursive, + ); env.builder.build_return(Some(&answer)); @@ -724,10 +755,9 @@ fn build_clone_tag_help<'a, 'ctx, 'env>( build_copy(env, ptr, offset, extra_offset.into()); let layout = Layout::struct_no_name_order(fields); - let basic_type = basic_type_from_layout(env, &layout); + let basic_type = basic_type_from_layout(env, layout_interner, &layout); - let (width, _) = - union_layout.data_size_and_alignment(env.layout_interner, env.target_info); + let (width, _) = union_layout.data_size_and_alignment(layout_interner, env.target_info); let cursors = Cursors { offset: extra_offset, @@ -738,10 +768,19 @@ fn build_clone_tag_help<'a, 'ctx, 'env>( ), }; - let data = load_tag_data(env, union_layout, tag_value, basic_type); + let data = load_tag_data(env, layout_interner, union_layout, tag_value, basic_type); let when_recursive = WhenRecursive::Loop(union_layout); - let answer = build_clone(env, layout_ids, ptr, cursors, data, layout, when_recursive); + let answer = build_clone( + env, + layout_interner, + layout_ids, + ptr, + cursors, + data, + layout, + when_recursive, + ); env.builder.build_return(Some(&answer)); } @@ -752,7 +791,7 @@ fn build_clone_tag_help<'a, 'ctx, 'env>( let switch_block = env.context.append_basic_block(parent, "switch_block"); let null_block = env.context.append_basic_block(parent, "null_block"); - let id = get_tag_id(env, parent, &union_layout, tag_value); + let id = get_tag_id(env, layout_interner, parent, &union_layout, tag_value); let comparison = env .builder @@ -782,10 +821,10 @@ fn build_clone_tag_help<'a, 'ctx, 'env>( }; let layout = Layout::struct_no_name_order(fields); - let basic_type = basic_type_from_layout(env, &layout); + let basic_type = basic_type_from_layout(env, layout_interner, &layout); let (width, _) = - union_layout.data_size_and_alignment(env.layout_interner, env.target_info); + union_layout.data_size_and_alignment(layout_interner, env.target_info); let cursors = Cursors { offset: extra_offset, @@ -797,11 +836,20 @@ fn build_clone_tag_help<'a, 'ctx, 'env>( }; let tag_value = tag_pointer_clear_tag_id(env, tag_value.into_pointer_value()); - let data = load_tag_data(env, union_layout, tag_value, basic_type); + let data = + load_tag_data(env, layout_interner, union_layout, tag_value, basic_type); let when_recursive = WhenRecursive::Loop(union_layout); - let answer = - build_clone(env, layout_ids, ptr, cursors, data, layout, when_recursive); + let answer = build_clone( + env, + layout_interner, + layout_ids, + ptr, + cursors, + data, + layout, + when_recursive, + ); env.builder.build_return(Some(&answer)); @@ -857,14 +905,14 @@ fn build_clone_tag_help<'a, 'ctx, 'env>( build_copy(env, ptr, offset, extra_offset.into()); let layout = Layout::struct_no_name_order(other_fields); - let basic_type = basic_type_from_layout(env, &layout); + let basic_type = basic_type_from_layout(env, layout_interner, &layout); let cursors = Cursors { offset: extra_offset, extra_offset: env.builder.build_int_add( extra_offset, env.ptr_int().const_int( - layout.stack_size(env.layout_interner, env.target_info) as _, + layout.stack_size(layout_interner, env.target_info) as _, false, ), "new_offset", @@ -873,14 +921,23 @@ fn build_clone_tag_help<'a, 'ctx, 'env>( let data = load_tag_data( env, + layout_interner, union_layout, tag_value.into_pointer_value(), basic_type, ); let when_recursive = WhenRecursive::Loop(union_layout); - let answer = - build_clone(env, layout_ids, ptr, cursors, data, layout, when_recursive); + let answer = build_clone( + env, + layout_interner, + layout_ids, + ptr, + cursors, + data, + layout, + when_recursive, + ); env.builder.build_return(Some(&answer)); } @@ -945,6 +1002,7 @@ fn build_copy<'a, 'ctx, 'env>( #[allow(clippy::too_many_arguments)] fn build_clone_builtin<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, ptr: PointerValue<'ctx>, cursors: Cursors<'ctx>, @@ -990,14 +1048,14 @@ fn build_clone_builtin<'a, 'ctx, 'env>( offset = build_copy(env, ptr, offset, len.into()); offset = build_copy(env, ptr, offset, len.into()); - let elem = env.layout_interner.get(elem); + let elem = layout_interner.get(elem); let (element_width, _element_align) = - elem.stack_size_and_alignment(env.layout_interner, env.target_info); + elem.stack_size_and_alignment(layout_interner, env.target_info); let element_width = env.ptr_int().const_int(element_width as _, false); let elements_width = bd.build_int_mul(element_width, len, "elements_width"); - if elem.safe_to_memcpy(env.layout_interner) { + if elem.safe_to_memcpy(layout_interner) { // NOTE we are not actually sure the dest is properly aligned let dest = pointer_at_offset(bd, env.context.i8_type(), ptr, offset); let src = bd.build_pointer_cast( @@ -1012,7 +1070,7 @@ fn build_clone_builtin<'a, 'ctx, 'env>( // We cloned the elements into the extra_offset address. let elements_start_offset = cursors.extra_offset; - let element_type = basic_type_from_layout(env, elem); + let element_type = basic_type_from_layout(env, layout_interner, elem); let elements = bd.build_pointer_cast( elements, element_type.ptr_type(AddressSpace::Generic), @@ -1023,7 +1081,7 @@ fn build_clone_builtin<'a, 'ctx, 'env>( let rest_offset = bd.build_alloca(env.ptr_int(), "rest_offset"); let element_stack_size = env.ptr_int().const_int( - elem.stack_size(env.layout_interner, env.target_info) as u64, + elem.stack_size(layout_interner, env.target_info) as u64, false, ); let rest_start_offset = bd.build_int_add( @@ -1033,7 +1091,7 @@ fn build_clone_builtin<'a, 'ctx, 'env>( ); bd.build_store(rest_offset, rest_start_offset); - let body = |index, element| { + let body = |layout_interner, index, element| { let current_offset = bd.build_int_mul(element_stack_size, index, "current_offset"); let current_offset = @@ -1051,6 +1109,7 @@ fn build_clone_builtin<'a, 'ctx, 'env>( let new_offset = build_clone( env, + layout_interner, layout_ids, ptr, cursors, @@ -1068,7 +1127,16 @@ fn build_clone_builtin<'a, 'ctx, 'env>( .and_then(|b| b.get_parent()) .unwrap(); - incrementing_elem_loop(env, parent, *elem, elements, len, "index", body); + incrementing_elem_loop( + env, + layout_interner, + parent, + *elem, + elements, + len, + "index", + body, + ); bd.new_build_load(env.ptr_int(), rest_offset, "rest_start_offset") .into_int_value() diff --git a/crates/compiler/gen_llvm/src/llvm/lowlevel.rs b/crates/compiler/gen_llvm/src/llvm/lowlevel.rs index b8ef1e375e..cb4a3921ff 100644 --- a/crates/compiler/gen_llvm/src/llvm/lowlevel.rs +++ b/crates/compiler/gen_llvm/src/llvm/lowlevel.rs @@ -13,7 +13,7 @@ use roc_intern::Interner; use roc_module::{low_level::LowLevel, symbol::Symbol}; use roc_mono::{ ir::HigherOrderLowLevel, - layout::{Builtin, LambdaSet, Layout, LayoutIds}, + layout::{Builtin, LambdaSet, Layout, LayoutIds, STLayoutInterner}, }; use roc_target::PtrWidth; @@ -62,6 +62,7 @@ macro_rules! list_element_layout { #[allow(clippy::too_many_arguments)] pub(crate) fn run_low_level<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, scope: &Scope<'a, 'ctx>, parent: FunctionValue<'ctx>, @@ -256,7 +257,8 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>( ); let roc_return_type = - basic_type_from_layout(env, layout).ptr_type(AddressSpace::Generic); + basic_type_from_layout(env, layout_interner, layout) + .ptr_type(AddressSpace::Generic); let roc_return_alloca = env.builder.build_pointer_cast( zig_return_alloca, @@ -264,7 +266,13 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>( "cast_to_roc", ); - load_roc_value(env, *layout, roc_return_alloca, "str_to_num_result") + load_roc_value( + env, + layout_interner, + *layout, + roc_return_alloca, + "str_to_num_result", + ) } } } @@ -286,6 +294,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>( call_bitcode_fn_fixing_for_convention( env, + layout_interner, bitcode_return_type, &[string], layout, @@ -298,7 +307,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>( }; // zig passes the result as a packed integer sometimes, instead of a struct. So we cast - let expected_type = basic_type_from_layout(env, layout); + let expected_type = basic_type_from_layout(env, layout_interner, layout); let actual_type = result.get_type(); if expected_type != actual_type { @@ -487,7 +496,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>( bitcode::STR_GET_SCALAR_UNSAFE, ); - let return_type = basic_type_from_layout(env, layout); + let return_type = basic_type_from_layout(env, layout_interner, layout); let cast_result = env.builder.build_pointer_cast( result, return_type.ptr_type(AddressSpace::Generic), @@ -510,7 +519,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>( match env.target_info.ptr_width() { PtrWidth::Bytes8 => result, PtrWidth::Bytes4 => { - let to = basic_type_from_layout(env, layout); + let to = basic_type_from_layout(env, layout_interner, layout); complex_bitcast_check_size(env, result, to, "to_roc_record") } } @@ -645,6 +654,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>( let result_layout = *layout; list_with_capacity( env, + layout_interner, list_len.into_int_value(), list_element_layout!(result_layout), ) @@ -658,7 +668,13 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>( let element_layout = list_element_layout!(list_layout); - list_concat(env, first_list, second_list, *element_layout) + list_concat( + env, + layout_interner, + first_list, + second_list, + *element_layout, + ) } ListAppendUnsafe => { // List.appendUnsafe : List elem, elem -> List elem @@ -667,7 +683,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>( let original_wrapper = load_symbol(scope, &args[0]).into_struct_value(); let (elem, elem_layout) = load_symbol_and_layout(scope, &args[1]); - list_append_unsafe(env, original_wrapper, elem, elem_layout) + list_append_unsafe(env, layout_interner, original_wrapper, elem, elem_layout) } ListPrepend => { // List.prepend : List elem, elem -> List elem @@ -676,7 +692,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>( let original_wrapper = load_symbol(scope, &args[0]).into_struct_value(); let (elem, elem_layout) = load_symbol_and_layout(scope, &args[1]); - list_prepend(env, original_wrapper, elem, elem_layout) + list_prepend(env, layout_interner, original_wrapper, elem, elem_layout) } ListReserve => { // List.reserve : List elem, Nat -> List elem @@ -686,7 +702,14 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>( let element_layout = list_element_layout!(list_layout); let spare = load_symbol(scope, &args[1]); - list_reserve(env, list, spare, *element_layout, update_mode) + list_reserve( + env, + layout_interner, + list, + spare, + *element_layout, + update_mode, + ) } ListSwap => { // List.swap : List elem, Nat, Nat -> List elem @@ -701,6 +724,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>( let element_layout = list_element_layout!(list_layout); list_swap( env, + layout_interner, original_wrapper, index_1.into_int_value(), index_2.into_int_value(), @@ -720,6 +744,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>( let element_layout = list_element_layout!(list_layout); list_sublist( env, + layout_interner, layout_ids, original_wrapper, start.into_int_value(), @@ -739,6 +764,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>( let element_layout = list_element_layout!(list_layout); list_drop_at( env, + layout_interner, layout_ids, original_wrapper, count.into_int_value(), @@ -763,6 +789,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>( list_get_unsafe( env, + layout_interner, layout_ids, *list_element_layout!(list_layout), element_index.into_int_value(), @@ -774,6 +801,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>( list_replace_unsafe( env, + layout_interner, layout_ids, list, index.into_int_value(), @@ -844,6 +872,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>( let int_type = convert::int_type_from_int_width(env, *int_width); build_int_unary_op( env, + layout_interner, parent, arg.into_int_value(), *int_width, @@ -1033,7 +1062,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>( NumIntCast => { arguments!(arg); - let to = basic_type_from_layout(env, layout).into_int_type(); + let to = basic_type_from_layout(env, layout_interner, layout).into_int_type(); let to_signed = intwidth_from_layout(*layout).is_signed(); env.builder @@ -1047,7 +1076,8 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>( Layout::Builtin(Builtin::Int(width)) => { // Converting from int to float let int_val = arg.into_int_value(); - let dest = basic_type_from_layout(env, layout).into_float_type(); + let dest = + basic_type_from_layout(env, layout_interner, layout).into_float_type(); if width.is_signed() { env.builder @@ -1061,7 +1091,8 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>( } Layout::Builtin(Builtin::Float(_)) => { // Converting from float to float - e.g. F64 to F32, or vice versa - let dest = basic_type_from_layout(env, layout).into_float_type(); + let dest = + basic_type_from_layout(env, layout_interner, layout).into_float_type(); env.builder .build_float_cast(arg.into_float_value(), dest, "cast_float_to_float") @@ -1083,12 +1114,28 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>( Eq => { arguments_with_layouts!((lhs_arg, lhs_layout), (rhs_arg, rhs_layout)); - generic_eq(env, layout_ids, lhs_arg, rhs_arg, lhs_layout, rhs_layout) + generic_eq( + env, + layout_interner, + layout_ids, + lhs_arg, + rhs_arg, + lhs_layout, + rhs_layout, + ) } NotEq => { arguments_with_layouts!((lhs_arg, lhs_layout), (rhs_arg, rhs_layout)); - generic_neq(env, layout_ids, lhs_arg, rhs_arg, lhs_layout, rhs_layout) + generic_neq( + env, + layout_interner, + layout_ids, + lhs_arg, + rhs_arg, + lhs_layout, + rhs_layout, + ) } And => { // The (&&) operator @@ -1137,13 +1184,13 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>( unreachable!("Not used in LLVM backend: {:?}", op); } - Unreachable => match RocReturn::from_layout(env, layout) { + Unreachable => match RocReturn::from_layout(env, layout_interner, layout) { RocReturn::Return => { - let basic_type = basic_type_from_layout(env, layout); + let basic_type = basic_type_from_layout(env, layout_interner, layout); basic_type.const_zero() } RocReturn::ByPointer => { - let basic_type = basic_type_from_layout(env, layout); + let basic_type = basic_type_from_layout(env, layout_interner, layout); let ptr = env.builder.build_alloca(basic_type, "unreachable_alloca"); env.builder.build_store(ptr, basic_type.const_zero()); @@ -1817,6 +1864,7 @@ fn int_type_signed_min(int_type: IntType) -> IntValue { fn build_int_unary_op<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, parent: FunctionValue<'ctx>, arg: IntValue<'ctx>, arg_width: IntWidth, @@ -1887,8 +1935,8 @@ fn build_int_unary_op<'a, 'ctx, 'env>( || // Or if the two types are the same, they trivially fit. arg_width == target_int_width; - let return_type = - convert::basic_type_from_layout(env, return_layout).into_struct_type(); + let return_type = convert::basic_type_from_layout(env, layout_interner, return_layout) + .into_struct_type(); if arg_always_fits_in_target { // This is guaranteed to succeed so we can just make it an int cast and let LLVM @@ -1958,8 +2006,9 @@ fn build_int_unary_op<'a, 'ctx, 'env>( intrinsic, ); - let roc_return_type = basic_type_from_layout(env, return_layout) - .ptr_type(AddressSpace::Generic); + let roc_return_type = + basic_type_from_layout(env, layout_interner, return_layout) + .ptr_type(AddressSpace::Generic); let roc_return_alloca = env.builder.build_pointer_cast( zig_return_alloca, @@ -1967,7 +2016,13 @@ fn build_int_unary_op<'a, 'ctx, 'env>( "cast_to_roc", ); - load_roc_value(env, *return_layout, roc_return_alloca, "num_to_int") + load_roc_value( + env, + layout_interner, + *return_layout, + roc_return_alloca, + "num_to_int", + ) } } } @@ -1978,6 +2033,7 @@ fn build_int_unary_op<'a, 'ctx, 'env>( call_bitcode_fn_fixing_for_convention( env, + layout_interner, bitcode_return_type, &[arg.into()], return_layout, @@ -2221,6 +2277,7 @@ fn build_float_unary_op<'a, 'ctx, 'env>( #[allow(clippy::too_many_arguments)] pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, scope: &Scope<'a, 'ctx>, return_layout: &Layout<'a>, @@ -2276,13 +2333,14 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>( Layout::Builtin(Builtin::List(element_layout)), Layout::Builtin(Builtin::List(result_layout)), ) => { - let element_layout = env.layout_interner.get(*element_layout); - let result_layout = env.layout_interner.get(*result_layout); + let element_layout = layout_interner.get(*element_layout); + let result_layout = layout_interner.get(*result_layout); let argument_layouts = &[*element_layout]; let roc_function_call = roc_function_call( env, + layout_interner, layout_ids, function, closure, @@ -2292,7 +2350,14 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>( *result_layout, ); - list_map(env, roc_function_call, list, element_layout, result_layout) + list_map( + env, + layout_interner, + roc_function_call, + list, + element_layout, + result_layout, + ) } _ => unreachable!("invalid list layout"), } @@ -2309,14 +2374,15 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>( Layout::Builtin(Builtin::List(element2_layout)), Layout::Builtin(Builtin::List(result_layout)), ) => { - let element1_layout = env.layout_interner.get(*element1_layout); - let element2_layout = env.layout_interner.get(*element2_layout); - let result_layout = env.layout_interner.get(*result_layout); + let element1_layout = layout_interner.get(*element1_layout); + let element2_layout = layout_interner.get(*element2_layout); + let result_layout = layout_interner.get(*result_layout); let argument_layouts = &[*element1_layout, *element2_layout]; let roc_function_call = roc_function_call( env, + layout_interner, layout_ids, function, closure, @@ -2328,6 +2394,7 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>( list_map2( env, + layout_interner, layout_ids, roc_function_call, list1, @@ -2354,15 +2421,16 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>( Layout::Builtin(Builtin::List(element3_layout)), Layout::Builtin(Builtin::List(result_layout)), ) => { - let element1_layout = env.layout_interner.get(*element1_layout); - let element2_layout = env.layout_interner.get(*element2_layout); - let element3_layout = env.layout_interner.get(*element3_layout); - let result_layout = env.layout_interner.get(*result_layout); + let element1_layout = layout_interner.get(*element1_layout); + let element2_layout = layout_interner.get(*element2_layout); + let element3_layout = layout_interner.get(*element3_layout); + let result_layout = layout_interner.get(*result_layout); let argument_layouts = &[*element1_layout, *element2_layout, *element3_layout]; let roc_function_call = roc_function_call( env, + layout_interner, layout_ids, function, closure, @@ -2374,6 +2442,7 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>( list_map3( env, + layout_interner, layout_ids, roc_function_call, list1, @@ -2410,11 +2479,11 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>( Layout::Builtin(Builtin::List(element4_layout)), Layout::Builtin(Builtin::List(result_layout)), ) => { - let element1_layout = env.layout_interner.get(*element1_layout); - let element2_layout = env.layout_interner.get(*element2_layout); - let element3_layout = env.layout_interner.get(*element3_layout); - let element4_layout = env.layout_interner.get(*element4_layout); - let result_layout = env.layout_interner.get(*result_layout); + let element1_layout = layout_interner.get(*element1_layout); + let element2_layout = layout_interner.get(*element2_layout); + let element3_layout = layout_interner.get(*element3_layout); + let element4_layout = layout_interner.get(*element4_layout); + let result_layout = layout_interner.get(*result_layout); let argument_layouts = &[ *element1_layout, @@ -2425,6 +2494,7 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>( let roc_function_call = roc_function_call( env, + layout_interner, layout_ids, function, closure, @@ -2436,6 +2506,7 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>( list_map4( env, + layout_interner, layout_ids, roc_function_call, list1, @@ -2462,17 +2533,23 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>( Layout::Builtin(Builtin::List(element_layout)) => { use crate::llvm::bitcode::build_compare_wrapper; - let element_layout = env.layout_interner.get(*element_layout); + let element_layout = layout_interner.get(*element_layout); let argument_layouts = &[*element_layout, *element_layout]; - let compare_wrapper = - build_compare_wrapper(env, function, closure_layout, element_layout) - .as_global_value() - .as_pointer_value(); + let compare_wrapper = build_compare_wrapper( + env, + layout_interner, + function, + closure_layout, + element_layout, + ) + .as_global_value() + .as_pointer_value(); let roc_function_call = roc_function_call( env, + layout_interner, layout_ids, function, closure, @@ -2484,6 +2561,7 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>( list_sort_with( env, + layout_interner, roc_function_call, compare_wrapper, list, diff --git a/crates/compiler/gen_llvm/src/llvm/refcounting.rs b/crates/compiler/gen_llvm/src/llvm/refcounting.rs index 782a174488..6425e91ee2 100644 --- a/crates/compiler/gen_llvm/src/llvm/refcounting.rs +++ b/crates/compiler/gen_llvm/src/llvm/refcounting.rs @@ -114,10 +114,11 @@ impl<'ctx> PointerToRefcount<'ctx> { mode: CallMode<'ctx>, layout: &Layout<'a>, env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, ) { match mode { CallMode::Inc(inc_amount) => self.increment(inc_amount, env), - CallMode::Dec => self.decrement(env, layout), + CallMode::Dec => self.decrement(env, layout_interner, layout), } } @@ -125,9 +126,14 @@ impl<'ctx> PointerToRefcount<'ctx> { incref_pointer(env, self.value, amount); } - pub fn decrement<'a, 'env>(&self, env: &Env<'a, 'ctx, 'env>, layout: &Layout<'a>) { + pub fn decrement<'a, 'env>( + &self, + env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, + layout: &Layout<'a>, + ) { let alignment = layout - .allocation_alignment_bytes(env.layout_interner, env.target_info) + .allocation_alignment_bytes(layout_interner, env.target_info) .max(env.target_info.ptr_width() as u32); let context = env.context; @@ -266,6 +272,7 @@ pub fn decref_pointer_check_null<'a, 'ctx, 'env>( fn modify_refcount_struct<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, layouts: &'a [Layout<'a>], mode: Mode, @@ -288,11 +295,12 @@ fn modify_refcount_struct<'a, 'ctx, 'env>( let function = match env.module.get_function(fn_name.as_str()) { Some(function_value) => function_value, None => { - let basic_type = basic_type_from_layout(env, &layout); + let basic_type = basic_type_from_layout(env, layout_interner, &layout); let function_value = build_header(env, basic_type, mode, &fn_name); modify_refcount_struct_help( env, + layout_interner, layout_ids, mode, when_recursive, @@ -314,6 +322,7 @@ fn modify_refcount_struct<'a, 'ctx, 'env>( #[allow(clippy::too_many_arguments)] fn modify_refcount_struct_help<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, mode: Mode, when_recursive: &WhenRecursive<'a>, @@ -339,7 +348,7 @@ fn modify_refcount_struct_help<'a, 'ctx, 'env>( let wrapper_struct = arg_val.into_struct_value(); for (i, field_layout) in layouts.iter().enumerate() { - if field_layout.contains_refcounted(env.layout_interner) { + if field_layout.contains_refcounted(layout_interner) { let raw_value = env .builder .build_extract_value(wrapper_struct, i as u32, "decrement_struct_field") @@ -347,6 +356,7 @@ fn modify_refcount_struct_help<'a, 'ctx, 'env>( let field_value = use_roc_value( env, + layout_interner, *field_layout, raw_value, "load_struct_tag_field_for_decrement", @@ -354,6 +364,7 @@ fn modify_refcount_struct_help<'a, 'ctx, 'env>( modify_refcount_layout_help( env, + layout_interner, layout_ids, mode.to_call_mode(fn_val), when_recursive, @@ -368,36 +379,54 @@ fn modify_refcount_struct_help<'a, 'ctx, 'env>( pub fn increment_refcount_layout<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, inc_amount: u64, value: BasicValueEnum<'ctx>, layout: &Layout<'a>, ) { let amount = env.ptr_int().const_int(inc_amount, false); - increment_n_refcount_layout(env, layout_ids, amount, value, layout); + increment_n_refcount_layout(env, layout_interner, layout_ids, amount, value, layout); } pub fn increment_n_refcount_layout<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, amount: IntValue<'ctx>, value: BasicValueEnum<'ctx>, layout: &Layout<'a>, ) { - modify_refcount_layout(env, layout_ids, CallMode::Inc(amount), value, layout); + modify_refcount_layout( + env, + layout_interner, + layout_ids, + CallMode::Inc(amount), + value, + layout, + ); } pub fn decrement_refcount_layout<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, value: BasicValueEnum<'ctx>, layout: &Layout<'a>, ) { - modify_refcount_layout(env, layout_ids, CallMode::Dec, value, layout); + modify_refcount_layout( + env, + layout_interner, + layout_ids, + CallMode::Dec, + value, + layout, + ); } fn modify_refcount_builtin<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, mode: Mode, when_recursive: &WhenRecursive<'a>, @@ -408,13 +437,25 @@ fn modify_refcount_builtin<'a, 'ctx, 'env>( match builtin { List(element_layout) => { - let function = - modify_refcount_list(env, layout_ids, mode, when_recursive, *element_layout); + let function = modify_refcount_list( + env, + layout_interner, + layout_ids, + mode, + when_recursive, + *element_layout, + ); Some(function) } - Str => Some(modify_refcount_str(env, layout_ids, mode, layout)), + Str => Some(modify_refcount_str( + env, + layout_interner, + layout_ids, + mode, + layout, + )), _ => { debug_assert!(!builtin.is_refcounted()); @@ -425,6 +466,7 @@ fn modify_refcount_builtin<'a, 'ctx, 'env>( fn modify_refcount_layout<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, call_mode: CallMode<'ctx>, value: BasicValueEnum<'ctx>, @@ -432,6 +474,7 @@ fn modify_refcount_layout<'a, 'ctx, 'env>( ) { modify_refcount_layout_help( env, + layout_interner, layout_ids, call_mode, &WhenRecursive::Unreachable, @@ -442,6 +485,7 @@ fn modify_refcount_layout<'a, 'ctx, 'env>( fn modify_refcount_layout_help<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, call_mode: CallMode<'ctx>, when_recursive: &WhenRecursive<'a>, @@ -455,6 +499,7 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>( let function = match modify_refcount_layout_build_function( env, + layout_interner, layout_ids, mode, when_recursive, @@ -472,7 +517,7 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>( WhenRecursive::Loop(union_layout) => { let layout = Layout::Union(*union_layout); - let bt = basic_type_from_layout(env, &layout); + let bt = basic_type_from_layout(env, layout_interner, &layout); // cast the i64 pointer to a pointer to block of memory let field_cast = env.builder.build_pointer_cast( @@ -519,6 +564,7 @@ fn call_help<'a, 'ctx, 'env>( fn modify_refcount_layout_build_function<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, mode: Mode, when_recursive: &WhenRecursive<'a>, @@ -527,12 +573,18 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>( use Layout::*; match layout { - Builtin(builtin) => { - modify_refcount_builtin(env, layout_ids, mode, when_recursive, layout, builtin) - } + Builtin(builtin) => modify_refcount_builtin( + env, + layout_interner, + layout_ids, + mode, + when_recursive, + layout, + builtin, + ), Boxed(inner) => { - let function = modify_refcount_boxed(env, layout_ids, mode, *inner); + let function = modify_refcount_boxed(env, layout_interner, layout_ids, mode, *inner); Some(function) } @@ -547,8 +599,14 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>( } NonRecursive(tags) => { - let function = - modify_refcount_nonrecursive(env, layout_ids, mode, when_recursive, tags); + let function = modify_refcount_nonrecursive( + env, + layout_interner, + layout_ids, + mode, + when_recursive, + tags, + ); Some(function) } @@ -556,6 +614,7 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>( _ => { let function = build_rec_union( env, + layout_interner, layout_ids, mode, &WhenRecursive::Loop(*variant), @@ -568,8 +627,14 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>( } Struct { field_layouts, .. } => { - let function = - modify_refcount_struct(env, layout_ids, field_layouts, mode, when_recursive); + let function = modify_refcount_struct( + env, + layout_interner, + layout_ids, + field_layouts, + mode, + when_recursive, + ); Some(function) } @@ -583,6 +648,7 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>( let function = modify_refcount_layout_build_function( env, + layout_interner, layout_ids, mode, when_recursive, @@ -594,16 +660,18 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>( }, LambdaSet(lambda_set) => modify_refcount_layout_build_function( env, + layout_interner, layout_ids, mode, when_recursive, - &lambda_set.runtime_representation(env.layout_interner), + &lambda_set.runtime_representation(layout_interner), ), } } fn modify_refcount_list<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, mode: Mode, when_recursive: &WhenRecursive<'a>, @@ -612,9 +680,9 @@ fn modify_refcount_list<'a, 'ctx, 'env>( let block = env.builder.get_insert_block().expect("to be in a function"); let di_location = env.builder.get_current_debug_location().unwrap(); - let element_layout = env.layout_interner.get(element_layout); + let element_layout = layout_interner.get(element_layout); let element_layout = when_recursive.unwrap_recursive_pointer(*element_layout); - let element_layout = env.layout_interner.insert(env.arena.alloc(element_layout)); + let element_layout = layout_interner.insert(env.arena.alloc(element_layout)); let list_layout = &Layout::Builtin(Builtin::List(element_layout)); let (_, fn_name) = function_name_from_mode( layout_ids, @@ -628,11 +696,12 @@ fn modify_refcount_list<'a, 'ctx, 'env>( let function = match env.module.get_function(fn_name.as_str()) { Some(function_value) => function_value, None => { - let basic_type = argument_type_from_layout(env, list_layout); + let basic_type = argument_type_from_layout(env, layout_interner, list_layout); let function_value = build_header(env, basic_type, mode, &fn_name); modify_refcount_list_help( env, + layout_interner, layout_ids, mode, when_recursive, @@ -661,6 +730,7 @@ fn mode_to_call_mode(function: FunctionValue<'_>, mode: Mode) -> CallMode<'_> { fn modify_refcount_list_help<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, mode: Mode, when_recursive: &WhenRecursive<'a>, @@ -704,15 +774,17 @@ fn modify_refcount_list_help<'a, 'ctx, 'env>( builder.position_at_end(modification_block); - let element_layout = env.layout_interner.get(element_layout); - if element_layout.contains_refcounted(env.layout_interner) { - let ptr_type = basic_type_from_layout(env, element_layout).ptr_type(AddressSpace::Generic); + let element_layout = layout_interner.get(element_layout); + if element_layout.contains_refcounted(layout_interner) { + let ptr_type = basic_type_from_layout(env, layout_interner, element_layout) + .ptr_type(AddressSpace::Generic); let (len, ptr) = load_list(env.builder, original_wrapper, ptr_type); - let loop_fn = |_index, element| { + let loop_fn = |layout_interner, _index, element| { modify_refcount_layout_help( env, + layout_interner, layout_ids, mode.to_call_mode(fn_val), when_recursive, @@ -723,6 +795,7 @@ fn modify_refcount_list_help<'a, 'ctx, 'env>( incrementing_elem_loop( env, + layout_interner, parent, *element_layout, ptr, @@ -734,7 +807,7 @@ fn modify_refcount_list_help<'a, 'ctx, 'env>( let refcount_ptr = PointerToRefcount::from_list_wrapper(env, original_wrapper); let call_mode = mode_to_call_mode(fn_val, mode); - refcount_ptr.modify(call_mode, layout, env); + refcount_ptr.modify(call_mode, layout, env, layout_interner); builder.build_unconditional_branch(cont_block); @@ -746,6 +819,7 @@ fn modify_refcount_list_help<'a, 'ctx, 'env>( fn modify_refcount_str<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, mode: Mode, layout: &Layout<'a>, @@ -765,10 +839,10 @@ fn modify_refcount_str<'a, 'ctx, 'env>( let function = match env.module.get_function(fn_name.as_str()) { Some(function_value) => function_value, None => { - let basic_type = argument_type_from_layout(env, layout); + let basic_type = argument_type_from_layout(env, layout_interner, layout); let function_value = build_header(env, basic_type, mode, &fn_name); - modify_refcount_str_help(env, mode, layout, function_value); + modify_refcount_str_help(env, layout_interner, mode, layout, function_value); function_value } @@ -783,6 +857,7 @@ fn modify_refcount_str<'a, 'ctx, 'env>( fn modify_refcount_str_help<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, mode: Mode, layout: &Layout<'a>, fn_val: FunctionValue<'ctx>, @@ -805,17 +880,16 @@ fn modify_refcount_str_help<'a, 'ctx, 'env>( let parent = fn_val; - let arg_val = if Layout::Builtin(Builtin::Str) - .is_passed_by_reference(env.layout_interner, env.target_info) - { - let str_type = zig_str_type(env); - env.builder - .new_build_load(str_type, arg_val.into_pointer_value(), "load_str_to_stack") - } else { - // it's already a struct, just do nothing - debug_assert!(arg_val.is_struct_value()); - arg_val - }; + let arg_val = + if Layout::Builtin(Builtin::Str).is_passed_by_reference(layout_interner, env.target_info) { + let str_type = zig_str_type(env); + env.builder + .new_build_load(str_type, arg_val.into_pointer_value(), "load_str_to_stack") + } else { + // it's already a struct, just do nothing + debug_assert!(arg_val.is_struct_value()); + arg_val + }; let str_wrapper = arg_val.into_struct_value(); let capacity = builder @@ -841,7 +915,7 @@ fn modify_refcount_str_help<'a, 'ctx, 'env>( let refcount_ptr = PointerToRefcount::from_list_wrapper(env, str_wrapper); let call_mode = mode_to_call_mode(fn_val, mode); - refcount_ptr.modify(call_mode, layout, env); + refcount_ptr.modify(call_mode, layout, env, layout_interner); builder.build_unconditional_branch(cont_block); @@ -853,6 +927,7 @@ fn modify_refcount_str_help<'a, 'ctx, 'env>( fn modify_refcount_boxed<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, mode: Mode, inner_layout: InLayout<'a>, @@ -874,10 +949,10 @@ fn modify_refcount_boxed<'a, 'ctx, 'env>( let function = match env.module.get_function(fn_name.as_str()) { Some(function_value) => function_value, None => { - let basic_type = basic_type_from_layout(env, boxed_layout); + let basic_type = basic_type_from_layout(env, layout_interner, boxed_layout); let function_value = build_header(env, basic_type, mode, &fn_name); - modify_refcount_box_help(env, mode, inner_layout, function_value); + modify_refcount_box_help(env, layout_interner, mode, inner_layout, function_value); function_value } @@ -892,6 +967,7 @@ fn modify_refcount_boxed<'a, 'ctx, 'env>( fn modify_refcount_box_help<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, mode: Mode, inner_layout: InLayout<'a>, fn_val: FunctionValue<'ctx>, @@ -915,7 +991,7 @@ fn modify_refcount_box_help<'a, 'ctx, 'env>( let refcount_ptr = PointerToRefcount::from_ptr_to_data(env, boxed); let call_mode = mode_to_call_mode(fn_val, mode); let boxed_layout = Layout::Boxed(inner_layout); - refcount_ptr.modify(call_mode, &boxed_layout, env); + refcount_ptr.modify(call_mode, &boxed_layout, env, layout_interner); // this function returns void builder.build_return(None); @@ -1014,6 +1090,7 @@ enum CallMode<'ctx> { fn build_rec_union<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, mode: Mode, when_recursive: &WhenRecursive<'a>, @@ -1036,11 +1113,12 @@ fn build_rec_union<'a, 'ctx, 'env>( let block = env.builder.get_insert_block().expect("to be in a function"); let di_location = env.builder.get_current_debug_location().unwrap(); - let basic_type = basic_type_from_layout(env, &layout); + let basic_type = basic_type_from_layout(env, layout_interner, &layout); let function_value = build_header(env, basic_type, mode, &fn_name); build_rec_union_help( env, + layout_interner, layout_ids, mode, when_recursive, @@ -1062,6 +1140,7 @@ fn build_rec_union<'a, 'ctx, 'env>( #[allow(clippy::too_many_arguments)] fn build_rec_union_help<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, mode: Mode, when_recursive: &WhenRecursive<'a>, @@ -1091,7 +1170,7 @@ fn build_rec_union_help<'a, 'ctx, 'env>( let parent = fn_val; debug_assert!(arg_val.is_pointer_value()); - let current_tag_id = get_tag_id(env, fn_val, &union_layout, arg_val); + let current_tag_id = get_tag_id(env, layout_interner, fn_val, &union_layout, arg_val); let value_ptr = if union_layout.stores_tag_id_in_pointer(env.target_info) { tag_pointer_clear_tag_id(env, arg_val.into_pointer_value()) } else { @@ -1128,7 +1207,7 @@ fn build_rec_union_help<'a, 'ctx, 'env>( match mode { Mode::Inc => { // inc is cheap; we never recurse - refcount_ptr.modify(call_mode, &layout, env); + refcount_ptr.modify(call_mode, &layout, env, layout_interner); env.builder.build_return(None); } @@ -1145,7 +1224,7 @@ fn build_rec_union_help<'a, 'ctx, 'env>( { env.builder.position_at_end(no_recurse_block); - refcount_ptr.modify(call_mode, &layout, env); + refcount_ptr.modify(call_mode, &layout, env, layout_interner); env.builder.build_return(None); } @@ -1154,6 +1233,7 @@ fn build_rec_union_help<'a, 'ctx, 'env>( build_rec_union_recursive_decrement( env, + layout_interner, layout_ids, when_recursive, parent, @@ -1185,6 +1265,7 @@ fn fields_need_no_refcounting(interner: &STLayoutInterner, field_layouts: &[Layo #[allow(clippy::too_many_arguments)] fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, when_recursive: &WhenRecursive<'a>, parent: FunctionValue<'ctx>, @@ -1205,11 +1286,11 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>( let mut cases = Vec::with_capacity_in(tags.len(), env.arena); let tag_id_int_type = - basic_type_from_layout(env, &union_layout.tag_id_layout()).into_int_type(); + basic_type_from_layout(env, layout_interner, &union_layout.tag_id_layout()).into_int_type(); for (tag_id, field_layouts) in tags.iter().enumerate() { // if none of the fields are or contain anything refcounted, just move on - if fields_need_no_refcounting(env.layout_interner, field_layouts) { + if fields_need_no_refcounting(layout_interner, field_layouts) { continue; } @@ -1217,8 +1298,11 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>( env.builder.position_at_end(block); - let wrapper_type = - basic_type_from_layout(env, &Layout::struct_no_name_order(field_layouts)); + let wrapper_type = basic_type_from_layout( + env, + layout_interner, + &Layout::struct_no_name_order(field_layouts), + ); // cast the opaque pointer to a pointer of the correct shape let struct_ptr = env.builder.build_pointer_cast( @@ -1254,11 +1338,12 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>( debug_assert!(ptr_as_i64_ptr.is_pointer_value()); // therefore we must cast it to our desired type - let union_type = basic_type_from_layout(env, &Layout::Union(union_layout)); + let union_type = + basic_type_from_layout(env, layout_interner, &Layout::Union(union_layout)); let recursive_field_ptr = cast_basic_basic(env.builder, ptr_as_i64_ptr, union_type); deferred_rec.push(recursive_field_ptr); - } else if field_layout.contains_refcounted(env.layout_interner) { + } else if field_layout.contains_refcounted(layout_interner) { let elem_pointer = env .builder .new_build_struct_gep( @@ -1269,8 +1354,13 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>( ) .unwrap(); - let field = - load_roc_value(env, *field_layout, elem_pointer, "decrement_struct_field"); + let field = load_roc_value( + env, + layout_interner, + *field_layout, + elem_pointer, + "decrement_struct_field", + ); deferred_nonrec.push((field, field_layout)); } @@ -1286,13 +1376,19 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>( match decrement_or_reuse { DecOrReuse::Reuse => {} DecOrReuse::Dec => { - refcount_ptr.modify(call_mode, &Layout::Union(union_layout), env); + refcount_ptr.modify( + call_mode, + &Layout::Union(union_layout), + env, + layout_interner, + ); } } for (field, field_layout) in deferred_nonrec { modify_refcount_layout_help( env, + layout_interner, layout_ids, mode.to_call_mode(decrement_fn), when_recursive, @@ -1338,7 +1434,12 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>( // increment/decrement the cons-cell itself if let DecOrReuse::Dec = decrement_or_reuse { - refcount_ptr.modify(call_mode, &Layout::Union(union_layout), env); + refcount_ptr.modify( + call_mode, + &Layout::Union(union_layout), + env, + layout_interner, + ); } } @@ -1366,6 +1467,7 @@ fn union_layout_tags<'a>( pub fn build_reset<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, union_layout: UnionLayout<'a>, ) -> FunctionValue<'ctx> { @@ -1376,7 +1478,14 @@ pub fn build_reset<'a, 'ctx, 'env>( let fn_name = format!("{}_reset", fn_name); let when_recursive = WhenRecursive::Loop(union_layout); - let dec_function = build_rec_union(env, layout_ids, Mode::Dec, &when_recursive, union_layout); + let dec_function = build_rec_union( + env, + layout_interner, + layout_ids, + Mode::Dec, + &when_recursive, + union_layout, + ); let function = match env.module.get_function(fn_name.as_str()) { Some(function_value) => function_value, @@ -1384,11 +1493,13 @@ pub fn build_reset<'a, 'ctx, 'env>( let block = env.builder.get_insert_block().expect("to be in a function"); let di_location = env.builder.get_current_debug_location().unwrap(); - let basic_type = basic_type_from_layout(env, &Layout::Union(union_layout)); + let basic_type = + basic_type_from_layout(env, layout_interner, &Layout::Union(union_layout)); let function_value = build_header(env, basic_type, mode, &fn_name); build_reuse_rec_union_help( env, + layout_interner, layout_ids, &when_recursive, union_layout, @@ -1410,6 +1521,7 @@ pub fn build_reset<'a, 'ctx, 'env>( #[allow(clippy::too_many_arguments)] fn build_reuse_rec_union_help<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, when_recursive: &WhenRecursive<'a>, union_layout: UnionLayout<'a>, @@ -1440,7 +1552,7 @@ fn build_reuse_rec_union_help<'a, 'ctx, 'env>( let parent = reset_function; debug_assert!(arg_val.is_pointer_value()); - let current_tag_id = get_tag_id(env, reset_function, &union_layout, arg_val); + let current_tag_id = get_tag_id(env, layout_interner, reset_function, &union_layout, arg_val); let value_ptr = tag_pointer_clear_tag_id(env, arg_val.into_pointer_value()); // to increment/decrement the cons-cell itself @@ -1478,7 +1590,7 @@ fn build_reuse_rec_union_help<'a, 'ctx, 'env>( { env.builder.position_at_end(no_recurse_block); - refcount_ptr.modify(call_mode, &layout, env); + refcount_ptr.modify(call_mode, &layout, env, layout_interner); env.builder.build_return(None); } @@ -1487,6 +1599,7 @@ fn build_reuse_rec_union_help<'a, 'ctx, 'env>( build_rec_union_recursive_decrement( env, + layout_interner, layout_ids, when_recursive, parent, @@ -1524,6 +1637,7 @@ fn function_name_from_mode<'a>( fn modify_refcount_nonrecursive<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, mode: Mode, when_recursive: &WhenRecursive<'a>, @@ -1547,11 +1661,12 @@ fn modify_refcount_nonrecursive<'a, 'ctx, 'env>( let function = match env.module.get_function(fn_name.as_str()) { Some(function_value) => function_value, None => { - let basic_type = argument_type_from_union_layout(env, &union_layout); + let basic_type = argument_type_from_union_layout(env, layout_interner, &union_layout); let function_value = build_header(env, basic_type, mode, &fn_name); modify_refcount_nonrecursive_help( env, + layout_interner, layout_ids, mode, when_recursive, @@ -1572,6 +1687,7 @@ fn modify_refcount_nonrecursive<'a, 'ctx, 'env>( fn modify_refcount_nonrecursive_help<'a, 'ctx, 'env>( env: &Env<'a, 'ctx, 'env>, + layout_interner: &mut STLayoutInterner<'a>, layout_ids: &mut LayoutIds<'a>, mode: Mode, when_recursive: &WhenRecursive<'a>, @@ -1602,7 +1718,8 @@ fn modify_refcount_nonrecursive_help<'a, 'ctx, 'env>( let union_layout = UnionLayout::NonRecursive(tags); let layout = Layout::Union(union_layout); - let union_struct_type = basic_type_from_layout(env, &layout).into_struct_type(); + let union_struct_type = + basic_type_from_layout(env, layout_interner, &layout).into_struct_type(); // read the tag_id let tag_id_ptr = env @@ -1618,7 +1735,7 @@ fn modify_refcount_nonrecursive_help<'a, 'ctx, 'env>( let tag_id = env .builder .new_build_load( - basic_type_from_layout(env, &union_layout.tag_id_layout()), + basic_type_from_layout(env, layout_interner, &union_layout.tag_id_layout()), tag_id_ptr, "load_tag_id", ) @@ -1639,7 +1756,7 @@ fn modify_refcount_nonrecursive_help<'a, 'ctx, 'env>( // if none of the fields are or contain anything refcounted, just move on if !field_layouts .iter() - .any(|x| x.is_refcounted() || x.contains_refcounted(env.layout_interner)) + .any(|x| x.is_refcounted() || x.contains_refcounted(layout_interner)) { continue; } @@ -1647,8 +1764,11 @@ fn modify_refcount_nonrecursive_help<'a, 'ctx, 'env>( let block = env.context.append_basic_block(parent, "tag_id_modify"); env.builder.position_at_end(block); - let data_struct_type = - basic_type_from_layout(env, &Layout::struct_no_name_order(field_layouts)); + let data_struct_type = basic_type_from_layout( + env, + layout_interner, + &Layout::struct_no_name_order(field_layouts), + ); debug_assert!(data_struct_type.is_struct_type()); let data_struct_type = data_struct_type.into_struct_type(); @@ -1698,20 +1818,24 @@ fn modify_refcount_nonrecursive_help<'a, 'ctx, 'env>( debug_assert!(field_value.is_pointer_value()); // therefore we must cast it to our desired type - let union_type = - basic_type_from_layout(env, &Layout::Union(*recursive_union_layout)); + let union_type = basic_type_from_layout( + env, + layout_interner, + &Layout::Union(*recursive_union_layout), + ); let recursive_ptr_field_value = cast_basic_basic(env.builder, field_value, union_type); modify_refcount_layout_help( env, + layout_interner, layout_ids, mode.to_call_mode(fn_val), when_recursive, recursive_ptr_field_value, &Layout::RecursivePointer, ) - } else if field_layout.contains_refcounted(env.layout_interner) { + } else if field_layout.contains_refcounted(layout_interner) { let field_ptr = env .builder .new_build_struct_gep( @@ -1723,11 +1847,11 @@ fn modify_refcount_nonrecursive_help<'a, 'ctx, 'env>( .unwrap(); let field_value = - if field_layout.is_passed_by_reference(env.layout_interner, env.target_info) { + if field_layout.is_passed_by_reference(layout_interner, env.target_info) { field_ptr.into() } else { env.builder.new_build_load( - basic_type_from_layout(env, field_layout), + basic_type_from_layout(env, layout_interner, field_layout), field_ptr, "field_value", ) @@ -1735,6 +1859,7 @@ fn modify_refcount_nonrecursive_help<'a, 'ctx, 'env>( modify_refcount_layout_help( env, + layout_interner, layout_ids, mode.to_call_mode(fn_val), when_recursive,