diff --git a/crates/compiler/alias_analysis/src/lib.rs b/crates/compiler/alias_analysis/src/lib.rs index 27a3be99478..82c9944c4d7 100644 --- a/crates/compiler/alias_analysis/src/lib.rs +++ b/crates/compiler/alias_analysis/src/lib.rs @@ -510,6 +510,12 @@ fn apply_refcount_operation( builder.add_recursive_touch(block, argument)?; } ModifyRc::DecRef(symbol) => { + // this is almost certainly suboptimal, but not incorrect + let argument = env.symbols[symbol]; + builder.add_recursive_touch(block, argument)?; + } + ModifyRc::Free(symbol) => { + // this is almost certainly suboptimal, but not incorrect let argument = env.symbols[symbol]; builder.add_recursive_touch(block, argument)?; } diff --git a/crates/compiler/builtins/bitcode/src/main.zig b/crates/compiler/builtins/bitcode/src/main.zig index 82bb7237563..a349ce26c31 100644 --- a/crates/compiler/builtins/bitcode/src/main.zig +++ b/crates/compiler/builtins/bitcode/src/main.zig @@ -195,8 +195,10 @@ comptime { exportUtilsFn(utils.test_panic, "test_panic"); exportUtilsFn(utils.increfRcPtrC, "incref_rc_ptr"); exportUtilsFn(utils.decrefRcPtrC, "decref_rc_ptr"); + exportUtilsFn(utils.freeRcPtrC, "free_rc_ptr"); exportUtilsFn(utils.increfDataPtrC, "incref_data_ptr"); exportUtilsFn(utils.decrefDataPtrC, "decref_data_ptr"); + exportUtilsFn(utils.freeDataPtrC, "free_data_ptr"); exportUtilsFn(utils.isUnique, "is_unique"); exportUtilsFn(utils.decrefCheckNullC, "decref_check_null"); exportUtilsFn(utils.allocateWithRefcountC, "allocate_with_refcount"); diff --git a/crates/compiler/builtins/bitcode/src/utils.zig b/crates/compiler/builtins/bitcode/src/utils.zig index 3a2e07b72da..d609aefbf82 100644 --- a/crates/compiler/builtins/bitcode/src/utils.zig +++ b/crates/compiler/builtins/bitcode/src/utils.zig @@ -220,6 +220,29 @@ pub fn increfDataPtrC( return increfRcPtrC(isizes, inc_amount); } +pub fn freeDataPtrC( + bytes_or_null: ?[*]isize, + alignment: u32, +) callconv(.C) void { + var bytes = bytes_or_null orelse return; + + const ptr = @ptrToInt(bytes); + const tag_mask: usize = if (@sizeOf(usize) == 8) 0b111 else 0b11; + const masked_ptr = ptr & ~tag_mask; + + const isizes: [*]isize = @intToPtr([*]isize, masked_ptr); + + return freeRcPtrC(isizes - 1, alignment); +} + +pub fn freeRcPtrC( + bytes_or_null: ?[*]isize, + alignment: u32, +) callconv(.C) void { + var bytes = bytes_or_null orelse return; + return free_ptr_to_refcount(bytes, alignment); +} + pub fn decref( bytes_or_null: ?[*]u8, data_bytes: usize, @@ -236,13 +259,23 @@ pub fn decref( decref_ptr_to_refcount(isizes - 1, alignment); } -inline fn decref_ptr_to_refcount( +inline fn free_ptr_to_refcount( refcount_ptr: [*]isize, alignment: u32, ) void { if (RC_TYPE == Refcount.none) return; const extra_bytes = std.math.max(alignment, @sizeOf(usize)); + // NOTE: we don't even check whether the refcount is "infinity" here! + dealloc(@ptrCast([*]u8, refcount_ptr) - (extra_bytes - @sizeOf(usize)), alignment); +} + +inline fn decref_ptr_to_refcount( + refcount_ptr: [*]isize, + alignment: u32, +) void { + if (RC_TYPE == Refcount.none) return; + if (DEBUG_INCDEC and builtin.target.cpu.arch != .wasm32) { std.debug.print("| decrement {*}: ", .{refcount_ptr}); } @@ -264,13 +297,13 @@ inline fn decref_ptr_to_refcount( } if (refcount == REFCOUNT_ONE_ISIZE) { - dealloc(@ptrCast([*]u8, refcount_ptr) - (extra_bytes - @sizeOf(usize)), alignment); + free_ptr_to_refcount(refcount_ptr, alignment); } }, Refcount.atomic => { var last = @atomicRmw(isize, &refcount_ptr[0], std.builtin.AtomicRmwOp.Sub, 1, Monotonic); if (last == REFCOUNT_ONE_ISIZE) { - dealloc(@ptrCast([*]u8, refcount_ptr) - (extra_bytes - @sizeOf(usize)), alignment); + free_ptr_to_refcount(refcount_ptr, alignment); } }, Refcount.none => unreachable, diff --git a/crates/compiler/builtins/src/bitcode.rs b/crates/compiler/builtins/src/bitcode.rs index dfc6a667716..92869d9fc48 100644 --- a/crates/compiler/builtins/src/bitcode.rs +++ b/crates/compiler/builtins/src/bitcode.rs @@ -393,8 +393,10 @@ pub const UTILS_TEST_PANIC: &str = "roc_builtins.utils.test_panic"; pub const UTILS_ALLOCATE_WITH_REFCOUNT: &str = "roc_builtins.utils.allocate_with_refcount"; pub const UTILS_INCREF_RC_PTR: &str = "roc_builtins.utils.incref_rc_ptr"; pub const UTILS_DECREF_RC_PTR: &str = "roc_builtins.utils.decref_rc_ptr"; +pub const UTILS_FREE_RC_PTR: &str = "roc_builtins.utils.free_rc_ptr"; pub const UTILS_INCREF_DATA_PTR: &str = "roc_builtins.utils.incref_data_ptr"; pub const UTILS_DECREF_DATA_PTR: &str = "roc_builtins.utils.decref_data_ptr"; +pub const UTILS_FREE_DATA_PTR: &str = "roc_builtins.utils.free_data_ptr"; pub const UTILS_IS_UNIQUE: &str = "roc_builtins.utils.is_unique"; pub const UTILS_DECREF_CHECK_NULL: &str = "roc_builtins.utils.decref_check_null"; pub const UTILS_DICT_PSEUDO_SEED: &str = "roc_builtins.utils.dict_pseudo_seed"; diff --git a/crates/compiler/can/src/builtins.rs b/crates/compiler/can/src/builtins.rs index 656f9cd1b42..55004df8b3c 100644 --- a/crates/compiler/can/src/builtins.rs +++ b/crates/compiler/can/src/builtins.rs @@ -87,6 +87,7 @@ macro_rules! map_symbol_to_lowlevel_and_arity { LowLevel::PtrCast => unimplemented!(), LowLevel::PtrStore => unimplemented!(), LowLevel::PtrLoad => unimplemented!(), + LowLevel::PtrClearTagId => unimplemented!(), LowLevel::Alloca => unimplemented!(), LowLevel::RefCountIncRcPtr => unimplemented!(), LowLevel::RefCountDecRcPtr=> unimplemented!(), diff --git a/crates/compiler/gen_dev/src/generic64/mod.rs b/crates/compiler/gen_dev/src/generic64/mod.rs index 90804dbc0f8..2057128396a 100644 --- a/crates/compiler/gen_dev/src/generic64/mod.rs +++ b/crates/compiler/gen_dev/src/generic64/mod.rs @@ -2996,12 +2996,17 @@ impl< ); } - fn build_ptr_to_stack_value( - &mut self, - sym: Symbol, - value: Symbol, - element_layout: InLayout<'a>, - ) { + fn build_ptr_clear_tag_id(&mut self, sym: Symbol, ptr: Symbol) { + let buf = &mut self.buf; + + let ptr_reg = self.storage_manager.load_to_general_reg(buf, &ptr); + let sym_reg = self.storage_manager.claim_general_reg(buf, &sym); + + ASM::mov_reg64_imm64(buf, sym_reg, !0b111); + ASM::and_reg64_reg64_reg64(buf, sym_reg, sym_reg, ptr_reg); + } + + fn build_alloca(&mut self, sym: Symbol, value: Symbol, element_layout: InLayout<'a>) { // 1. acquire some stack space let element_width = self.interner().stack_size(element_layout); let allocation = self.debug_symbol("stack_allocation"); diff --git a/crates/compiler/gen_dev/src/lib.rs b/crates/compiler/gen_dev/src/lib.rs index 25bd620e95e..f624165de0d 100644 --- a/crates/compiler/gen_dev/src/lib.rs +++ b/crates/compiler/gen_dev/src/lib.rs @@ -17,7 +17,7 @@ use roc_module::symbol::{Interns, ModuleId, Symbol}; use roc_mono::code_gen_help::{CallerProc, CodeGenHelp}; use roc_mono::ir::{ BranchInfo, CallType, CrashTag, Expr, HigherOrderLowLevel, JoinPointId, ListLiteralElement, - Literal, Param, Proc, ProcLayout, SelfRecursive, Stmt, + Literal, ModifyRc, Param, Proc, ProcLayout, SelfRecursive, Stmt, }; use roc_mono::layout::{ Builtin, InLayout, LambdaName, Layout, LayoutIds, LayoutInterner, LayoutRepr, STLayoutInterner, @@ -525,6 +525,29 @@ trait Backend<'a> { self.return_symbol(sym, ret_layout); self.free_symbols(stmt); } + Stmt::Refcounting(ModifyRc::Free(symbol), following) => { + let dst = Symbol::DEV_TMP; + + let layout = *self.layout_map().get(symbol).unwrap(); + let alignment_bytes = self.interner().allocation_alignment_bytes(layout); + let alignment = self.debug_symbol("alignment"); + self.load_literal_i32(&alignment, alignment_bytes as i32); + + // NOTE: UTILS_FREE_DATA_PTR clears any tag id bits + + self.build_fn_call( + &dst, + bitcode::UTILS_FREE_DATA_PTR.to_string(), + &[*symbol, alignment], + &[Layout::I64, Layout::I32], + &Layout::UNIT, + ); + + self.free_symbol(&dst); + self.free_symbol(&alignment); + + self.build_stmt(layout_ids, following, ret_layout) + } Stmt::Refcounting(modify, following) => { let sym = modify.get_symbol(); let layout = *self.layout_map().get(&sym).unwrap(); @@ -1605,8 +1628,12 @@ trait Backend<'a> { self.build_ptr_load(*sym, args[0], *ret_layout); } + LowLevel::PtrClearTagId => { + self.build_ptr_clear_tag_id(*sym, args[0]); + } + LowLevel::Alloca => { - self.build_ptr_to_stack_value(*sym, args[0], arg_layouts[0]); + self.build_alloca(*sym, args[0], arg_layouts[0]); } LowLevel::RefCountDecRcPtr => self.build_fn_call( @@ -2247,12 +2274,9 @@ trait Backend<'a> { fn build_ptr_load(&mut self, sym: Symbol, ptr: Symbol, element_layout: InLayout<'a>); - fn build_ptr_to_stack_value( - &mut self, - sym: Symbol, - value: Symbol, - element_layout: InLayout<'a>, - ); + fn build_ptr_clear_tag_id(&mut self, sym: Symbol, ptr: Symbol); + + fn build_alloca(&mut self, sym: Symbol, value: Symbol, element_layout: InLayout<'a>); /// literal_map gets the map from symbol to literal and layout, used for lazy loading and literal folding. fn literal_map(&mut self) -> &mut MutMap, *const InLayout<'a>)>; diff --git a/crates/compiler/gen_llvm/src/llvm/build.rs b/crates/compiler/gen_llvm/src/llvm/build.rs index 3870d5ba388..9d14ab0fe2e 100644 --- a/crates/compiler/gen_llvm/src/llvm/build.rs +++ b/crates/compiler/gen_llvm/src/llvm/build.rs @@ -1180,8 +1180,14 @@ pub(crate) fn build_exp_expr<'a, 'ctx>( let then_block = ctx.append_basic_block(parent, "then_reset"); let else_block = ctx.append_basic_block(parent, "else_decref"); - let refcount_ptr = - PointerToRefcount::from_ptr_to_data(env, tag_pointer_clear_tag_id(env, tag_ptr)); + let refcount_ptr = PointerToRefcount::from_ptr_to_data( + env, + if union_layout.stores_tag_id_in_pointer(env.target_info) { + tag_pointer_clear_tag_id(env, tag_ptr) + } else { + tag_ptr + }, + ); let is_unique = match update_mode { UpdateMode::InPlace => env.context.bool_type().const_int(1, false), @@ -1265,8 +1271,20 @@ pub(crate) fn build_exp_expr<'a, 'ctx>( let not_unique_block = ctx.append_basic_block(parent, "else_decref"); - let refcount_ptr = - PointerToRefcount::from_ptr_to_data(env, tag_pointer_clear_tag_id(env, tag_ptr)); + // reset is only generated for union values + let union_layout = match layout_interner.get_repr(layout) { + LayoutRepr::Union(ul) => ul, + _ => unreachable!(), + }; + + let refcount_ptr = PointerToRefcount::from_ptr_to_data( + env, + if union_layout.stores_tag_id_in_pointer(env.target_info) { + tag_pointer_clear_tag_id(env, tag_ptr) + } else { + tag_ptr + }, + ); let is_unique = match update_mode { UpdateMode::InPlace => env.context.bool_type().const_int(1, false), @@ -2930,6 +2948,39 @@ pub(crate) fn build_exp_stmt<'a, 'ctx>( cont, ) } + + Free(symbol) => { + // unconditionally deallocate the symbol + let (value, layout) = scope.load_symbol_and_layout(symbol); + let alignment = layout_interner.alignment_bytes(layout); + + debug_assert!(value.is_pointer_value()); + let value = value.into_pointer_value(); + + let clear_tag_id = match layout_interner.chase_recursive(layout) { + LayoutRepr::Union(union) => union.stores_tag_id_in_pointer(env.target_info), + _ => false, + }; + + let ptr = if clear_tag_id { + tag_pointer_clear_tag_id(env, value) + } else { + value + }; + + let rc_ptr = PointerToRefcount::from_ptr_to_data(env, ptr); + rc_ptr.deallocate(env, alignment); + + build_exp_stmt( + env, + layout_interner, + layout_ids, + func_spec_solutions, + scope, + parent, + cont, + ) + } } } diff --git a/crates/compiler/gen_llvm/src/llvm/lowlevel.rs b/crates/compiler/gen_llvm/src/llvm/lowlevel.rs index 285f4b929a8..eae0f438584 100644 --- a/crates/compiler/gen_llvm/src/llvm/lowlevel.rs +++ b/crates/compiler/gen_llvm/src/llvm/lowlevel.rs @@ -1325,6 +1325,12 @@ pub(crate) fn run_low_level<'a, 'ctx>( .new_build_load(element_type, ptr.into_pointer_value(), "ptr_load") } + PtrClearTagId => { + arguments!(ptr); + + tag_pointer_clear_tag_id(env, ptr.into_pointer_value()).into() + } + Alloca => { arguments!(initial_value); diff --git a/crates/compiler/gen_llvm/src/llvm/refcounting.rs b/crates/compiler/gen_llvm/src/llvm/refcounting.rs index 06f9e73bf1e..8164e27d380 100644 --- a/crates/compiler/gen_llvm/src/llvm/refcounting.rs +++ b/crates/compiler/gen_llvm/src/llvm/refcounting.rs @@ -14,7 +14,7 @@ use bumpalo::collections::Vec; use inkwell::basic_block::BasicBlock; use inkwell::module::Linkage; use inkwell::types::{AnyTypeEnum, BasicMetadataTypeEnum, BasicType, BasicTypeEnum}; -use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue}; +use inkwell::values::{BasicValueEnum, FunctionValue, InstructionValue, IntValue, PointerValue}; use inkwell::{AddressSpace, IntPredicate}; use roc_module::symbol::Interns; use roc_module::symbol::Symbol; @@ -193,6 +193,14 @@ impl<'ctx> PointerToRefcount<'ctx> { builder.build_return(None); } + + pub fn deallocate<'a, 'env>( + &self, + env: &Env<'a, 'ctx, 'env>, + alignment: u32, + ) -> InstructionValue<'ctx> { + free_pointer(env, self.value, alignment) + } } fn incref_pointer<'ctx>( @@ -216,6 +224,28 @@ fn incref_pointer<'ctx>( ); } +fn free_pointer<'ctx>( + env: &Env<'_, 'ctx, '_>, + pointer: PointerValue<'ctx>, + alignment: u32, +) -> InstructionValue<'ctx> { + let alignment = env.context.i32_type().const_int(alignment as _, false); + call_void_bitcode_fn( + env, + &[ + env.builder + .build_pointer_cast( + pointer, + env.ptr_int().ptr_type(AddressSpace::default()), + "to_isize_ptr", + ) + .into(), + alignment.into(), + ], + roc_builtins::bitcode::UTILS_FREE_RC_PTR, + ) +} + fn decref_pointer<'ctx>(env: &Env<'_, 'ctx, '_>, pointer: PointerValue<'ctx>, alignment: u32) { let alignment = env.context.i32_type().const_int(alignment as _, false); call_void_bitcode_fn( diff --git a/crates/compiler/gen_wasm/src/backend.rs b/crates/compiler/gen_wasm/src/backend.rs index b333a73999e..557cdbecc2d 100644 --- a/crates/compiler/gen_wasm/src/backend.rs +++ b/crates/compiler/gen_wasm/src/backend.rs @@ -1,7 +1,7 @@ use bitvec::vec::BitVec; use bumpalo::collections::{String, Vec}; -use roc_builtins::bitcode::{FloatWidth, IntWidth}; +use roc_builtins::bitcode::{self, FloatWidth, IntWidth}; use roc_collections::all::MutMap; use roc_error_macros::internal_error; use roc_module::low_level::{LowLevel, LowLevelWrapperType}; @@ -719,7 +719,10 @@ impl<'a, 'r> WasmBackend<'a, 'r> { Stmt::Jump(id, arguments) => self.stmt_jump(*id, arguments), - Stmt::Refcounting(modify, following) => self.stmt_refcounting(modify, following), + Stmt::Refcounting(modify, following) => match modify { + ModifyRc::Free(symbol) => self.stmt_refcounting_free(*symbol, following), + _ => self.stmt_refcounting(modify, following), + }, Stmt::Dbg { .. } => todo!("dbg is not implemented in the wasm backend"), Stmt::Expect { .. } => todo!("expect is not implemented in the wasm backend"), @@ -999,6 +1002,43 @@ impl<'a, 'r> WasmBackend<'a, 'r> { self.stmt(rc_stmt); } + fn stmt_refcounting_free(&mut self, value: Symbol, following: &'a Stmt<'a>) { + let layout = self.storage.symbol_layouts[&value]; + let alignment = self.layout_interner.allocation_alignment_bytes(layout); + + // Get pointer and offset + let value_storage = self.storage.get(&value).to_owned(); + let stored_with_local = + self.storage + .ensure_value_has_local(&mut self.code_builder, value, value_storage); + let (tag_local_id, tag_offset) = match stored_with_local { + StoredValue::StackMemory { location, .. } => { + location.local_and_offset(self.storage.stack_frame_pointer) + } + StoredValue::Local { local_id, .. } => (local_id, 0), + StoredValue::VirtualMachineStack { .. } => { + internal_error!("{:?} should have a local variable", value) + } + }; + + // load pointer, and add the offset to the pointer + self.code_builder.get_local(tag_local_id); + + if tag_offset > 0 { + self.code_builder.i32_const(tag_offset as i32); + self.code_builder.i32_add(); + } + + // NOTE: UTILS_FREE_DATA_PTR clears any tag id bits + + // push the allocation's alignment + self.code_builder.i32_const(alignment as i32); + + self.call_host_fn_after_loading_args(bitcode::UTILS_FREE_DATA_PTR, 2, false); + + self.stmt(following); + } + pub fn stmt_internal_error(&mut self, msg: &'a str) { let msg_sym = self.create_symbol("panic_str"); let msg_storage = self.storage.allocate_var( diff --git a/crates/compiler/gen_wasm/src/low_level.rs b/crates/compiler/gen_wasm/src/low_level.rs index f87807a6da6..22810606d9a 100644 --- a/crates/compiler/gen_wasm/src/low_level.rs +++ b/crates/compiler/gen_wasm/src/low_level.rs @@ -1979,6 +1979,19 @@ impl<'a> LowLevelCall<'a> { ); } PtrLoad => backend.expr_unbox(self.ret_symbol, self.arguments[0]), + PtrClearTagId => { + let ptr = self.arguments[0]; + + let ptr_local_id = match backend.storage.get(&ptr) { + StoredValue::Local { local_id, .. } => *local_id, + _ => internal_error!("A pointer will always be an i32"), + }; + + backend.code_builder.get_local(ptr_local_id); + + backend.code_builder.i32_const(-4); // 11111111...1100 + backend.code_builder.i32_and(); + } Alloca => { // Alloca : a -> Ptr a let arg = self.arguments[0]; diff --git a/crates/compiler/load_internal/src/file.rs b/crates/compiler/load_internal/src/file.rs index 9821a6c8831..661feb9bd8e 100644 --- a/crates/compiler/load_internal/src/file.rs +++ b/crates/compiler/load_internal/src/file.rs @@ -3141,6 +3141,7 @@ fn update<'a>( arena, &layout_interner, module_id, + state.target_info, ident_ids, &mut update_mode_ids, &mut state.procedures, diff --git a/crates/compiler/module/src/low_level.rs b/crates/compiler/module/src/low_level.rs index bbb30d075cd..bca0692c50c 100644 --- a/crates/compiler/module/src/low_level.rs +++ b/crates/compiler/module/src/low_level.rs @@ -120,6 +120,7 @@ pub enum LowLevel { PtrCast, PtrStore, PtrLoad, + PtrClearTagId, Alloca, RefCountIncRcPtr, RefCountDecRcPtr, @@ -232,6 +233,7 @@ macro_rules! map_symbol_to_lowlevel { LowLevel::PtrCast => unimplemented!(), LowLevel::PtrStore => unimplemented!(), LowLevel::PtrLoad => unimplemented!(), + LowLevel::PtrClearTagId => unimplemented!(), LowLevel::Alloca => unimplemented!(), LowLevel::RefCountIncRcPtr => unimplemented!(), LowLevel::RefCountDecRcPtr=> unimplemented!(), diff --git a/crates/compiler/mono/src/borrow.rs b/crates/compiler/mono/src/borrow.rs index bd03651ecc2..dc5ad52fc19 100644 --- a/crates/compiler/mono/src/borrow.rs +++ b/crates/compiler/mono/src/borrow.rs @@ -1047,8 +1047,8 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[Ownership] { PtrLoad => arena.alloc_slice_copy(&[owned]), Alloca => arena.alloc_slice_copy(&[owned]), - PtrCast | RefCountIncRcPtr | RefCountDecRcPtr | RefCountIncDataPtr | RefCountDecDataPtr - | RefCountIsUnique => { + PtrClearTagId | PtrCast | RefCountIncRcPtr | RefCountDecRcPtr | RefCountIncDataPtr + | RefCountDecDataPtr | RefCountIsUnique => { unreachable!("Only inserted *after* borrow checking: {:?}", op); } } diff --git a/crates/compiler/mono/src/code_gen_help/mod.rs b/crates/compiler/mono/src/code_gen_help/mod.rs index a79293294fa..2ea7809d207 100644 --- a/crates/compiler/mono/src/code_gen_help/mod.rs +++ b/crates/compiler/mono/src/code_gen_help/mod.rs @@ -141,6 +141,7 @@ impl<'a> CodeGenHelp<'a> { let jp_decref = JoinPointId(self.create_symbol(ident_ids, "jp_decref")); HelperOp::DecRef(jp_decref) } + ModifyRc::Free(_) => unreachable!("free should be handled by the backend directly"), }; let mut ctx = Context { diff --git a/crates/compiler/mono/src/code_gen_help/refcount.rs b/crates/compiler/mono/src/code_gen_help/refcount.rs index 4174698e097..7fcea26f453 100644 --- a/crates/compiler/mono/src/code_gen_help/refcount.rs +++ b/crates/compiler/mono/src/code_gen_help/refcount.rs @@ -118,6 +118,9 @@ pub fn refcount_stmt<'a>( }, } } + ModifyRc::Free(_) => { + unreachable!("free should be handled by the backend directly") + } } } @@ -453,8 +456,10 @@ pub fn refcount_reset_proc_body<'a>( root.arena.alloc(refcount_1_stmt), ); - // a Box never masks bits - let mask_lower_bits = false; + let mask_lower_bits = match layout_interner.get_repr(layout) { + LayoutRepr::Union(ul) => ul.stores_tag_id_in_pointer(root.target_info), + _ => false, + }; // Refcount pointer let rc_ptr_stmt = { @@ -576,8 +581,10 @@ pub fn refcount_resetref_proc_body<'a>( root.arena.alloc(refcount_1_stmt), ); - // a Box never masks bits - let mask_lower_bits = false; + let mask_lower_bits = match layout_interner.get_repr(layout) { + LayoutRepr::Union(ul) => ul.stores_tag_id_in_pointer(root.target_info), + _ => false, + }; // Refcount pointer let rc_ptr_stmt = { @@ -629,39 +636,33 @@ fn rc_ptr_from_data_ptr_help<'a>( addr_sym: Symbol, recursion_ptr: InLayout<'a>, ) -> Stmt<'a> { - use std::ops::Neg; - - // Typecast the structure pointer to an integer - // Backends expect a number Layout to choose the right "subtract" instruction - let as_int_sym = if mask_lower_bits { - root.create_symbol(ident_ids, "as_int") + // symbol of a pointer with any tag id bits cleared + let cleared_sym = if mask_lower_bits { + root.create_symbol(ident_ids, "cleared") } else { - addr_sym + structure }; - let as_int_expr = Expr::Call(Call { + + let clear_tag_id_expr = Expr::Call(Call { call_type: CallType::LowLevel { - op: LowLevel::PtrCast, + op: LowLevel::PtrClearTagId, update_mode: UpdateModeId::BACKEND_DUMMY, }, arguments: root.arena.alloc([structure]), }); - let as_int_stmt = |next| Stmt::Let(as_int_sym, as_int_expr, root.layout_isize, next); + let clear_tag_id_stmt = + |next| Stmt::Let(cleared_sym, clear_tag_id_expr, root.layout_isize, next); - // Mask for lower bits (for tag union id) - let mask_sym = root.create_symbol(ident_ids, "mask"); - let mask_expr = Expr::Literal(Literal::Int( - (root.target_info.ptr_width() as i128).neg().to_ne_bytes(), - )); - let mask_stmt = |next| Stmt::Let(mask_sym, mask_expr, root.layout_isize, next); - - let and_expr = Expr::Call(Call { + // Typecast the structure pointer to an integer + // Backends expect a number Layout to choose the right "subtract" instruction + let as_int_expr = Expr::Call(Call { call_type: CallType::LowLevel { - op: LowLevel::And, + op: LowLevel::PtrCast, update_mode: UpdateModeId::BACKEND_DUMMY, }, - arguments: root.arena.alloc([as_int_sym, mask_sym]), + arguments: root.arena.alloc([cleared_sym]), }); - let and_stmt = |next| Stmt::Let(addr_sym, and_expr, root.layout_isize, next); + let as_int_stmt = |next| Stmt::Let(addr_sym, as_int_expr, root.layout_isize, next); // Pointer size constant let ptr_size_sym = root.create_symbol(ident_ids, "ptr_size"); @@ -691,40 +692,24 @@ fn rc_ptr_from_data_ptr_help<'a>( }); let cast_stmt = |next| Stmt::Let(rc_ptr_sym, cast_expr, recursion_ptr, next); - if mask_lower_bits { - as_int_stmt(root.arena.alloc( + let body = as_int_stmt(root.arena.alloc( + // + ptr_size_stmt(root.arena.alloc( // - mask_stmt(root.arena.alloc( + sub_stmt(root.arena.alloc( // - and_stmt(root.arena.alloc( + cast_stmt(root.arena.alloc( // - ptr_size_stmt(root.arena.alloc( - // - sub_stmt(root.arena.alloc( - // - cast_stmt(root.arena.alloc( - // - following, - )), - )), - )), + following, )), )), - )) + )), + )); + + if mask_lower_bits { + clear_tag_id_stmt(root.arena.alloc(body)) } else { - as_int_stmt(root.arena.alloc( - // - ptr_size_stmt(root.arena.alloc( - // - sub_stmt(root.arena.alloc( - // - cast_stmt(root.arena.alloc( - // - following, - )), - )), - )), - )) + body } } diff --git a/crates/compiler/mono/src/debug/checker.rs b/crates/compiler/mono/src/debug/checker.rs index 1012fa0842c..afb0917cf83 100644 --- a/crates/compiler/mono/src/debug/checker.rs +++ b/crates/compiler/mono/src/debug/checker.rs @@ -716,8 +716,10 @@ impl<'a, 'r> Ctx<'a, 'r> { } fn check_modify_rc(&mut self, rc: ModifyRc) { + use ModifyRc::*; + match rc { - ModifyRc::Inc(sym, _) | ModifyRc::Dec(sym) | ModifyRc::DecRef(sym) => { + Inc(sym, _) | Dec(sym) | DecRef(sym) | Free(sym) => { // TODO: also check that sym layout needs refcounting self.check_sym_exists(sym); } diff --git a/crates/compiler/mono/src/drop_specialization.rs b/crates/compiler/mono/src/drop_specialization.rs index 6639440583c..a4203dec05b 100644 --- a/crates/compiler/mono/src/drop_specialization.rs +++ b/crates/compiler/mono/src/drop_specialization.rs @@ -582,8 +582,9 @@ fn specialize_drops_stmt<'a, 'i>( updated_stmt } } - ModifyRc::DecRef(_) => { - // Inlining has no point, since it doesn't decrement it's children + ModifyRc::DecRef(_) | ModifyRc::Free(_) => { + // These operations are not recursive (the children are not touched) + // so inlining is not useful arena.alloc(Stmt::Refcounting( *rc, specialize_drops_stmt( @@ -1031,8 +1032,10 @@ fn specialize_union<'a, 'i>( )) }), arena.alloc(Stmt::Refcounting( - // TODO this could be replaced by a free if ever added to the IR. - ModifyRc::DecRef(*symbol), + // we know for sure that the allocation is unique at + // this point. Therefore we can free (or maybe reuse) + // without checking the refcount again. + ModifyRc::Free(*symbol), continuation, )), ) @@ -1101,8 +1104,10 @@ fn specialize_boxed<'a, 'i>( // - free the box |_, _, continuation| { arena.alloc(Stmt::Refcounting( - // TODO can be replaced by free if ever added to the IR. - ModifyRc::DecRef(*symbol), + // we know for sure that the allocation is unique at + // this point. Therefore we can free (or maybe reuse) + // without checking the refcount again. + ModifyRc::Free(*symbol), continuation, )) }, @@ -1682,8 +1687,8 @@ fn low_level_no_rc(lowlevel: &LowLevel) -> RC { PtrLoad => RC::NoRc, Alloca => RC::NoRc, - PtrCast | RefCountIncRcPtr | RefCountDecRcPtr | RefCountIncDataPtr | RefCountDecDataPtr - | RefCountIsUnique => { + PtrClearTagId | PtrCast | RefCountIncRcPtr | RefCountDecRcPtr | RefCountIncDataPtr + | RefCountDecDataPtr | RefCountIsUnique => { unreachable!("Only inserted *after* borrow checking: {:?}", lowlevel); } } diff --git a/crates/compiler/mono/src/ir.rs b/crates/compiler/mono/src/ir.rs index 4e417b3cdaf..c9013e78f12 100644 --- a/crates/compiler/mono/src/ir.rs +++ b/crates/compiler/mono/src/ir.rs @@ -1612,6 +1612,9 @@ pub enum ModifyRc { /// sometimes we know we already dealt with the elements (e.g. by copying them all over /// to a new list) and so we can just do a DecRef, which is much cheaper in such a case. DecRef(Symbol), + /// Unconditionally deallocate the memory. For tag union that do pointer tagging (store the tag + /// id in the pointer) the backend has to clear the tag id! + Free(Symbol), } impl ModifyRc { @@ -1641,6 +1644,10 @@ impl ModifyRc { .text("decref ") .append(symbol_to_doc(alloc, symbol, pretty)) .append(";"), + Free(symbol) => alloc + .text("free ") + .append(symbol_to_doc(alloc, symbol, pretty)) + .append(";"), } } @@ -1651,6 +1658,7 @@ impl ModifyRc { Inc(symbol, _) => *symbol, Dec(symbol) => *symbol, DecRef(symbol) => *symbol, + Free(symbol) => *symbol, } } } diff --git a/crates/compiler/mono/src/reset_reuse.rs b/crates/compiler/mono/src/reset_reuse.rs index f6fe8264946..1fb2b581641 100644 --- a/crates/compiler/mono/src/reset_reuse.rs +++ b/crates/compiler/mono/src/reset_reuse.rs @@ -19,7 +19,9 @@ use bumpalo::Bump; use bumpalo::collections::vec::Vec; use bumpalo::collections::CollectIn; use roc_collections::{MutMap, MutSet}; +use roc_module::low_level::LowLevel; use roc_module::symbol::{IdentIds, ModuleId, Symbol}; +use roc_target::TargetInfo; /** Insert reset and reuse operations into the IR. @@ -29,6 +31,7 @@ pub fn insert_reset_reuse_operations<'a, 'i>( arena: &'a Bump, layout_interner: &'i STLayoutInterner<'a>, home: ModuleId, + target_info: TargetInfo, ident_ids: &'i mut IdentIds, update_mode_ids: &'i mut UpdateModeIds, procs: &mut MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>, @@ -42,6 +45,7 @@ pub fn insert_reset_reuse_operations<'a, 'i>( let new_proc = insert_reset_reuse_operations_proc( arena, layout_interner, + target_info, home, ident_ids, update_mode_ids, @@ -55,6 +59,7 @@ pub fn insert_reset_reuse_operations<'a, 'i>( fn insert_reset_reuse_operations_proc<'a, 'i>( arena: &'a Bump, layout_interner: &'i STLayoutInterner<'a>, + target_info: TargetInfo, home: ModuleId, ident_ids: &'i mut IdentIds, update_mode_ids: &'i mut UpdateModeIds, @@ -66,6 +71,7 @@ fn insert_reset_reuse_operations_proc<'a, 'i>( } let mut env = ReuseEnvironment { + target_info, symbol_tags: MutMap::default(), non_unique_symbols: MutSet::default(), reuse_tokens: MutMap::default(), @@ -398,33 +404,83 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>( }) } Stmt::Refcounting(rc, continuation) => { - let reuse_pair = match rc { - ModifyRc::Dec(symbol) | ModifyRc::DecRef(symbol) - if !environment.non_unique_symbols.contains(symbol) => - { + enum SymbolIsUnique { + Never, + Always(Symbol), + MustCheck(Symbol), + } + + let can_reuse = match rc { + ModifyRc::Dec(symbol) | ModifyRc::DecRef(symbol) => { + // can only reuse if the symbol is (potentially) unique + if environment.non_unique_symbols.contains(symbol) { + SymbolIsUnique::Never + } else { + SymbolIsUnique::MustCheck(*symbol) + } + } + ModifyRc::Free(symbol) => { + // a free'd symbol is guaranteed to be unique + SymbolIsUnique::Always(*symbol) + } + ModifyRc::Inc(_, _) => { + // an incremented symbol is never unique + SymbolIsUnique::Never + } + }; + + enum ResetOperation { + Reset, + ResetRef, + ClearTagId, + Nothing, + } + + let reuse_pair = match can_reuse { + SymbolIsUnique::MustCheck(symbol) | SymbolIsUnique::Always(symbol) => { // Get the layout of the symbol from where it is defined. - let layout_option = environment.get_symbol_layout(*symbol); + let layout_option = environment.get_symbol_layout(symbol); // If the symbol is defined in the current proc, we can use the layout from the environment. - match layout_option.clone() { + match layout_option { LayoutOption::Layout(layout) => { match symbol_layout_reusability( layout_interner, environment, - symbol, + &symbol, layout, ) { Reuse::Reusable(union_layout) => { + let (reuse_symbol, reset_op) = match rc { + ModifyRc::Dec(_) => ( + Symbol::new(home, ident_ids.gen_unique()), + ResetOperation::Reset, + ), + ModifyRc::DecRef(_) => ( + Symbol::new(home, ident_ids.gen_unique()), + ResetOperation::ResetRef, + ), + ModifyRc::Free(_) => { + if union_layout + .stores_tag_id_in_pointer(environment.target_info) + { + ( + Symbol::new(home, ident_ids.gen_unique()), + ResetOperation::ClearTagId, + ) + } else { + (symbol, ResetOperation::Nothing) + } + } + _ => unreachable!(), + }; + let reuse_token = ReuseToken { - symbol: Symbol::new(home, ident_ids.gen_unique()), + symbol: reuse_symbol, update_mode_id: update_mode_ids.next_id(), }; - let dec_ref = match rc { - ModifyRc::Dec(_) => false, - ModifyRc::DecRef(_) => true, - _ => unreachable!(), - }; + let owned_layout = **layout; environment.push_reuse_token( arena, @@ -432,7 +488,14 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>( reuse_token, layout, ); - Some((layout, union_layout, *symbol, reuse_token, dec_ref)) + + Some(( + owned_layout, + union_layout, + symbol, + reuse_token, + reset_op, + )) } Reuse::Nonreusable => None, } @@ -440,7 +503,7 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>( _ => None, } } - _ => { + SymbolIsUnique::Never => { // We don't need to do anything for an inc or symbols known to be non-unique. None } @@ -457,7 +520,7 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>( ); // If we inserted a reuse token, we need to insert a reset reuse operation if the reuse token is consumed. - if let Some((layout, union_layout, symbol, reuse_token, dec_ref)) = reuse_pair { + if let Some((layout, union_layout, symbol, reuse_token, reset_op)) = reuse_pair { let stack_reuse_token = environment .peek_reuse_token(&get_reuse_layout_info(layout_interner, union_layout)); @@ -471,29 +534,56 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>( _ => { // The token we inserted is no longer on the stack, it must have been consumed. // So we need to insert a reset operation. - let reset_expr = match dec_ref { - // A decref will be replaced by a resetref. - true => Expr::ResetRef { - symbol, - update_mode: reuse_token.update_mode_id, - }, - // And a dec will be replaced by a reset. - false => Expr::Reset { - symbol, - update_mode: reuse_token.update_mode_id, - }, - }; - - // If we generate a reuse token, we no longer want to use the drop statement anymore. So we just return the reset expression. - // TODO verify if this works for both dec and decref. - // TODO reset probably decrements it's children. So we probably need to create a resetref that only does the token. - return arena.alloc(Stmt::Let( - reuse_token.symbol, - reset_expr, - // TODO not sure what the layout should be for a reset token. Currently it is the layout of the symbol. - *layout, - new_continuation, - )); + match reset_op { + ResetOperation::Reset => { + // a dec will be replaced by a reset. + let reset_expr = Expr::Reset { + symbol, + update_mode: reuse_token.update_mode_id, + }; + + return arena.alloc(Stmt::Let( + reuse_token.symbol, + reset_expr, + layout, + new_continuation, + )); + } + ResetOperation::ResetRef => { + // a decref will be replaced by a resetref. + let reset_expr = Expr::ResetRef { + symbol, + update_mode: reuse_token.update_mode_id, + }; + + return arena.alloc(Stmt::Let( + reuse_token.symbol, + reset_expr, + layout, + new_continuation, + )); + } + ResetOperation::ClearTagId => { + let reset_expr = Expr::Call(crate::ir::Call { + call_type: crate::ir::CallType::LowLevel { + op: LowLevel::PtrClearTagId, + update_mode: update_mode_ids.next_id(), + }, + arguments: arena.alloc([symbol]), + }); + + return arena.alloc(Stmt::Let( + reuse_token.symbol, + reset_expr, + layout, + new_continuation, + )); + } + ResetOperation::Nothing => { + // the reuse token is already in a valid state + return new_continuation; + } + } } } } @@ -661,6 +751,7 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>( // Create a new environment for the body. With everything but the jump reuse tokens. As those should be given by the jump. let mut first_pass_body_environment = ReuseEnvironment { + target_info: environment.target_info, symbol_tags: environment.symbol_tags.clone(), non_unique_symbols: environment.non_unique_symbols.clone(), reuse_tokens: max_reuse_token_symbols.clone(), @@ -824,6 +915,7 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>( let (second_pass_body_environment, second_pass_body) = { // Create a new environment for the body. With everything but the jump reuse tokens. As those should be given by the jump. let mut body_environment = ReuseEnvironment { + target_info: environment.target_info, symbol_tags: environment.symbol_tags.clone(), non_unique_symbols: environment.non_unique_symbols.clone(), reuse_tokens: used_reuse_tokens.clone(), @@ -889,7 +981,8 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>( let mut void_pointer_layout_symbols = Vec::new_in(arena); // See what tokens we can get from the env, if none are available, use a void pointer. - // We process the tokens in reverse order, so that when we consume the tokens we last added, we consume the tokens that are most likely not to be null. + // We process the tokens in reverse order, so that when we consume the tokens we last added, + // we consume the tokens that are most likely not to be null. let tokens = token_layouts_clone .iter() .rev() @@ -1002,7 +1095,7 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>( fn create_ptr_cast(arena: &Bump, symbol: Symbol) -> Expr { Expr::Call(crate::ir::Call { call_type: crate::ir::CallType::LowLevel { - op: roc_module::low_level::LowLevel::PtrCast, + op: LowLevel::PtrCast, update_mode: UpdateModeId::BACKEND_DUMMY, }, arguments: Vec::from_iter_in([symbol], arena).into_bump_slice(), @@ -1029,7 +1122,6 @@ Struct to to check whether two reuse layouts are interchangeable. */ #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] struct TokenLayout { - has_tag: bool, size: u32, alignment: u32, } @@ -1092,8 +1184,9 @@ enum JoinPointReuseTokens<'a> { RemainderSecond(Vec<'a, (&'a InLayout<'a>, TokenLayout)>), } -#[derive(Default, Clone)] +#[derive(Clone)] struct ReuseEnvironment<'a> { + target_info: TargetInfo, symbol_tags: MutMap, non_unique_symbols: MutSet, reuse_tokens: ReuseTokens<'a>, @@ -1322,16 +1415,6 @@ fn get_reuse_layout_info<'a, 'i>( union_layout: UnionLayout<'a>, ) -> TokenLayout { let (size, alignment) = union_layout.data_size_and_alignment(layout_interner); - let has_tag = match union_layout { - UnionLayout::NonRecursive(_) => unreachable!("Non recursive unions should not be reused."), - // The memory for union layouts that has a tag_id can be reused for new allocations with tag_id. - UnionLayout::Recursive(_) | UnionLayout::NullableWrapped { .. } => true, - // The memory for union layouts that have no tag_id can be reused for new allocations without tag_id - UnionLayout::NonNullableUnwrapped(_) | UnionLayout::NullableUnwrapped { .. } => false, - }; - TokenLayout { - has_tag, - size, - alignment, - } + + TokenLayout { size, alignment } } diff --git a/crates/compiler/test_mono/generated/binary_tree_fbip.txt b/crates/compiler/test_mono/generated/binary_tree_fbip.txt index 77de42cdbd8..d8b5457f1a9 100644 --- a/crates/compiler/test_mono/generated/binary_tree_fbip.txt +++ b/crates/compiler/test_mono/generated/binary_tree_fbip.txt @@ -16,23 +16,22 @@ procedure Test.5 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2): if Test.53 then let Test.32 : [, C *self *self] = UnionAtIndex (Id 0) (Index 0) Test.29; let Test.33 : [, C *self *self] = UnionAtIndex (Id 0) (Index 1) Test.29; - joinpoint #Derived_gen.3 #Derived_gen.7: - let #Derived_gen.8 : [C [, C *self *self] *self, ] = lowlevel PtrCast #Derived_gen.7; - let Test.43 : [C [, C *self *self] *self, ] = Reuse #Derived_gen.8 UpdateModeId { id: 1 } TagId(1) Test.33 Test.30; + joinpoint #Derived_gen.3 #Derived_gen.6: + let #Derived_gen.7 : [C [, C *self *self] *self, ] = lowlevel PtrCast #Derived_gen.6; + let Test.43 : [C [, C *self *self] *self, ] = Reuse #Derived_gen.7 UpdateModeId { id: 1 } TagId(1) Test.33 Test.30; let Test.45 : I64 = 1i64; let Test.44 : I64 = CallByName Num.19 Test.31 Test.45; jump Test.41 Test.32 Test.43 Test.44; in let #Derived_gen.4 : Int1 = lowlevel RefCountIsUnique Test.29; if #Derived_gen.4 then - let #Derived_gen.9 : [, C *self *self] = ResetRef { symbol: Test.29, id: UpdateModeId { id: 2 } }; - jump #Derived_gen.3 #Derived_gen.9; + jump #Derived_gen.3 Test.29; else inc Test.32; inc Test.33; decref Test.29; - let #Derived_gen.10 : [, C *self *self] = NullPointer; - jump #Derived_gen.3 #Derived_gen.10; + let #Derived_gen.8 : [, C *self *self] = NullPointer; + jump #Derived_gen.3 #Derived_gen.8; else let Test.48 : U8 = 1i64; let Test.49 : U8 = GetTagId Test.30; @@ -42,7 +41,7 @@ procedure Test.5 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2): let Test.36 : [C [, C *self *self] *self, ] = UnionAtIndex (Id 1) (Index 1) Test.30; let #Derived_gen.5 : Int1 = lowlevel RefCountIsUnique Test.30; if #Derived_gen.5 then - decref Test.30; + free Test.30; jump Test.41 Test.35 Test.36 Test.31; else inc Test.35; diff --git a/crates/compiler/test_mono/generated/choose_correct_recursion_var_under_record.txt b/crates/compiler/test_mono/generated/choose_correct_recursion_var_under_record.txt index 653d6dc3b9e..b52e46a91d9 100644 --- a/crates/compiler/test_mono/generated/choose_correct_recursion_var_under_record.txt +++ b/crates/compiler/test_mono/generated/choose_correct_recursion_var_under_record.txt @@ -90,7 +90,7 @@ procedure Test.2 (Test.6): in let #Derived_gen.2 : Int1 = lowlevel RefCountIsUnique Test.6; if #Derived_gen.2 then - decref Test.6; + free Test.6; jump #Derived_gen.1; else inc Test.7; @@ -108,7 +108,7 @@ procedure Test.2 (Test.6): in let #Derived_gen.4 : Int1 = lowlevel RefCountIsUnique Test.6; if #Derived_gen.4 then - decref Test.6; + free Test.6; jump #Derived_gen.3; else inc Test.9; diff --git a/crates/compiler/test_mono/generated/compose_recursive_lambda_set_productive_nullable_wrapped.txt b/crates/compiler/test_mono/generated/compose_recursive_lambda_set_productive_nullable_wrapped.txt index ca95a51d0b1..6d9e4c3688d 100644 --- a/crates/compiler/test_mono/generated/compose_recursive_lambda_set_productive_nullable_wrapped.txt +++ b/crates/compiler/test_mono/generated/compose_recursive_lambda_set_productive_nullable_wrapped.txt @@ -87,7 +87,7 @@ procedure Test.11 (#Derived_gen.7, #Derived_gen.8): in let #Derived_gen.15 : Int1 = lowlevel RefCountIsUnique #Attr.12; if #Derived_gen.15 then - decref #Attr.12; + free #Attr.12; jump #Derived_gen.14; else inc Test.7; @@ -155,7 +155,7 @@ procedure Test.9 (Test.10, #Attr.12): in let #Derived_gen.13 : Int1 = lowlevel RefCountIsUnique #Attr.12; if #Derived_gen.13 then - decref #Attr.12; + free #Attr.12; jump #Derived_gen.12; else inc Test.7; diff --git a/crates/compiler/test_mono/generated/issue_3669.txt b/crates/compiler/test_mono/generated/issue_3669.txt index 03438ca1040..1b670be63b8 100644 --- a/crates/compiler/test_mono/generated/issue_3669.txt +++ b/crates/compiler/test_mono/generated/issue_3669.txt @@ -15,7 +15,7 @@ procedure Test.2 (#Derived_gen.0): let Test.5 : [, C *self] = UnionAtIndex (Id 0) (Index 0) Test.7; let #Derived_gen.1 : Int1 = lowlevel RefCountIsUnique Test.7; if #Derived_gen.1 then - decref Test.7; + free Test.7; jump Test.13 Test.5; else inc Test.5; diff --git a/crates/compiler/test_mono/generated/issue_4770.txt b/crates/compiler/test_mono/generated/issue_4770.txt index 4f1d14165db..7c010f63343 100644 --- a/crates/compiler/test_mono/generated/issue_4770.txt +++ b/crates/compiler/test_mono/generated/issue_4770.txt @@ -116,7 +116,7 @@ procedure Test.1 (#Derived_gen.0): in let #Derived_gen.7 : Int1 = lowlevel RefCountIsUnique Test.49; if #Derived_gen.7 then - decref Test.49; + free Test.49; jump #Derived_gen.6; else decref Test.49; @@ -161,7 +161,7 @@ procedure Test.1 (#Derived_gen.0): in let #Derived_gen.9 : Int1 = lowlevel RefCountIsUnique Test.51; if #Derived_gen.9 then - decref Test.51; + free Test.51; jump #Derived_gen.8; else inc Test.14; diff --git a/crates/compiler/test_mono/generated/linked_list_filter.txt b/crates/compiler/test_mono/generated/linked_list_filter.txt index e7120f4e91c..988e96f2fa0 100644 --- a/crates/compiler/test_mono/generated/linked_list_filter.txt +++ b/crates/compiler/test_mono/generated/linked_list_filter.txt @@ -22,27 +22,26 @@ procedure Test.2 (#Derived_gen.0, #Derived_gen.1): else let Test.7 : I64 = UnionAtIndex (Id 0) (Index 0) Test.4; let Test.8 : [, C I64 *self] = UnionAtIndex (Id 0) (Index 1) Test.4; - joinpoint #Derived_gen.12 #Derived_gen.15: + joinpoint #Derived_gen.12 #Derived_gen.14: let Test.19 : Int1 = CallByName Num.31 Test.7; if Test.19 then let #Derived_gen.9 : [, C I64 *self] = NullPointer; - let Test.20 : [, C I64 *self] = Reuse #Derived_gen.15 UpdateModeId { id: 1 } TagId(0) Test.7 #Derived_gen.9; + let Test.20 : [, C I64 *self] = Reuse #Derived_gen.14 UpdateModeId { id: 1 } TagId(0) Test.7 #Derived_gen.9; let #Derived_gen.10 : Ptr([, C I64 *self]) = UnionFieldPtrAtIndex (Id 0) (Index 1) Test.20; let #Derived_gen.11 : {} = lowlevel PtrStore #Derived_gen.5 Test.20; jump #Derived_gen.4 Test.8 Test.5 #Derived_gen.10 #Derived_gen.6; else - decref #Derived_gen.15; + decref #Derived_gen.14; jump #Derived_gen.4 Test.8 Test.5 #Derived_gen.5 #Derived_gen.6; in let #Derived_gen.13 : Int1 = lowlevel RefCountIsUnique Test.4; if #Derived_gen.13 then - let #Derived_gen.16 : [, C I64 *self] = ResetRef { symbol: Test.4, id: UpdateModeId { id: 2 } }; - jump #Derived_gen.12 #Derived_gen.16; + jump #Derived_gen.12 Test.4; else inc Test.8; decref Test.4; - let #Derived_gen.17 : [, C I64 *self] = NullPointer; - jump #Derived_gen.12 #Derived_gen.17; + let #Derived_gen.15 : [, C I64 *self] = NullPointer; + jump #Derived_gen.12 #Derived_gen.15; in jump #Derived_gen.4 #Derived_gen.0 #Derived_gen.1 #Derived_gen.2 #Derived_gen.2; diff --git a/crates/compiler/test_mono/generated/linked_list_map.txt b/crates/compiler/test_mono/generated/linked_list_map.txt index 9626e531966..8e57cb49a4e 100644 --- a/crates/compiler/test_mono/generated/linked_list_map.txt +++ b/crates/compiler/test_mono/generated/linked_list_map.txt @@ -22,23 +22,22 @@ procedure Test.2 (#Derived_gen.0, #Derived_gen.1): else let Test.7 : I64 = UnionAtIndex (Id 0) (Index 0) Test.5; let Test.8 : [, C I64 *self] = UnionAtIndex (Id 0) (Index 1) Test.5; - joinpoint #Derived_gen.12 #Derived_gen.15: + joinpoint #Derived_gen.12 #Derived_gen.14: let Test.20 : I64 = CallByName Test.10 Test.7; let #Derived_gen.9 : [, C I64 *self] = NullPointer; - let Test.19 : [, C I64 *self] = Reuse #Derived_gen.15 UpdateModeId { id: 1 } TagId(0) Test.20 #Derived_gen.9; + let Test.19 : [, C I64 *self] = Reuse #Derived_gen.14 UpdateModeId { id: 1 } TagId(0) Test.20 #Derived_gen.9; let #Derived_gen.10 : Ptr([, C I64 *self]) = UnionFieldPtrAtIndex (Id 0) (Index 1) Test.19; let #Derived_gen.11 : {} = lowlevel PtrStore #Derived_gen.5 Test.19; jump #Derived_gen.4 Test.4 Test.8 #Derived_gen.10 #Derived_gen.6; in let #Derived_gen.13 : Int1 = lowlevel RefCountIsUnique Test.5; if #Derived_gen.13 then - let #Derived_gen.16 : [, C I64 *self] = ResetRef { symbol: Test.5, id: UpdateModeId { id: 2 } }; - jump #Derived_gen.12 #Derived_gen.16; + jump #Derived_gen.12 Test.5; else inc Test.8; decref Test.5; - let #Derived_gen.17 : [, C I64 *self] = NullPointer; - jump #Derived_gen.12 #Derived_gen.17; + let #Derived_gen.15 : [, C I64 *self] = NullPointer; + jump #Derived_gen.12 #Derived_gen.15; in jump #Derived_gen.4 #Derived_gen.0 #Derived_gen.1 #Derived_gen.2 #Derived_gen.2; diff --git a/crates/compiler/test_mono/generated/linked_list_reverse.txt b/crates/compiler/test_mono/generated/linked_list_reverse.txt index 00461392a9b..892df1a7132 100644 --- a/crates/compiler/test_mono/generated/linked_list_reverse.txt +++ b/crates/compiler/test_mono/generated/linked_list_reverse.txt @@ -13,19 +13,18 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1): else let Test.9 : I64 = UnionAtIndex (Id 0) (Index 0) Test.8; let Test.10 : [, C I64 *self] = UnionAtIndex (Id 0) (Index 1) Test.8; - joinpoint #Derived_gen.2 #Derived_gen.5: - let Test.21 : [, C I64 *self] = Reuse #Derived_gen.5 UpdateModeId { id: 1 } TagId(0) Test.9 Test.7; + joinpoint #Derived_gen.2 #Derived_gen.4: + let Test.21 : [, C I64 *self] = Reuse #Derived_gen.4 UpdateModeId { id: 1 } TagId(0) Test.9 Test.7; jump Test.18 Test.21 Test.10; in let #Derived_gen.3 : Int1 = lowlevel RefCountIsUnique Test.8; if #Derived_gen.3 then - let #Derived_gen.6 : [, C I64 *self] = ResetRef { symbol: Test.8, id: UpdateModeId { id: 2 } }; - jump #Derived_gen.2 #Derived_gen.6; + jump #Derived_gen.2 Test.8; else inc Test.10; decref Test.8; - let #Derived_gen.7 : [, C I64 *self] = NullPointer; - jump #Derived_gen.2 #Derived_gen.7; + let #Derived_gen.5 : [, C I64 *self] = NullPointer; + jump #Derived_gen.2 #Derived_gen.5; in jump Test.18 #Derived_gen.0 #Derived_gen.1; diff --git a/crates/compiler/test_mono/generated/peano1.txt b/crates/compiler/test_mono/generated/peano1.txt index 1d291bf98f9..7ec0b3c2f5f 100644 --- a/crates/compiler/test_mono/generated/peano1.txt +++ b/crates/compiler/test_mono/generated/peano1.txt @@ -17,7 +17,7 @@ procedure Test.0 (): let #Derived_gen.1 : Int1 = lowlevel RefCountIsUnique Test.2; if #Derived_gen.1 then dec Test.13; - decref Test.2; + free Test.2; jump #Derived_gen.0; else decref Test.2; diff --git a/crates/compiler/test_mono/generated/peano2.txt b/crates/compiler/test_mono/generated/peano2.txt index e4d53cc3be9..f090c272ddc 100644 --- a/crates/compiler/test_mono/generated/peano2.txt +++ b/crates/compiler/test_mono/generated/peano2.txt @@ -22,7 +22,7 @@ procedure Test.0 (): in let #Derived_gen.1 : Int1 = lowlevel RefCountIsUnique Test.2; if #Derived_gen.1 then - decref Test.2; + free Test.2; jump #Derived_gen.0; else inc Test.12; diff --git a/crates/compiler/test_mono/generated/polymorphic_expression_unification.txt b/crates/compiler/test_mono/generated/polymorphic_expression_unification.txt index 8984da0b47e..de6d1acdc53 100644 --- a/crates/compiler/test_mono/generated/polymorphic_expression_unification.txt +++ b/crates/compiler/test_mono/generated/polymorphic_expression_unification.txt @@ -37,7 +37,7 @@ procedure Test.0 (): let #Derived_gen.1 : Int1 = lowlevel RefCountIsUnique Test.15; if #Derived_gen.1 then dec Test.16; - decref Test.15; + free Test.15; jump #Derived_gen.0; else decref Test.15; diff --git a/crates/compiler/test_mono/generated/rb_tree_fbip.txt b/crates/compiler/test_mono/generated/rb_tree_fbip.txt index e2db544d2d9..28f4d749260 100644 --- a/crates/compiler/test_mono/generated/rb_tree_fbip.txt +++ b/crates/compiler/test_mono/generated/rb_tree_fbip.txt @@ -30,13 +30,13 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2): let Test.18 : I64 = UnionAtIndex (Id 1) (Index 1) Test.9; let Test.19 : [C *self I64 *self I32 Int1, ] = UnionAtIndex (Id 1) (Index 2) Test.9; let Test.17 : I32 = UnionAtIndex (Id 1) (Index 3) Test.9; - joinpoint #Derived_gen.114 #Derived_gen.119: + joinpoint #Derived_gen.114 #Derived_gen.118: let Test.179 : Int1 = CallByName Num.22 Test.10 Test.17; if Test.179 then - joinpoint Test.238 #Derived_gen.181: + joinpoint Test.238 #Derived_gen.166: let Test.232 : Int1 = false; let #Derived_gen.10 : [C *self I64 *self I32 Int1, ] = NullPointer; - let Test.231 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.181 UpdateModeId { id: 56 } TagId(1) #Derived_gen.10 Test.18 Test.19 Test.17 Test.232; + let Test.231 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.166 UpdateModeId { id: 56 } TagId(1) #Derived_gen.10 Test.18 Test.19 Test.17 Test.232; let #Derived_gen.11 : Ptr([C *self I64 *self I32 Int1, ]) = UnionFieldPtrAtIndex (Id 1) (Index 0) Test.231; let #Derived_gen.12 : {} = lowlevel PtrStore #Derived_gen.6 Test.231; jump #Derived_gen.5 Test.16 Test.10 Test.11 #Derived_gen.11 #Derived_gen.7; @@ -50,7 +50,7 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2): let Test.239 : Int1 = lowlevel Eq Test.235 Test.234; if Test.239 then let Test.180 : [C *self I64 *self I32 Int1, ] = CallByName Test.3 Test.16 Test.10 Test.11; - joinpoint Test.199 #Derived_gen.208: + joinpoint Test.199 #Derived_gen.187: let Test.198 : [C *self I64 *self I32 Int1, ] = UnionAtIndex (Id 1) (Index 0) Test.180; let Test.20 : [C *self I64 *self I32 Int1, ] = UnionAtIndex (Id 1) (Index 0) Test.198; inc Test.20; @@ -61,57 +61,55 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2): let Test.25 : I64 = UnionAtIndex (Id 1) (Index 1) Test.180; let Test.26 : [C *self I64 *self I32 Int1, ] = UnionAtIndex (Id 1) (Index 2) Test.180; let Test.24 : I32 = UnionAtIndex (Id 1) (Index 3) Test.180; - joinpoint #Derived_gen.72 #Derived_gen.211 #Derived_gen.212 #Derived_gen.213: + joinpoint #Derived_gen.72 #Derived_gen.189 #Derived_gen.190 #Derived_gen.191: let Test.186 : Int1 = false; - let Test.183 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.213 UpdateModeId { id: 85 } TagId(1) Test.20 Test.22 Test.23 Test.21 Test.186; + let Test.183 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.191 UpdateModeId { id: 85 } TagId(1) Test.20 Test.22 Test.23 Test.21 Test.186; let Test.185 : Int1 = false; - let Test.184 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.212 UpdateModeId { id: 84 } TagId(1) Test.26 Test.18 Test.19 Test.17 Test.185; + let Test.184 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.190 UpdateModeId { id: 84 } TagId(1) Test.26 Test.18 Test.19 Test.17 Test.185; let Test.182 : Int1 = true; - let Test.181 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.211 UpdateModeId { id: 83 } TagId(1) Test.183 Test.25 Test.184 Test.24 Test.182; + let Test.181 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.189 UpdateModeId { id: 83 } TagId(1) Test.183 Test.25 Test.184 Test.24 Test.182; let #Derived_gen.14 : {} = lowlevel PtrStore #Derived_gen.6 Test.181; let #Derived_gen.13 : [C *self I64 *self I32 Int1, ] = lowlevel PtrLoad #Derived_gen.7; ret #Derived_gen.13; in let #Derived_gen.73 : Int1 = lowlevel RefCountIsUnique Test.180; if #Derived_gen.73 then - let #Derived_gen.214 : [C *self I64 *self I32 Int1, ] = Reset { symbol: Test.198, id: UpdateModeId { id: 86 } }; - let #Derived_gen.215 : [C *self I64 *self I32 Int1, ] = ResetRef { symbol: Test.180, id: UpdateModeId { id: 87 } }; - jump #Derived_gen.72 #Derived_gen.208 #Derived_gen.214 #Derived_gen.215; + let #Derived_gen.192 : [C *self I64 *self I32 Int1, ] = Reset { symbol: Test.198, id: UpdateModeId { id: 86 } }; + jump #Derived_gen.72 #Derived_gen.187 #Derived_gen.192 Test.180; else inc Test.26; decref Test.180; - let #Derived_gen.216 : [C *self I64 *self I32 Int1, ] = NullPointer; - jump #Derived_gen.72 #Derived_gen.216 #Derived_gen.216 #Derived_gen.208; + let #Derived_gen.193 : [C *self I64 *self I32 Int1, ] = NullPointer; + jump #Derived_gen.72 #Derived_gen.193 #Derived_gen.193 #Derived_gen.187; in let Test.228 : U8 = 1i64; let Test.229 : U8 = GetTagId Test.180; let Test.230 : Int1 = lowlevel Eq Test.228 Test.229; if Test.230 then - joinpoint Test.225 #Derived_gen.226: - joinpoint Test.216 #Derived_gen.227: + joinpoint Test.225 #Derived_gen.201: + joinpoint Test.216 #Derived_gen.202: let Test.46 : [C *self I64 *self I32 Int1, ] = UnionAtIndex (Id 1) (Index 0) Test.180; let Test.48 : I64 = UnionAtIndex (Id 1) (Index 1) Test.180; let Test.49 : [C *self I64 *self I32 Int1, ] = UnionAtIndex (Id 1) (Index 2) Test.180; let Test.47 : I32 = UnionAtIndex (Id 1) (Index 3) Test.180; - joinpoint #Derived_gen.66 #Derived_gen.229 #Derived_gen.230: + joinpoint #Derived_gen.66 #Derived_gen.203 #Derived_gen.204: let Test.196 : Int1 = true; - let Test.195 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.230 UpdateModeId { id: 100 } TagId(1) Test.46 Test.48 Test.49 Test.47 Test.196; + let Test.195 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.204 UpdateModeId { id: 100 } TagId(1) Test.46 Test.48 Test.49 Test.47 Test.196; let Test.194 : Int1 = false; - let Test.193 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.229 UpdateModeId { id: 99 } TagId(1) Test.195 Test.18 Test.19 Test.17 Test.194; + let Test.193 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.203 UpdateModeId { id: 99 } TagId(1) Test.195 Test.18 Test.19 Test.17 Test.194; let #Derived_gen.16 : {} = lowlevel PtrStore #Derived_gen.6 Test.193; let #Derived_gen.15 : [C *self I64 *self I32 Int1, ] = lowlevel PtrLoad #Derived_gen.7; ret #Derived_gen.15; in let #Derived_gen.67 : Int1 = lowlevel RefCountIsUnique Test.180; if #Derived_gen.67 then - let #Derived_gen.231 : [C *self I64 *self I32 Int1, ] = ResetRef { symbol: Test.180, id: UpdateModeId { id: 101 } }; - jump #Derived_gen.66 #Derived_gen.227 #Derived_gen.231; + jump #Derived_gen.66 #Derived_gen.202 Test.180; else inc Test.46; inc Test.49; decref Test.180; - let #Derived_gen.232 : [C *self I64 *self I32 Int1, ] = NullPointer; - jump #Derived_gen.66 #Derived_gen.232 #Derived_gen.227; + let #Derived_gen.205 : [C *self I64 *self I32 Int1, ] = NullPointer; + jump #Derived_gen.66 #Derived_gen.205 #Derived_gen.202; in let Test.213 : [C *self I64 *self I32 Int1, ] = UnionAtIndex (Id 1) (Index 0) Test.180; let Test.214 : U8 = 1i64; @@ -123,11 +121,11 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2): let Test.212 : Int1 = true; let Test.217 : Int1 = lowlevel Eq Test.212 Test.211; if Test.217 then - jump Test.199 #Derived_gen.226; + jump Test.199 #Derived_gen.201; else - jump Test.216 #Derived_gen.226; + jump Test.216 #Derived_gen.201; else - jump Test.216 #Derived_gen.226; + jump Test.216 #Derived_gen.201; in let Test.222 : [C *self I64 *self I32 Int1, ] = UnionAtIndex (Id 1) (Index 2) Test.180; let Test.223 : U8 = 1i64; @@ -139,7 +137,7 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2): let Test.221 : Int1 = true; let Test.226 : Int1 = lowlevel Eq Test.221 Test.220; if Test.226 then - joinpoint Test.207 #Derived_gen.233: + joinpoint Test.207 #Derived_gen.206: let Test.33 : [C *self I64 *self I32 Int1, ] = UnionAtIndex (Id 1) (Index 0) Test.180; let Test.35 : I64 = UnionAtIndex (Id 1) (Index 1) Test.180; let Test.200 : [C *self I64 *self I32 Int1, ] = UnionAtIndex (Id 1) (Index 2) Test.180; @@ -150,27 +148,26 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2): inc Test.39; let Test.37 : I32 = UnionAtIndex (Id 1) (Index 3) Test.200; let Test.34 : I32 = UnionAtIndex (Id 1) (Index 3) Test.180; - joinpoint #Derived_gen.70 #Derived_gen.236 #Derived_gen.237 #Derived_gen.238: + joinpoint #Derived_gen.70 #Derived_gen.208 #Derived_gen.209 #Derived_gen.210: let Test.192 : Int1 = false; - let Test.189 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.238 UpdateModeId { id: 107 } TagId(1) Test.33 Test.35 Test.36 Test.34 Test.192; + let Test.189 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.210 UpdateModeId { id: 107 } TagId(1) Test.33 Test.35 Test.36 Test.34 Test.192; let Test.191 : Int1 = false; - let Test.190 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.237 UpdateModeId { id: 106 } TagId(1) Test.39 Test.18 Test.19 Test.17 Test.191; + let Test.190 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.209 UpdateModeId { id: 106 } TagId(1) Test.39 Test.18 Test.19 Test.17 Test.191; let Test.188 : Int1 = true; - let Test.187 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.236 UpdateModeId { id: 105 } TagId(1) Test.189 Test.38 Test.190 Test.37 Test.188; + let Test.187 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.208 UpdateModeId { id: 105 } TagId(1) Test.189 Test.38 Test.190 Test.37 Test.188; let #Derived_gen.18 : {} = lowlevel PtrStore #Derived_gen.6 Test.187; let #Derived_gen.17 : [C *self I64 *self I32 Int1, ] = lowlevel PtrLoad #Derived_gen.7; ret #Derived_gen.17; in let #Derived_gen.71 : Int1 = lowlevel RefCountIsUnique Test.180; if #Derived_gen.71 then - let #Derived_gen.239 : [C *self I64 *self I32 Int1, ] = Reset { symbol: Test.200, id: UpdateModeId { id: 108 } }; - let #Derived_gen.240 : [C *self I64 *self I32 Int1, ] = ResetRef { symbol: Test.180, id: UpdateModeId { id: 109 } }; - jump #Derived_gen.70 #Derived_gen.233 #Derived_gen.239 #Derived_gen.240; + let #Derived_gen.211 : [C *self I64 *self I32 Int1, ] = Reset { symbol: Test.200, id: UpdateModeId { id: 108 } }; + jump #Derived_gen.70 #Derived_gen.206 #Derived_gen.211 Test.180; else inc Test.33; decref Test.180; - let #Derived_gen.241 : [C *self I64 *self I32 Int1, ] = NullPointer; - jump #Derived_gen.70 #Derived_gen.241 #Derived_gen.241 #Derived_gen.233; + let #Derived_gen.212 : [C *self I64 *self I32 Int1, ] = NullPointer; + jump #Derived_gen.70 #Derived_gen.212 #Derived_gen.212 #Derived_gen.206; in let Test.204 : [C *self I64 *self I32 Int1, ] = UnionAtIndex (Id 1) (Index 0) Test.180; let Test.205 : U8 = 1i64; @@ -182,33 +179,33 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2): let Test.203 : Int1 = true; let Test.208 : Int1 = lowlevel Eq Test.203 Test.202; if Test.208 then - jump Test.199 #Derived_gen.119; + jump Test.199 #Derived_gen.118; else - jump Test.207 #Derived_gen.119; + jump Test.207 #Derived_gen.118; else - jump Test.207 #Derived_gen.119; + jump Test.207 #Derived_gen.118; else - jump Test.225 #Derived_gen.119; + jump Test.225 #Derived_gen.118; else - jump Test.225 #Derived_gen.119; + jump Test.225 #Derived_gen.118; else - decref #Derived_gen.119; + decref #Derived_gen.118; dec Test.19; let Test.197 : [C *self I64 *self I32 Int1, ] = TagId(0) ; let #Derived_gen.20 : {} = lowlevel PtrStore #Derived_gen.6 Test.197; let #Derived_gen.19 : [C *self I64 *self I32 Int1, ] = lowlevel PtrLoad #Derived_gen.7; ret #Derived_gen.19; else - jump Test.238 #Derived_gen.119; + jump Test.238 #Derived_gen.118; else - jump Test.238 #Derived_gen.119; + jump Test.238 #Derived_gen.118; else let Test.117 : Int1 = CallByName Num.24 Test.10 Test.17; if Test.117 then - joinpoint Test.176 #Derived_gen.333: + joinpoint Test.176 #Derived_gen.288: let Test.170 : Int1 = false; let #Derived_gen.21 : [C *self I64 *self I32 Int1, ] = NullPointer; - let Test.169 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.333 UpdateModeId { id: 196 } TagId(1) Test.16 Test.18 #Derived_gen.21 Test.17 Test.170; + let Test.169 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.288 UpdateModeId { id: 196 } TagId(1) Test.16 Test.18 #Derived_gen.21 Test.17 Test.170; let #Derived_gen.22 : Ptr([C *self I64 *self I32 Int1, ]) = UnionFieldPtrAtIndex (Id 1) (Index 2) Test.169; let #Derived_gen.23 : {} = lowlevel PtrStore #Derived_gen.6 Test.169; jump #Derived_gen.5 Test.19 Test.10 Test.11 #Derived_gen.22 #Derived_gen.7; @@ -222,9 +219,9 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2): let Test.177 : Int1 = lowlevel Eq Test.173 Test.172; if Test.177 then inc Test.19; - let #Derived_gen.334 : [C *self I64 *self I32 Int1, ] = Reset { symbol: Test.16, id: UpdateModeId { id: 197 } }; + let #Derived_gen.289 : [C *self I64 *self I32 Int1, ] = Reset { symbol: Test.16, id: UpdateModeId { id: 197 } }; let Test.118 : [C *self I64 *self I32 Int1, ] = CallByName Test.3 Test.19 Test.10 Test.11; - joinpoint Test.137 #Derived_gen.374 #Derived_gen.375: + joinpoint Test.137 #Derived_gen.322 #Derived_gen.323: let Test.136 : [C *self I64 *self I32 Int1, ] = UnionAtIndex (Id 1) (Index 0) Test.118; let Test.57 : [C *self I64 *self I32 Int1, ] = UnionAtIndex (Id 1) (Index 0) Test.136; inc Test.57; @@ -235,58 +232,56 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2): let Test.62 : I64 = UnionAtIndex (Id 1) (Index 1) Test.118; let Test.63 : [C *self I64 *self I32 Int1, ] = UnionAtIndex (Id 1) (Index 2) Test.118; let Test.61 : I32 = UnionAtIndex (Id 1) (Index 3) Test.118; - joinpoint #Derived_gen.112 #Derived_gen.379 #Derived_gen.380 #Derived_gen.381: + joinpoint #Derived_gen.112 #Derived_gen.326 #Derived_gen.327 #Derived_gen.328: let Test.124 : Int1 = false; - let Test.121 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.381 UpdateModeId { id: 242 } TagId(1) Test.57 Test.59 Test.60 Test.58 Test.124; + let Test.121 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.328 UpdateModeId { id: 242 } TagId(1) Test.57 Test.59 Test.60 Test.58 Test.124; let Test.123 : Int1 = false; - let Test.122 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.380 UpdateModeId { id: 241 } TagId(1) Test.63 Test.18 Test.19 Test.17 Test.123; + let Test.122 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.327 UpdateModeId { id: 241 } TagId(1) Test.63 Test.18 Test.19 Test.17 Test.123; let Test.120 : Int1 = true; - let Test.119 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.379 UpdateModeId { id: 240 } TagId(1) Test.121 Test.62 Test.122 Test.61 Test.120; + let Test.119 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.326 UpdateModeId { id: 240 } TagId(1) Test.121 Test.62 Test.122 Test.61 Test.120; let #Derived_gen.25 : {} = lowlevel PtrStore #Derived_gen.6 Test.119; let #Derived_gen.24 : [C *self I64 *self I32 Int1, ] = lowlevel PtrLoad #Derived_gen.7; ret #Derived_gen.24; in let #Derived_gen.113 : Int1 = lowlevel RefCountIsUnique Test.118; if #Derived_gen.113 then - decref #Derived_gen.374; - let #Derived_gen.382 : [C *self I64 *self I32 Int1, ] = Reset { symbol: Test.136, id: UpdateModeId { id: 243 } }; - let #Derived_gen.383 : [C *self I64 *self I32 Int1, ] = ResetRef { symbol: Test.118, id: UpdateModeId { id: 244 } }; - jump #Derived_gen.112 #Derived_gen.375 #Derived_gen.382 #Derived_gen.383; + decref #Derived_gen.322; + let #Derived_gen.329 : [C *self I64 *self I32 Int1, ] = Reset { symbol: Test.136, id: UpdateModeId { id: 243 } }; + jump #Derived_gen.112 #Derived_gen.323 #Derived_gen.329 Test.118; else inc Test.63; decref Test.118; - let #Derived_gen.384 : [C *self I64 *self I32 Int1, ] = NullPointer; - jump #Derived_gen.112 #Derived_gen.384 #Derived_gen.374 #Derived_gen.375; + let #Derived_gen.330 : [C *self I64 *self I32 Int1, ] = NullPointer; + jump #Derived_gen.112 #Derived_gen.330 #Derived_gen.322 #Derived_gen.323; in let Test.166 : U8 = 1i64; let Test.167 : U8 = GetTagId Test.118; let Test.168 : Int1 = lowlevel Eq Test.166 Test.167; if Test.168 then - joinpoint Test.163 #Derived_gen.396 #Derived_gen.397: - joinpoint Test.154 #Derived_gen.398 #Derived_gen.399: + joinpoint Test.163 #Derived_gen.340 #Derived_gen.341: + joinpoint Test.154 #Derived_gen.342 #Derived_gen.343: let Test.83 : [C *self I64 *self I32 Int1, ] = UnionAtIndex (Id 1) (Index 0) Test.118; let Test.85 : I64 = UnionAtIndex (Id 1) (Index 1) Test.118; let Test.86 : [C *self I64 *self I32 Int1, ] = UnionAtIndex (Id 1) (Index 2) Test.118; let Test.84 : I32 = UnionAtIndex (Id 1) (Index 3) Test.118; - joinpoint #Derived_gen.102 #Derived_gen.402 #Derived_gen.403: + joinpoint #Derived_gen.102 #Derived_gen.345 #Derived_gen.346: let Test.134 : Int1 = true; - let Test.133 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.403 UpdateModeId { id: 262 } TagId(1) Test.83 Test.85 Test.86 Test.84 Test.134; + let Test.133 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.346 UpdateModeId { id: 262 } TagId(1) Test.83 Test.85 Test.86 Test.84 Test.134; let Test.132 : Int1 = false; - let Test.131 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.402 UpdateModeId { id: 261 } TagId(1) Test.133 Test.18 Test.19 Test.17 Test.132; + let Test.131 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.345 UpdateModeId { id: 261 } TagId(1) Test.133 Test.18 Test.19 Test.17 Test.132; let #Derived_gen.27 : {} = lowlevel PtrStore #Derived_gen.6 Test.131; let #Derived_gen.26 : [C *self I64 *self I32 Int1, ] = lowlevel PtrLoad #Derived_gen.7; ret #Derived_gen.26; in let #Derived_gen.103 : Int1 = lowlevel RefCountIsUnique Test.118; if #Derived_gen.103 then - decref #Derived_gen.398; - let #Derived_gen.404 : [C *self I64 *self I32 Int1, ] = ResetRef { symbol: Test.118, id: UpdateModeId { id: 263 } }; - jump #Derived_gen.102 #Derived_gen.399 #Derived_gen.404; + decref #Derived_gen.342; + jump #Derived_gen.102 #Derived_gen.343 Test.118; else inc Test.83; inc Test.86; decref Test.118; - jump #Derived_gen.102 #Derived_gen.398 #Derived_gen.399; + jump #Derived_gen.102 #Derived_gen.342 #Derived_gen.343; in let Test.151 : [C *self I64 *self I32 Int1, ] = UnionAtIndex (Id 1) (Index 0) Test.118; let Test.152 : U8 = 1i64; @@ -298,11 +293,11 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2): let Test.150 : Int1 = true; let Test.155 : Int1 = lowlevel Eq Test.150 Test.149; if Test.155 then - jump Test.137 #Derived_gen.396 #Derived_gen.397; + jump Test.137 #Derived_gen.340 #Derived_gen.341; else - jump Test.154 #Derived_gen.396 #Derived_gen.397; + jump Test.154 #Derived_gen.340 #Derived_gen.341; else - jump Test.154 #Derived_gen.396 #Derived_gen.397; + jump Test.154 #Derived_gen.340 #Derived_gen.341; in let Test.160 : [C *self I64 *self I32 Int1, ] = UnionAtIndex (Id 1) (Index 2) Test.118; let Test.161 : U8 = 1i64; @@ -314,7 +309,7 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2): let Test.159 : Int1 = true; let Test.164 : Int1 = lowlevel Eq Test.159 Test.158; if Test.164 then - joinpoint Test.145 #Derived_gen.405 #Derived_gen.406: + joinpoint Test.145 #Derived_gen.347 #Derived_gen.348: let Test.70 : [C *self I64 *self I32 Int1, ] = UnionAtIndex (Id 1) (Index 0) Test.118; let Test.72 : I64 = UnionAtIndex (Id 1) (Index 1) Test.118; let Test.138 : [C *self I64 *self I32 Int1, ] = UnionAtIndex (Id 1) (Index 2) Test.118; @@ -325,28 +320,27 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2): inc Test.76; let Test.74 : I32 = UnionAtIndex (Id 1) (Index 3) Test.138; let Test.71 : I32 = UnionAtIndex (Id 1) (Index 3) Test.118; - joinpoint #Derived_gen.106 #Derived_gen.410 #Derived_gen.411 #Derived_gen.412: + joinpoint #Derived_gen.106 #Derived_gen.351 #Derived_gen.352 #Derived_gen.353: let Test.130 : Int1 = false; - let Test.127 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.412 UpdateModeId { id: 271 } TagId(1) Test.70 Test.72 Test.73 Test.71 Test.130; + let Test.127 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.353 UpdateModeId { id: 271 } TagId(1) Test.70 Test.72 Test.73 Test.71 Test.130; let Test.129 : Int1 = false; - let Test.128 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.411 UpdateModeId { id: 270 } TagId(1) Test.76 Test.18 Test.19 Test.17 Test.129; + let Test.128 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.352 UpdateModeId { id: 270 } TagId(1) Test.76 Test.18 Test.19 Test.17 Test.129; let Test.126 : Int1 = true; - let Test.125 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.410 UpdateModeId { id: 269 } TagId(1) Test.127 Test.75 Test.128 Test.74 Test.126; + let Test.125 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.351 UpdateModeId { id: 269 } TagId(1) Test.127 Test.75 Test.128 Test.74 Test.126; let #Derived_gen.29 : {} = lowlevel PtrStore #Derived_gen.6 Test.125; let #Derived_gen.28 : [C *self I64 *self I32 Int1, ] = lowlevel PtrLoad #Derived_gen.7; ret #Derived_gen.28; in let #Derived_gen.107 : Int1 = lowlevel RefCountIsUnique Test.118; if #Derived_gen.107 then - decref #Derived_gen.405; - let #Derived_gen.413 : [C *self I64 *self I32 Int1, ] = Reset { symbol: Test.138, id: UpdateModeId { id: 272 } }; - let #Derived_gen.414 : [C *self I64 *self I32 Int1, ] = ResetRef { symbol: Test.118, id: UpdateModeId { id: 273 } }; - jump #Derived_gen.106 #Derived_gen.406 #Derived_gen.413 #Derived_gen.414; + decref #Derived_gen.347; + let #Derived_gen.354 : [C *self I64 *self I32 Int1, ] = Reset { symbol: Test.138, id: UpdateModeId { id: 272 } }; + jump #Derived_gen.106 #Derived_gen.348 #Derived_gen.354 Test.118; else inc Test.70; decref Test.118; - let #Derived_gen.415 : [C *self I64 *self I32 Int1, ] = NullPointer; - jump #Derived_gen.106 #Derived_gen.415 #Derived_gen.405 #Derived_gen.406; + let #Derived_gen.355 : [C *self I64 *self I32 Int1, ] = NullPointer; + jump #Derived_gen.106 #Derived_gen.355 #Derived_gen.347 #Derived_gen.348; in let Test.142 : [C *self I64 *self I32 Int1, ] = UnionAtIndex (Id 1) (Index 0) Test.118; let Test.143 : U8 = 1i64; @@ -358,18 +352,18 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2): let Test.141 : Int1 = true; let Test.146 : Int1 = lowlevel Eq Test.141 Test.140; if Test.146 then - jump Test.137 #Derived_gen.119 #Derived_gen.334; + jump Test.137 #Derived_gen.118 #Derived_gen.289; else - jump Test.145 #Derived_gen.119 #Derived_gen.334; + jump Test.145 #Derived_gen.118 #Derived_gen.289; else - jump Test.145 #Derived_gen.119 #Derived_gen.334; + jump Test.145 #Derived_gen.118 #Derived_gen.289; else - jump Test.163 #Derived_gen.119 #Derived_gen.334; + jump Test.163 #Derived_gen.118 #Derived_gen.289; else - jump Test.163 #Derived_gen.119 #Derived_gen.334; + jump Test.163 #Derived_gen.118 #Derived_gen.289; else - decref #Derived_gen.334; - decref #Derived_gen.119; + decref #Derived_gen.289; + decref #Derived_gen.118; joinpoint #Derived_gen.108: let Test.135 : [C *self I64 *self I32 Int1, ] = TagId(0) ; let #Derived_gen.31 : {} = lowlevel PtrStore #Derived_gen.6 Test.135; @@ -382,43 +376,42 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2): dec #Derived_gen.110; let #Derived_gen.109 : [C *self I64 *self I32 Int1, ] = UnionAtIndex (Id 1) (Index 2) Test.19; dec #Derived_gen.109; - decref Test.19; + free Test.19; jump #Derived_gen.108; else decref Test.19; jump #Derived_gen.108; else - jump Test.176 #Derived_gen.119; + jump Test.176 #Derived_gen.118; else - jump Test.176 #Derived_gen.119; + jump Test.176 #Derived_gen.118; else let Test.116 : Int1 = false; - let Test.115 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.119 UpdateModeId { id: 1 } TagId(1) Test.16 Test.11 Test.19 Test.10 Test.116; + let Test.115 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.118 UpdateModeId { id: 1 } TagId(1) Test.16 Test.11 Test.19 Test.10 Test.116; let #Derived_gen.33 : {} = lowlevel PtrStore #Derived_gen.6 Test.115; let #Derived_gen.32 : [C *self I64 *self I32 Int1, ] = lowlevel PtrLoad #Derived_gen.7; ret #Derived_gen.32; in let #Derived_gen.115 : Int1 = lowlevel RefCountIsUnique Test.9; if #Derived_gen.115 then - let #Derived_gen.424 : [C *self I64 *self I32 Int1, ] = ResetRef { symbol: Test.9, id: UpdateModeId { id: 282 } }; - jump #Derived_gen.114 #Derived_gen.424; + jump #Derived_gen.114 Test.9; else inc Test.16; inc Test.19; decref Test.9; - let #Derived_gen.425 : [C *self I64 *self I32 Int1, ] = NullPointer; - jump #Derived_gen.114 #Derived_gen.425; + let #Derived_gen.363 : [C *self I64 *self I32 Int1, ] = NullPointer; + jump #Derived_gen.114 #Derived_gen.363; else let Test.96 : [C *self I64 *self I32 Int1, ] = UnionAtIndex (Id 1) (Index 0) Test.9; let Test.98 : I64 = UnionAtIndex (Id 1) (Index 1) Test.9; let Test.99 : [C *self I64 *self I32 Int1, ] = UnionAtIndex (Id 1) (Index 2) Test.9; let Test.97 : I32 = UnionAtIndex (Id 1) (Index 3) Test.9; - joinpoint #Derived_gen.116 #Derived_gen.427: + joinpoint #Derived_gen.116 #Derived_gen.364: let Test.247 : Int1 = CallByName Num.22 Test.10 Test.97; if Test.247 then let Test.249 : Int1 = true; let #Derived_gen.34 : [C *self I64 *self I32 Int1, ] = NullPointer; - let Test.248 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.427 UpdateModeId { id: 284 } TagId(1) #Derived_gen.34 Test.98 Test.99 Test.97 Test.249; + let Test.248 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.364 UpdateModeId { id: 284 } TagId(1) #Derived_gen.34 Test.98 Test.99 Test.97 Test.249; let #Derived_gen.35 : Ptr([C *self I64 *self I32 Int1, ]) = UnionFieldPtrAtIndex (Id 1) (Index 0) Test.248; let #Derived_gen.36 : {} = lowlevel PtrStore #Derived_gen.6 Test.248; jump #Derived_gen.5 Test.96 Test.10 Test.11 #Derived_gen.35 #Derived_gen.7; @@ -427,27 +420,26 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2): if Test.243 then let Test.245 : Int1 = true; let #Derived_gen.37 : [C *self I64 *self I32 Int1, ] = NullPointer; - let Test.244 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.427 UpdateModeId { id: 284 } TagId(1) Test.96 Test.98 #Derived_gen.37 Test.97 Test.245; + let Test.244 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.364 UpdateModeId { id: 284 } TagId(1) Test.96 Test.98 #Derived_gen.37 Test.97 Test.245; let #Derived_gen.38 : Ptr([C *self I64 *self I32 Int1, ]) = UnionFieldPtrAtIndex (Id 1) (Index 2) Test.244; let #Derived_gen.39 : {} = lowlevel PtrStore #Derived_gen.6 Test.244; jump #Derived_gen.5 Test.99 Test.10 Test.11 #Derived_gen.38 #Derived_gen.7; else let Test.242 : Int1 = true; - let Test.241 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.427 UpdateModeId { id: 284 } TagId(1) Test.96 Test.11 Test.99 Test.10 Test.242; + let Test.241 : [C *self I64 *self I32 Int1, ] = Reuse #Derived_gen.364 UpdateModeId { id: 284 } TagId(1) Test.96 Test.11 Test.99 Test.10 Test.242; let #Derived_gen.41 : {} = lowlevel PtrStore #Derived_gen.6 Test.241; let #Derived_gen.40 : [C *self I64 *self I32 Int1, ] = lowlevel PtrLoad #Derived_gen.7; ret #Derived_gen.40; in let #Derived_gen.117 : Int1 = lowlevel RefCountIsUnique Test.9; if #Derived_gen.117 then - let #Derived_gen.428 : [C *self I64 *self I32 Int1, ] = ResetRef { symbol: Test.9, id: UpdateModeId { id: 285 } }; - jump #Derived_gen.116 #Derived_gen.428; + jump #Derived_gen.116 Test.9; else inc Test.96; inc Test.99; decref Test.9; - let #Derived_gen.429 : [C *self I64 *self I32 Int1, ] = NullPointer; - jump #Derived_gen.116 #Derived_gen.429; + let #Derived_gen.365 : [C *self I64 *self I32 Int1, ] = NullPointer; + jump #Derived_gen.116 #Derived_gen.365; in jump #Derived_gen.5 #Derived_gen.0 #Derived_gen.1 #Derived_gen.2 #Derived_gen.3 #Derived_gen.3; diff --git a/crates/compiler/test_mono/generated/recursive_lambda_set_has_nested_non_recursive_lambda_sets_issue_5026.txt b/crates/compiler/test_mono/generated/recursive_lambda_set_has_nested_non_recursive_lambda_sets_issue_5026.txt index 3e08cd465da..c6a00595d7d 100644 --- a/crates/compiler/test_mono/generated/recursive_lambda_set_has_nested_non_recursive_lambda_sets_issue_5026.txt +++ b/crates/compiler/test_mono/generated/recursive_lambda_set_has_nested_non_recursive_lambda_sets_issue_5026.txt @@ -44,7 +44,7 @@ procedure Test.6 (Test.16, #Attr.12): in let #Derived_gen.3 : Int1 = lowlevel RefCountIsUnique #Attr.12; if #Derived_gen.3 then - decref #Attr.12; + free #Attr.12; jump #Derived_gen.2; else decref #Attr.12; diff --git a/crates/compiler/test_mono/generated/recursive_lambda_set_resolved_only_upon_specialization.txt b/crates/compiler/test_mono/generated/recursive_lambda_set_resolved_only_upon_specialization.txt index f053cf0a19c..a6ad8acc154 100644 --- a/crates/compiler/test_mono/generated/recursive_lambda_set_resolved_only_upon_specialization.txt +++ b/crates/compiler/test_mono/generated/recursive_lambda_set_resolved_only_upon_specialization.txt @@ -54,7 +54,7 @@ procedure Test.4 (#Derived_gen.2, #Derived_gen.3): in let #Derived_gen.5 : Int1 = lowlevel RefCountIsUnique #Attr.12; if #Derived_gen.5 then - decref #Attr.12; + free #Attr.12; jump #Derived_gen.4; else inc Test.3; diff --git a/crates/compiler/test_mono/generated/recursively_build_effect.txt b/crates/compiler/test_mono/generated/recursively_build_effect.txt index 72edafead47..d1f4bd9809b 100644 --- a/crates/compiler/test_mono/generated/recursively_build_effect.txt +++ b/crates/compiler/test_mono/generated/recursively_build_effect.txt @@ -10,7 +10,7 @@ procedure Test.11 (Test.29, #Attr.12): let Test.10 : {} = UnionAtIndex (Id 0) (Index 0) #Attr.12; let #Derived_gen.9 : Int1 = lowlevel RefCountIsUnique #Attr.12; if #Derived_gen.9 then - decref #Attr.12; + free #Attr.12; ret Test.10; else decref #Attr.12; @@ -40,7 +40,7 @@ procedure Test.14 (#Derived_gen.2, #Derived_gen.3): in let #Derived_gen.11 : Int1 = lowlevel RefCountIsUnique #Attr.12; if #Derived_gen.11 then - decref #Attr.12; + free #Attr.12; jump #Derived_gen.10; else decref #Attr.12; diff --git a/crates/compiler/test_mono/generated/specialize_after_match.txt b/crates/compiler/test_mono/generated/specialize_after_match.txt index 7dd9c9c5eb0..dfb63f7e7da 100644 --- a/crates/compiler/test_mono/generated/specialize_after_match.txt +++ b/crates/compiler/test_mono/generated/specialize_after_match.txt @@ -39,7 +39,7 @@ procedure Test.2 (Test.9, Test.10): let #Derived_gen.5 : Int1 = lowlevel RefCountIsUnique Test.9; if #Derived_gen.5 then dec Test.11; - decref Test.9; + free Test.9; jump #Derived_gen.4; else inc Test.12; @@ -65,7 +65,7 @@ procedure Test.3 (Test.17): if #Derived_gen.3 then let #Derived_gen.2 : Str = UnionAtIndex (Id 0) (Index 0) Test.17; dec #Derived_gen.2; - decref Test.17; + free Test.17; jump #Derived_gen.1; else inc Test.18;