diff --git a/compiler/gen_wasm/src/backend.rs b/compiler/gen_wasm/src/backend.rs index b8584bdb02..bd3c99a3e4 100644 --- a/compiler/gen_wasm/src/backend.rs +++ b/compiler/gen_wasm/src/backend.rs @@ -1371,7 +1371,7 @@ impl<'a> WasmBackend<'a> { let layout = self.storage.symbol_layouts[&argument]; let (specialized_call_expr, new_specializations) = self .helper_proc_gen - .call_reset_refcount(ident_ids, &layout, argument); + .call_reset_refcount(ident_ids, layout, argument); // If any new specializations were created, register their symbol data for spec in new_specializations.into_iter() { diff --git a/compiler/gen_wasm/src/lib.rs b/compiler/gen_wasm/src/lib.rs index 57266be640..1e526669cc 100644 --- a/compiler/gen_wasm/src/lib.rs +++ b/compiler/gen_wasm/src/lib.rs @@ -134,7 +134,7 @@ pub fn build_module_without_wrapper<'a>( println!("## procs"); for proc in procs.iter() { println!("{}", proc.to_pretty(200)); - // println!("{:#?}", proc); + println!("{:#?}", proc); } } @@ -240,7 +240,7 @@ pub struct WasmDebugLogSettings { pub const DEBUG_LOG_SETTINGS: WasmDebugLogSettings = WasmDebugLogSettings { proc_start_end: false && cfg!(debug_assertions), - user_procs_ir: false && cfg!(debug_assertions), + user_procs_ir: true && cfg!(debug_assertions), helper_procs_ir: false && cfg!(debug_assertions), let_stmt_ir: false && cfg!(debug_assertions), instructions: false && cfg!(debug_assertions), diff --git a/compiler/mono/src/code_gen_help/mod.rs b/compiler/mono/src/code_gen_help/mod.rs index ec7d81654b..2ecbc76fec 100644 --- a/compiler/mono/src/code_gen_help/mod.rs +++ b/compiler/mono/src/code_gen_help/mod.rs @@ -37,9 +37,6 @@ impl HelperOp { fn is_decref(&self) -> bool { matches!(self, Self::DecRef(_)) } - fn is_reset(&self) -> bool { - matches!(self, Self::Reset) - } } #[derive(Debug)] @@ -151,7 +148,7 @@ impl<'a> CodeGenHelp<'a> { pub fn call_reset_refcount( &mut self, ident_ids: &mut IdentIds, - layout: &Layout<'a>, + layout: Layout<'a>, argument: Symbol, ) -> (Expr<'a>, Vec<'a, (Symbol, ProcLayout<'a>)>) { let mut ctx = Context { @@ -160,11 +157,20 @@ impl<'a> CodeGenHelp<'a> { op: HelperOp::Reset, }; - let arguments = self.arena.alloc([argument]); + let proc_name = self.find_or_create_proc(ident_ids, &mut ctx, layout); - let expr = self - .call_specialized_op(ident_ids, &mut ctx, *layout, arguments) - .unwrap(); + let arguments = self.arena.alloc([argument]); + let ret_layout = self.arena.alloc(layout); + let arg_layouts = self.arena.alloc([layout]); + let expr = Expr::Call(Call { + call_type: CallType::ByName { + name: proc_name, + ret_layout, + arg_layouts, + specialization_id: CallSpecId::BACKEND_DUMMY, + }, + arguments, + }); (expr, ctx.new_linker_data) } @@ -283,10 +289,14 @@ impl<'a> CodeGenHelp<'a> { // Recursively generate the body of the Proc and sub-procs let (ret_layout, body) = match ctx.op { - Inc | Dec | DecRef(_) | Reset => ( + Inc | Dec | DecRef(_) => ( LAYOUT_UNIT, refcount::refcount_generic(self, ident_ids, ctx, layout, Symbol::ARG_1), ), + Reset => ( + layout, + refcount::refcount_reset_proc_body(self, ident_ids, ctx, layout, Symbol::ARG_1), + ), Eq => ( LAYOUT_BOOL, equality::eq_generic(self, ident_ids, ctx, layout), diff --git a/compiler/mono/src/code_gen_help/refcount.rs b/compiler/mono/src/code_gen_help/refcount.rs index 4af25fdc2b..f5b1cd2907 100644 --- a/compiler/mono/src/code_gen_help/refcount.rs +++ b/compiler/mono/src/code_gen_help/refcount.rs @@ -128,6 +128,40 @@ pub fn refcount_generic<'a>( } } +pub fn refcount_reset_proc_body<'a>( + root: &mut CodeGenHelp<'a>, + ident_ids: &mut IdentIds, + ctx: &mut Context<'a>, + layout: Layout<'a>, + structure: Symbol, +) -> Stmt<'a> { + // Reset is a fancy Decrement. When we recurse into child layouts we just want Dec. + ctx.op = HelperOp::Dec; + + /* + assert layout is union + create the context, with op=Dec + + load the rc value + - do I have a helper for this? + + let isUnique = lowlevel Eq rc refcount_unique + switch + True => { + refcount union contents + ret structure + } + False => { + call specialized op Dec + let zero = 0 + let typed_null = lowlevel PtrCast zero + ret typed_null + } + */ + + todo!() +} + // Check if refcounting is implemented yet. In the long term, this will be deleted. // In the short term, it helps us to skip refcounting and let it leak, so we can make // progress incrementally. Kept in sync with generate_procs using assertions. @@ -786,7 +820,7 @@ fn refcount_union<'a>( Recursive(tags) => { let (is_tailrec, tail_idx) = root.union_tail_recursion_fields(union); - if is_tailrec && !ctx.op.is_decref() && !ctx.op.is_reset() { + if is_tailrec && !ctx.op.is_decref() { refcount_union_tailrec(root, ident_ids, ctx, union, tags, None, tail_idx, structure) } else { refcount_union_rec(root, ident_ids, ctx, union, tags, None, structure) @@ -808,7 +842,7 @@ fn refcount_union<'a>( } => { let null_id = Some(nullable_id); let (is_tailrec, tail_idx) = root.union_tail_recursion_fields(union); - if is_tailrec && !ctx.op.is_decref() && !ctx.op.is_reset() { + if is_tailrec && !ctx.op.is_decref() { refcount_union_tailrec( root, ident_ids, ctx, union, tags, null_id, tail_idx, structure, ) @@ -824,7 +858,7 @@ fn refcount_union<'a>( let null_id = Some(nullable_id as TagIdIntType); let tags = root.arena.alloc([other_fields]); let (is_tailrec, tail_idx) = root.union_tail_recursion_fields(union); - if is_tailrec && !ctx.op.is_decref() && !ctx.op.is_reset() { + if is_tailrec && !ctx.op.is_decref() { refcount_union_tailrec( root, ident_ids, ctx, union, tags, null_id, tail_idx, structure, ) @@ -980,18 +1014,14 @@ fn refcount_union_rec<'a>( let alignment = Layout::Union(union_layout).alignment_bytes(root.target_info); let ret_stmt = rc_return_stmt(root, ident_ids, ctx); - let modify_structure_stmt = if ctx.op.is_reset() { - ret_stmt - } else { - modify_refcount( - root, - ident_ids, - ctx, - rc_ptr, - alignment, - root.arena.alloc(ret_stmt), - ) - }; + let modify_structure_stmt = modify_refcount( + root, + ident_ids, + ctx, + rc_ptr, + alignment, + root.arena.alloc(ret_stmt), + ); rc_ptr_from_data_ptr( root, @@ -1020,13 +1050,13 @@ fn refcount_union_rec<'a>( ) }; - match ctx.op { - HelperOp::DecRef(_) if null_id.is_none() => rc_contents_then_structure, - HelperOp::Reset => rc_contents_then_structure, - _ => tag_id_stmt(root.arena.alloc( + if ctx.op.is_decref() && null_id.is_none() { + rc_contents_then_structure + } else { + tag_id_stmt(root.arena.alloc( // rc_contents_then_structure, - )), + )) } } diff --git a/compiler/test_gen/src/gen_primitives.rs b/compiler/test_gen/src/gen_primitives.rs index 04d8a122e3..f17090762f 100644 --- a/compiler/test_gen/src/gen_primitives.rs +++ b/compiler/test_gen/src/gen_primitives.rs @@ -16,6 +16,8 @@ use crate::helpers::dev::assert_evals_to; #[cfg(feature = "gen-wasm")] use crate::helpers::wasm::assert_evals_to; +#[cfg(feature = "gen-wasm")] +use crate::helpers::wasm::assert_evals_to as assert_non_opt_evals_to; // #[cfg(feature = "gen-wasm")] // use crate::helpers::dev::assert_expect_failed; // #[cfg(feature = "gen-wasm")] @@ -790,7 +792,7 @@ fn linked_list_sum_int() { } #[test] -#[cfg(any(feature = "gen-llvm"))] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] fn linked_list_map() { assert_non_opt_evals_to!( indoc!( diff --git a/compiler/test_gen/src/helpers/wasm.rs b/compiler/test_gen/src/helpers/wasm.rs index ef22688018..d1d35ae0f9 100644 --- a/compiler/test_gen/src/helpers/wasm.rs +++ b/compiler/test_gen/src/helpers/wasm.rs @@ -8,7 +8,7 @@ use wasmer::{Memory, WasmPtr}; use super::RefCount; use crate::helpers::from_wasmer_memory::FromWasmerMemory; -use roc_collections::all::{MutMap, MutSet}; +use roc_collections::all::MutSet; use roc_gen_wasm::wasm32_result::Wasm32Result; use roc_gen_wasm::{DEBUG_LOG_SETTINGS, MEMORY_NAME};