From 1241d5ccbd624bb65d5f5b86fb03be48bffe61b4 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 28 Nov 2021 14:03:48 +0100 Subject: [PATCH 1/9] make UpdateModeIds a proper type --- compiler/load/src/file.rs | 9 +++++++-- compiler/mono/src/ir.rs | 29 +++++++++++++++++++++-------- reporting/tests/test_reporting.rs | 2 +- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index 4ac1f371e1..ed14abcc95 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -20,6 +20,7 @@ use roc_module::symbol::{ }; use roc_mono::ir::{ CapturedSymbols, EntryPoint, ExternalSpecializations, PartialProc, Proc, ProcLayout, Procs, + UpdateModeIds, }; use roc_mono::layout::{Layout, LayoutCache, LayoutProblem}; use roc_parse::ast::{self, StrLiteral, TypeAnnotation}; @@ -835,6 +836,7 @@ enum Msg<'a> { external_specializations_requested: BumpMap, procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>, problems: Vec, + update_mode_ids: UpdateModeIds, module_timing: ModuleTiming, subs: Subs, }, @@ -3922,6 +3924,7 @@ fn make_specializations<'a>( ) -> Msg<'a> { let make_specializations_start = SystemTime::now(); let mut mono_problems = Vec::new(); + let mut update_mode_ids = UpdateModeIds::new(); // do the thing let mut mono_env = roc_mono::ir::Env { arena, @@ -3930,7 +3933,7 @@ fn make_specializations<'a>( home, ident_ids: &mut ident_ids, ptr_bytes, - update_mode_counter: 0, + update_mode_ids: &mut update_mode_ids, // call_specialization_counter=0 is reserved call_specialization_counter: 1, }; @@ -3973,6 +3976,7 @@ fn make_specializations<'a>( layout_cache, procedures, problems: mono_problems, + update_mode_ids, subs, external_specializations_requested, module_timing, @@ -4016,6 +4020,7 @@ fn build_pending_specializations<'a>( }; let mut mono_problems = std::vec::Vec::new(); + let mut update_mode_ids = UpdateModeIds::new(); let mut subs = solved_subs.into_inner(); let mut mono_env = roc_mono::ir::Env { arena, @@ -4024,7 +4029,7 @@ fn build_pending_specializations<'a>( home, ident_ids: &mut ident_ids, ptr_bytes, - update_mode_counter: 0, + update_mode_ids: &mut update_mode_ids, // call_specialization_counter=0 is reserved call_specialization_counter: 1, }; diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index d4956d4ba9..dabc5b5c05 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -988,7 +988,7 @@ pub struct Env<'a, 'i> { pub home: ModuleId, pub ident_ids: &'i mut IdentIds, pub ptr_bytes: u32, - pub update_mode_counter: u64, + pub update_mode_ids: &'i mut UpdateModeIds, pub call_specialization_counter: u64, } @@ -1000,13 +1000,7 @@ impl<'a, 'i> Env<'a, 'i> { } pub fn next_update_mode_id(&mut self) -> UpdateModeId { - let id = UpdateModeId { - id: self.update_mode_counter, - }; - - self.update_mode_counter += 1; - - id + self.update_mode_ids.next_id() } pub fn next_call_specialization_id(&mut self) -> CallSpecId { @@ -1302,6 +1296,23 @@ impl UpdateModeId { } } +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct UpdateModeIds { + next: u64, +} + +impl UpdateModeIds { + pub const fn new() -> Self { + Self { next: 0 } + } + + fn next_id(&mut self) -> UpdateModeId { + let id = UpdateModeId { id: self.next }; + self.next += 1; + id + } +} + #[derive(Clone, Debug, PartialEq)] pub enum CallType<'a> { ByName { @@ -1390,12 +1401,14 @@ pub enum Expr<'a> { Reuse { symbol: Symbol, update_tag_id: bool, + // update_mode: UpdateModeId, // normal Tag fields tag_layout: UnionLayout<'a>, tag_name: TagName, tag_id: TagIdIntType, arguments: &'a [Symbol], }, + // Reset { symbol: Symbol, update_mode: UpdateModeId, }, Reset(Symbol), RuntimeErrorFunction(&'a str), diff --git a/reporting/tests/test_reporting.rs b/reporting/tests/test_reporting.rs index 735861ebb3..5b16a871c2 100644 --- a/reporting/tests/test_reporting.rs +++ b/reporting/tests/test_reporting.rs @@ -102,7 +102,7 @@ mod test_reporting { home, ident_ids: &mut ident_ids, ptr_bytes, - update_mode_counter: 0, + update_mode_ids: 0, // call_specialization_counter=0 is reserved call_specialization_counter: 1, }; From 0bdda2506cfec10c174e94d9d01d8ffacc8e4584 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 28 Nov 2021 14:13:02 +0100 Subject: [PATCH 2/9] add update mode to reset and reuse --- compiler/gen_dev/src/lib.rs | 4 ++-- compiler/gen_llvm/src/llvm/build.rs | 2 +- compiler/load/src/file.rs | 2 ++ compiler/mono/src/alias_analysis.rs | 2 +- compiler/mono/src/borrow.rs | 2 +- compiler/mono/src/inc_dec.rs | 6 +++--- compiler/mono/src/ir.rs | 26 +++++++++++++++++--------- compiler/mono/src/reset_reuse.rs | 17 +++++++++++++---- 8 files changed, 40 insertions(+), 21 deletions(-) diff --git a/compiler/gen_dev/src/lib.rs b/compiler/gen_dev/src/lib.rs index 6dbd01be28..de56decfac 100644 --- a/compiler/gen_dev/src/lib.rs +++ b/compiler/gen_dev/src/lib.rs @@ -757,8 +757,8 @@ where self.set_last_seen(*sym, stmt, &owning_symbol); } } - Expr::Reset(sym) => { - self.set_last_seen(*sym, stmt, &owning_symbol); + Expr::Reset { symbol, .. } => { + self.set_last_seen(*symbol, stmt, &owning_symbol); } Expr::EmptyArray => {} Expr::RuntimeErrorFunction(_) => {} diff --git a/compiler/gen_llvm/src/llvm/build.rs b/compiler/gen_llvm/src/llvm/build.rs index a5038fc2a5..69168415c0 100644 --- a/compiler/gen_llvm/src/llvm/build.rs +++ b/compiler/gen_llvm/src/llvm/build.rs @@ -1108,7 +1108,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>( .. } => build_tag(env, scope, union_layout, *tag_id, arguments, None, parent), - Reset(symbol) => { + Reset { symbol, .. } => { let (tag_ptr, layout) = load_symbol_and_layout(scope, symbol); let tag_ptr = tag_ptr.into_pointer_value(); diff --git a/compiler/load/src/file.rs b/compiler/load/src/file.rs index ed14abcc95..c75a803ea2 100644 --- a/compiler/load/src/file.rs +++ b/compiler/load/src/file.rs @@ -2100,6 +2100,7 @@ fn update<'a>( MadeSpecializations { module_id, mut ident_ids, + mut update_mode_ids, subs, procedures, external_specializations_requested, @@ -2126,6 +2127,7 @@ fn update<'a>( arena, module_id, &mut ident_ids, + &mut update_mode_ids, &mut state.procedures, ); diff --git a/compiler/mono/src/alias_analysis.rs b/compiler/mono/src/alias_analysis.rs index 88a2b1ce46..5eb480b328 100644 --- a/compiler/mono/src/alias_analysis.rs +++ b/compiler/mono/src/alias_analysis.rs @@ -1626,7 +1626,7 @@ fn expr_spec<'a>( } _ => unreachable!("empty array does not have a list layout"), }, - Reset(symbol) => { + Reset { symbol, .. } => { let type_id = layout_spec(builder, layout)?; let value_id = env.symbols[symbol]; diff --git a/compiler/mono/src/borrow.rs b/compiler/mono/src/borrow.rs index bc5492c8bf..e29eca34ed 100644 --- a/compiler/mono/src/borrow.rs +++ b/compiler/mono/src/borrow.rs @@ -726,7 +726,7 @@ impl<'a> BorrowInfState<'a> { // the function must take it as an owned parameter self.own_args_if_param(xs); } - Reset(x) => { + Reset { symbol: x, .. } => { self.own_var(z); self.own_var(*x); } diff --git a/compiler/mono/src/inc_dec.rs b/compiler/mono/src/inc_dec.rs index c6dfd67314..3eb3896b13 100644 --- a/compiler/mono/src/inc_dec.rs +++ b/compiler/mono/src/inc_dec.rs @@ -110,7 +110,7 @@ pub fn occurring_variables_expr(expr: &Expr<'_>, result: &mut MutSet) { result.extend(arguments.iter().copied()); result.insert(*symbol); } - Reset(x) => { + Reset { symbol: x, .. } => { result.insert(*x); } @@ -761,7 +761,7 @@ impl<'a> Context<'a> { self.arena.alloc(Stmt::Let(z, v, l, b)) } - EmptyArray | Literal(_) | Reset(_) | RuntimeErrorFunction(_) => { + EmptyArray | Literal(_) | Reset { .. } | RuntimeErrorFunction(_) => { // EmptyArray is always stack-allocated // function pointers are persistent self.arena.alloc(Stmt::Let(z, v, l, b)) @@ -779,7 +779,7 @@ impl<'a> Context<'a> { // must this value be consumed? let consume = consume_expr(&self.vars, expr); - let reset = matches!(expr, Expr::Reset(_)); + let reset = matches!(expr, Expr::Reset { .. }); self.update_var_info_help(symbol, layout, persistent, consume, reset) } diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index dabc5b5c05..c2bfe76538 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -31,7 +31,7 @@ pub const PRETTY_PRINT_IR_SYMBOLS: bool = false; static_assertions::assert_eq_size!([u8; 4 * 8], Literal); #[cfg(not(target_arch = "aarch64"))] static_assertions::assert_eq_size!([u8; 3 * 8], Literal); -static_assertions::assert_eq_size!([u8; 10 * 8], Expr); +static_assertions::assert_eq_size!([u8; 11 * 8], Expr); #[cfg(not(target_arch = "aarch64"))] static_assertions::assert_eq_size!([u8; 19 * 8], Stmt); #[cfg(target_arch = "aarch64")] @@ -318,11 +318,17 @@ impl<'a> Proc<'a> { arena: &'a Bump, home: ModuleId, ident_ids: &'i mut IdentIds, + update_mode_ids: &'i mut UpdateModeIds, procs: &mut MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>, ) { for (_, proc) in procs.iter_mut() { - let new_proc = - crate::reset_reuse::insert_reset_reuse(arena, home, ident_ids, proc.clone()); + let new_proc = crate::reset_reuse::insert_reset_reuse( + arena, + home, + ident_ids, + update_mode_ids, + proc.clone(), + ); *proc = new_proc; } } @@ -1306,7 +1312,7 @@ impl UpdateModeIds { Self { next: 0 } } - fn next_id(&mut self) -> UpdateModeId { + pub fn next_id(&mut self) -> UpdateModeId { let id = UpdateModeId { id: self.next }; self.next += 1; id @@ -1401,15 +1407,17 @@ pub enum Expr<'a> { Reuse { symbol: Symbol, update_tag_id: bool, - // update_mode: UpdateModeId, + update_mode: UpdateModeId, // normal Tag fields tag_layout: UnionLayout<'a>, tag_name: TagName, tag_id: TagIdIntType, arguments: &'a [Symbol], }, - // Reset { symbol: Symbol, update_mode: UpdateModeId, }, - Reset(Symbol), + Reset { + symbol: Symbol, + update_mode: UpdateModeId, + }, RuntimeErrorFunction(&'a str), } @@ -1525,7 +1533,7 @@ impl<'a> Expr<'a> { .append(alloc.space()) .append(alloc.intersperse(it, " ")) } - Reset(symbol) => alloc.text("Reset ").append(symbol_to_doc(alloc, *symbol)), + Reset { symbol, .. } => alloc.text("Reset ").append(symbol_to_doc(alloc, *symbol)), Struct(args) => { let it = args.iter().map(|s| symbol_to_doc(alloc, *s)); @@ -5728,7 +5736,7 @@ fn substitute_in_expr<'a>( } } - Reuse { .. } | Reset(_) => unreachable!("reset/reuse have not been introduced yet"), + Reuse { .. } | Reset { .. } => unreachable!("reset/reuse have not been introduced yet"), Struct(args) => { let mut did_change = false; diff --git a/compiler/mono/src/reset_reuse.rs b/compiler/mono/src/reset_reuse.rs index cf8ecff9cf..2cba3eb638 100644 --- a/compiler/mono/src/reset_reuse.rs +++ b/compiler/mono/src/reset_reuse.rs @@ -1,5 +1,5 @@ use crate::inc_dec::{collect_stmt, occurring_variables_expr, JPLiveVarMap, LiveVarSet}; -use crate::ir::{BranchInfo, Call, Expr, ListLiteralElement, Proc, Stmt}; +use crate::ir::{BranchInfo, Call, Expr, ListLiteralElement, Proc, Stmt, UpdateModeIds}; use crate::layout::{Layout, TagIdIntType, UnionLayout}; use bumpalo::collections::Vec; use bumpalo::Bump; @@ -10,12 +10,14 @@ pub fn insert_reset_reuse<'a, 'i>( arena: &'a Bump, home: ModuleId, ident_ids: &'i mut IdentIds, + update_mode_ids: &'i mut UpdateModeIds, mut proc: Proc<'a>, ) -> Proc<'a> { let mut env = Env { arena, home, ident_ids, + update_mode_ids, jp_live_vars: Default::default(), }; @@ -50,6 +52,7 @@ struct Env<'a, 'i> { /// required for creating new `Symbol`s home: ModuleId, ident_ids: &'i mut IdentIds, + update_mode_ids: &'i mut UpdateModeIds, jp_live_vars: JPLiveVarMap, } @@ -82,10 +85,12 @@ fn function_s<'a, 'i>( } if may_reuse(*tag_layout, *tag_id, c) => { // for now, always overwrite the tag ID just to be sure let update_tag_id = true; + let update_mode = env.update_mode_ids.next_id(); let new_expr = Expr::Reuse { symbol: w, update_tag_id, + update_mode, tag_layout: *tag_layout, tag_id: *tag_id, tag_name: tag_name.clone(), @@ -216,12 +221,16 @@ fn insert_reset<'a>( | Array { .. } | EmptyArray | Reuse { .. } - | Reset(_) + | Reset { .. } | RuntimeErrorFunction(_) => break, } } - let reset_expr = Expr::Reset(x); + let update_mode = env.update_mode_ids.next_id(); + let reset_expr = Expr::Reset { + symbol: x, + update_mode, + }; let layout = Layout::Union(union_layout); @@ -584,7 +593,7 @@ fn has_live_var_expr<'a>(expr: &'a Expr<'a>, needle: Symbol) -> bool { Expr::Reuse { symbol, arguments, .. } => needle == *symbol || arguments.iter().any(|s| *s == needle), - Expr::Reset(symbol) => needle == *symbol, + Expr::Reset { symbol, .. } => needle == *symbol, Expr::RuntimeErrorFunction(_) => false, } } From aefe719e56a9a828a45df47ef377afd7c9cb6165 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 28 Nov 2021 14:25:51 +0100 Subject: [PATCH 3/9] hook up update mode for reset/reuse --- compiler/mono/src/ir.rs | 11 ++++++++++- compiler/mono/src/reset_reuse.rs | 31 +++++++++++++++++++++---------- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index c2bfe76538..52e54bd195 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -1512,6 +1512,7 @@ impl<'a> Expr<'a> { symbol, tag_name, arguments, + update_mode, .. } => { let doc_tag = match tag_name { @@ -1529,11 +1530,19 @@ impl<'a> Expr<'a> { .text("Reuse ") .append(symbol_to_doc(alloc, *symbol)) .append(alloc.space()) + .append(format!("{:?}", update_mode)) + .append(alloc.space()) .append(doc_tag) .append(alloc.space()) .append(alloc.intersperse(it, " ")) } - Reset { symbol, .. } => alloc.text("Reset ").append(symbol_to_doc(alloc, *symbol)), + Reset { + symbol, + update_mode, + } => alloc.text(format!( + "Reset {{ symbol: {:?}, id: {} }}", + symbol, update_mode.id + )), Struct(args) => { let it = args.iter().map(|s| symbol_to_doc(alloc, *s)); diff --git a/compiler/mono/src/reset_reuse.rs b/compiler/mono/src/reset_reuse.rs index 2cba3eb638..fc63890d73 100644 --- a/compiler/mono/src/reset_reuse.rs +++ b/compiler/mono/src/reset_reuse.rs @@ -1,5 +1,7 @@ use crate::inc_dec::{collect_stmt, occurring_variables_expr, JPLiveVarMap, LiveVarSet}; -use crate::ir::{BranchInfo, Call, Expr, ListLiteralElement, Proc, Stmt, UpdateModeIds}; +use crate::ir::{ + BranchInfo, Call, Expr, ListLiteralElement, Proc, Stmt, UpdateModeId, UpdateModeIds, +}; use crate::layout::{Layout, TagIdIntType, UnionLayout}; use bumpalo::collections::Vec; use bumpalo::Bump; @@ -67,7 +69,7 @@ impl<'a, 'i> Env<'a, 'i> { fn function_s<'a, 'i>( env: &mut Env<'a, 'i>, - w: Symbol, + w: Opportunity, c: &CtorInfo<'a>, stmt: &'a Stmt<'a>, ) -> &'a Stmt<'a> { @@ -85,12 +87,11 @@ fn function_s<'a, 'i>( } if may_reuse(*tag_layout, *tag_id, c) => { // for now, always overwrite the tag ID just to be sure let update_tag_id = true; - let update_mode = env.update_mode_ids.next_id(); let new_expr = Expr::Reuse { - symbol: w, + symbol: w.symbol, + update_mode: w.update_mode, update_tag_id, - update_mode, tag_layout: *tag_layout, tag_id: *tag_id, tag_name: tag_name.clone(), @@ -180,13 +181,22 @@ fn function_s<'a, 'i>( } } +#[derive(Clone, Copy)] +struct Opportunity { + symbol: Symbol, + update_mode: UpdateModeId, +} + fn try_function_s<'a, 'i>( env: &mut Env<'a, 'i>, x: Symbol, c: &CtorInfo<'a>, stmt: &'a Stmt<'a>, ) -> &'a Stmt<'a> { - let w = env.unique_symbol(); + let w = Opportunity { + symbol: env.unique_symbol(), + update_mode: env.update_mode_ids.next_id(), + }; let new_stmt = function_s(env, w, c, stmt); @@ -199,7 +209,7 @@ fn try_function_s<'a, 'i>( fn insert_reset<'a>( env: &mut Env<'a, '_>, - w: Symbol, + w: Opportunity, x: Symbol, union_layout: UnionLayout<'a>, mut stmt: &'a Stmt<'a>, @@ -226,15 +236,16 @@ fn insert_reset<'a>( } } - let update_mode = env.update_mode_ids.next_id(); let reset_expr = Expr::Reset { symbol: x, - update_mode, + update_mode: w.update_mode, }; let layout = Layout::Union(union_layout); - stmt = env.arena.alloc(Stmt::Let(w, reset_expr, layout, stmt)); + stmt = env + .arena + .alloc(Stmt::Let(w.symbol, reset_expr, layout, stmt)); for (symbol, expr, expr_layout) in stack.into_iter().rev() { stmt = env From e110f5137fc207cdafb38066d6ff8bb0135739bd Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 28 Nov 2021 15:41:36 +0100 Subject: [PATCH 4/9] fix test compilation failure --- reporting/tests/test_reporting.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/reporting/tests/test_reporting.rs b/reporting/tests/test_reporting.rs index 5b16a871c2..948860825c 100644 --- a/reporting/tests/test_reporting.rs +++ b/reporting/tests/test_reporting.rs @@ -13,7 +13,7 @@ mod test_reporting { use crate::helpers::{can_expr, infer_expr, CanExprOut, ParseErrOut}; use bumpalo::Bump; use roc_module::symbol::{Interns, ModuleId}; - use roc_mono::ir::{Procs, Stmt}; + use roc_mono::ir::{Procs, Stmt, UpdateModeIds}; use roc_mono::layout::LayoutCache; use roc_reporting::report::{ can_problem, mono_problem, parse_problem, type_problem, Report, Severity, BLUE_CODE, @@ -91,6 +91,7 @@ mod test_reporting { // Compile and add all the Procs before adding main let mut procs = Procs::new_in(&arena); let mut ident_ids = interns.all_ident_ids.remove(&home).unwrap(); + let mut update_mode_ids = UpdateModeIds::new(); // Populate Procs and Subs, and get the low-level Expr from the canonical Expr let ptr_bytes = 8; @@ -101,8 +102,8 @@ mod test_reporting { problems: &mut mono_problems, home, ident_ids: &mut ident_ids, + update_mode_ids: &mut update_mode_ids, ptr_bytes, - update_mode_ids: 0, // call_specialization_counter=0 is reserved call_specialization_counter: 1, }; From 537cf69344ccce254bd776f0ef8d248a8f4ee199 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 28 Nov 2021 15:41:46 +0100 Subject: [PATCH 5/9] add helper for adding a heap cell to values --- compiler/mono/src/alias_analysis.rs | 49 ++++++++++++++--------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/compiler/mono/src/alias_analysis.rs b/compiler/mono/src/alias_analysis.rs index 5eb480b328..c2c2a53fbe 100644 --- a/compiler/mono/src/alias_analysis.rs +++ b/compiler/mono/src/alias_analysis.rs @@ -867,8 +867,7 @@ fn call_spec( builder.add_update(block, update_mode_var, cell)?; - let new_cell = builder.add_new_heap_cell(block)?; - builder.add_make_tuple(block, &[new_cell, bag]) + with_new_heap_cell(builder, block, bag) }; let state_layout = Layout::Builtin(Builtin::List(&arg_layouts[0])); @@ -998,9 +997,8 @@ fn call_spec( builder.add_recursive_touch(block, removed_element)?; let new_bag = builder.add_get_tuple_field(block, removed, 0)?; - let new_cell = builder.add_new_heap_cell(block)?; - builder.add_make_tuple(block, &[new_cell, new_bag]) + with_new_heap_cell(builder, block, new_bag) }; let state_layout = Layout::Builtin(Builtin::List(&arg_layouts[0])); @@ -1181,8 +1179,7 @@ fn list_append( let new_bag = builder.add_bag_insert(block, bag, to_insert)?; - let new_cell = builder.add_new_heap_cell(block)?; - builder.add_make_tuple(block, &[new_cell, new_bag]) + with_new_heap_cell(builder, block, new_bag) } fn lowlevel_spec( @@ -1268,8 +1265,7 @@ fn lowlevel_spec( builder.add_bag_insert(block, bag, to_insert)?; - let new_cell = builder.add_new_heap_cell(block)?; - builder.add_make_tuple(block, &[new_cell, bag]) + with_new_heap_cell(builder, block, bag) } ListSwap => { let list = env.symbols[&arguments[0]]; @@ -1279,8 +1275,7 @@ fn lowlevel_spec( let _unit = builder.add_update(block, update_mode_var, cell)?; - let new_cell = builder.add_new_heap_cell(block)?; - builder.add_make_tuple(block, &[new_cell, bag]) + with_new_heap_cell(builder, block, bag) } ListReverse => { let list = env.symbols[&arguments[0]]; @@ -1290,8 +1285,7 @@ fn lowlevel_spec( let _unit = builder.add_update(block, update_mode_var, cell)?; - let new_cell = builder.add_new_heap_cell(block)?; - builder.add_make_tuple(block, &[new_cell, bag]) + with_new_heap_cell(builder, block, bag) } ListAppend => { let list = env.symbols[&arguments[0]]; @@ -1359,8 +1353,7 @@ fn lowlevel_spec( builder.add_bag_insert(block, bag, key_value)?; - let new_cell = builder.add_new_heap_cell(block)?; - builder.add_make_tuple(block, &[new_cell, bag]) + with_new_heap_cell(builder, block, bag) } _other => { // println!("missing {:?}", _other); @@ -1485,7 +1478,6 @@ fn expr_spec<'a>( let variant_types = build_variant_types(builder, tag_layout)?; let data_id = build_tuple_value(builder, env, block, arguments)?; - let cell_id = builder.add_new_heap_cell(block)?; let value_id = match tag_layout { UnionLayout::NonRecursive(_) => { @@ -1493,7 +1485,7 @@ fn expr_spec<'a>( return builder.add_make_union(block, &variant_types, *tag_id as u32, value_id); } UnionLayout::NonNullableUnwrapped(_) => { - let value_id = builder.add_make_tuple(block, &[cell_id, data_id])?; + let value_id = with_new_heap_cell(builder, block, data_id)?; let type_name_bytes = recursive_tag_union_name_bytes(tag_layout).as_bytes(); let type_name = TypeName(&type_name_bytes); @@ -1502,19 +1494,19 @@ fn expr_spec<'a>( return builder.add_make_named(block, MOD_APP, type_name, value_id); } - UnionLayout::Recursive(_) => builder.add_make_tuple(block, &[cell_id, data_id])?, + UnionLayout::Recursive(_) => with_new_heap_cell(builder, block, data_id)?, UnionLayout::NullableWrapped { nullable_id, .. } => { if *tag_id == *nullable_id as _ { data_id } else { - builder.add_make_tuple(block, &[cell_id, data_id])? + with_new_heap_cell(builder, block, data_id)? } } UnionLayout::NullableUnwrapped { nullable_id, .. } => { if *tag_id == *nullable_id as _ { data_id } else { - builder.add_make_tuple(block, &[cell_id, data_id])? + with_new_heap_cell(builder, block, data_id)? } } }; @@ -1613,9 +1605,7 @@ fn expr_spec<'a>( if all_constants { new_static_list(builder, block) } else { - let cell = builder.add_new_heap_cell(block)?; - - builder.add_make_tuple(block, &[cell, bag]) + with_new_heap_cell(builder, block, bag) } } @@ -1777,10 +1767,18 @@ const LIST_BAG_INDEX: u32 = 1; const DICT_CELL_INDEX: u32 = LIST_CELL_INDEX; const DICT_BAG_INDEX: u32 = LIST_BAG_INDEX; -fn new_list(builder: &mut FuncDefBuilder, block: BlockId, element_type: TypeId) -> Result { +fn with_new_heap_cell( + builder: &mut FuncDefBuilder, + block: BlockId, + value: ValueId, +) -> Result { let cell = builder.add_new_heap_cell(block)?; + builder.add_make_tuple(block, &[cell, value]) +} + +fn new_list(builder: &mut FuncDefBuilder, block: BlockId, element_type: TypeId) -> Result { let bag = builder.add_empty_bag(block, element_type)?; - builder.add_make_tuple(block, &[cell, bag]) + with_new_heap_cell(builder, block, bag) } fn new_dict( @@ -1789,10 +1787,9 @@ fn new_dict( key_type: TypeId, value_type: TypeId, ) -> Result { - let cell = builder.add_new_heap_cell(block)?; let element_type = builder.add_tuple_type(&[key_type, value_type])?; let bag = builder.add_empty_bag(block, element_type)?; - builder.add_make_tuple(block, &[cell, bag]) + with_new_heap_cell(builder, block, bag) } fn new_static_string(builder: &mut FuncDefBuilder, block: BlockId) -> Result { From 8bcb985a8022869606338c8ac89262df631efb24 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 28 Nov 2021 15:53:05 +0100 Subject: [PATCH 6/9] always also add heap cell to nulled tags --- compiler/mono/src/alias_analysis.rs | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/compiler/mono/src/alias_analysis.rs b/compiler/mono/src/alias_analysis.rs index c2c2a53fbe..c72f014fed 100644 --- a/compiler/mono/src/alias_analysis.rs +++ b/compiler/mono/src/alias_analysis.rs @@ -1418,8 +1418,7 @@ fn build_variant_types( result.push(recursive_tag_variant(builder, union_layout, tag)?); } - let unit = builder.add_tuple_type(&[])?; - result.push(unit); + result.push(recursive_tag_variant(builder, union_layout, &[])?); for tag in tags[cutoff..].iter() { result.push(recursive_tag_variant(builder, union_layout, tag)?); @@ -1429,7 +1428,7 @@ fn build_variant_types( nullable_id, other_fields: fields, } => { - let unit = builder.add_tuple_type(&[])?; + let unit = recursive_tag_variant(builder, union_layout, &[])?; let other_type = recursive_tag_variant(builder, union_layout, fields)?; if *nullable_id { @@ -1495,19 +1494,9 @@ fn expr_spec<'a>( return builder.add_make_named(block, MOD_APP, type_name, value_id); } UnionLayout::Recursive(_) => with_new_heap_cell(builder, block, data_id)?, - UnionLayout::NullableWrapped { nullable_id, .. } => { - if *tag_id == *nullable_id as _ { - data_id - } else { - with_new_heap_cell(builder, block, data_id)? - } - } - UnionLayout::NullableUnwrapped { nullable_id, .. } => { - if *tag_id == *nullable_id as _ { - data_id - } else { - with_new_heap_cell(builder, block, data_id)? - } + UnionLayout::NullableWrapped { .. } => with_new_heap_cell(builder, block, data_id)?, + UnionLayout::NullableUnwrapped { .. } => { + with_new_heap_cell(builder, block, data_id)? } }; From 92cca127b111cee5cc9dd9bb03e039e06069069b Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 28 Nov 2021 15:58:30 +0100 Subject: [PATCH 7/9] refactor --- compiler/mono/src/alias_analysis.rs | 39 ++++++++++++++++++----------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/compiler/mono/src/alias_analysis.rs b/compiler/mono/src/alias_analysis.rs index c72f014fed..0faf4d3052 100644 --- a/compiler/mono/src/alias_analysis.rs +++ b/compiler/mono/src/alias_analysis.rs @@ -210,7 +210,7 @@ where let mut builder = TypeDefBuilder::new(); - let variant_types = build_variant_types(&mut builder, &union_layout)?; + let variant_types = recursive_variant_types(&mut builder, &union_layout)?; let root_type = if let UnionLayout::NonNullableUnwrapped(_) = union_layout { debug_assert_eq!(variant_types.len(), 1); variant_types[0] @@ -1380,7 +1380,7 @@ fn recursive_tag_variant( builder.add_tuple_type(&[cell_id, data_id]) } -fn build_variant_types( +fn recursive_variant_types( builder: &mut impl TypeContext, union_layout: &UnionLayout, ) -> Result> { @@ -1389,12 +1389,8 @@ fn build_variant_types( let mut result; match union_layout { - NonRecursive(tags) => { - result = Vec::with_capacity(tags.len()); - - for tag in tags.iter() { - result.push(build_tuple_type(builder, tag)?); - } + NonRecursive(_) => { + unreachable!() } Recursive(tags) => { result = Vec::with_capacity(tags.len()); @@ -1474,12 +1470,11 @@ fn expr_spec<'a>( tag_id, arguments, } => { - let variant_types = build_variant_types(builder, tag_layout)?; - let data_id = build_tuple_value(builder, env, block, arguments)?; let value_id = match tag_layout { - UnionLayout::NonRecursive(_) => { + UnionLayout::NonRecursive(tags) => { + let variant_types = non_recursive_variant_types(builder, tags)?; let value_id = build_tuple_value(builder, env, block, arguments)?; return builder.add_make_union(block, &variant_types, *tag_id as u32, value_id); } @@ -1500,6 +1495,8 @@ fn expr_spec<'a>( } }; + let variant_types = recursive_variant_types(builder, tag_layout)?; + let union_id = builder.add_make_union(block, &variant_types, *tag_id as u32, value_id)?; @@ -1637,6 +1634,19 @@ fn layout_spec(builder: &mut impl TypeContext, layout: &Layout) -> Result Result> { + let mut result = Vec::with_capacity(tags.len()); + + for tag in tags.iter() { + result.push(build_tuple_type(builder, tag)?); + } + + Ok(result) +} + fn layout_spec_help( builder: &mut impl TypeContext, layout: &Layout, @@ -1653,8 +1663,6 @@ fn layout_spec_help( when_recursive, ), Union(union_layout) => { - let variant_types = build_variant_types(builder, union_layout)?; - match union_layout { UnionLayout::NonRecursive(&[]) => { // must model Void as Unit, otherwise we run into problems where @@ -1662,7 +1670,10 @@ fn layout_spec_help( // which is of course not possible builder.add_tuple_type(&[]) } - UnionLayout::NonRecursive(_) => builder.add_union_type(&variant_types), + UnionLayout::NonRecursive(tags) => { + let variant_types = non_recursive_variant_types(builder, tags)?; + builder.add_union_type(&variant_types) + } UnionLayout::Recursive(_) | UnionLayout::NullableUnwrapped { .. } | UnionLayout::NullableWrapped { .. } From 5b8c63d29292cca46736d2d81c629c7a8e419b98 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 28 Nov 2021 17:51:43 +0100 Subject: [PATCH 8/9] move the heap cell out of the union --- compiler/mono/src/alias_analysis.rs | 59 ++++++++++++++++++----------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/compiler/mono/src/alias_analysis.rs b/compiler/mono/src/alias_analysis.rs index 0faf4d3052..0803bac802 100644 --- a/compiler/mono/src/alias_analysis.rs +++ b/compiler/mono/src/alias_analysis.rs @@ -215,7 +215,10 @@ where debug_assert_eq!(variant_types.len(), 1); variant_types[0] } else { - builder.add_union_type(&variant_types)? + let data_type = builder.add_union_type(&variant_types)?; + let cell_type = builder.add_heap_cell_type(); + + builder.add_tuple_type(&[cell_type, data_type])? }; let type_def = builder.build(root_type)?; @@ -1374,10 +1377,7 @@ fn recursive_tag_variant( ) -> Result { let when_recursive = WhenRecursive::Loop(*union_layout); - let data_id = build_recursive_tuple_type(builder, fields, &when_recursive)?; - let cell_id = builder.add_heap_cell_type(); - - builder.add_tuple_type(&[cell_id, data_id]) + build_recursive_tuple_type(builder, fields, &when_recursive) } fn recursive_variant_types( @@ -1479,7 +1479,7 @@ fn expr_spec<'a>( return builder.add_make_union(block, &variant_types, *tag_id as u32, value_id); } UnionLayout::NonNullableUnwrapped(_) => { - let value_id = with_new_heap_cell(builder, block, data_id)?; + let value_id = data_id; let type_name_bytes = recursive_tag_union_name_bytes(tag_layout).as_bytes(); let type_name = TypeName(&type_name_bytes); @@ -1488,11 +1488,9 @@ fn expr_spec<'a>( return builder.add_make_named(block, MOD_APP, type_name, value_id); } - UnionLayout::Recursive(_) => with_new_heap_cell(builder, block, data_id)?, - UnionLayout::NullableWrapped { .. } => with_new_heap_cell(builder, block, data_id)?, - UnionLayout::NullableUnwrapped { .. } => { - with_new_heap_cell(builder, block, data_id)? - } + UnionLayout::Recursive(_) => data_id, + UnionLayout::NullableWrapped { .. } => data_id, + UnionLayout::NullableUnwrapped { .. } => data_id, }; let variant_types = recursive_variant_types(builder, tag_layout)?; @@ -1500,12 +1498,14 @@ fn expr_spec<'a>( let union_id = builder.add_make_union(block, &variant_types, *tag_id as u32, value_id)?; + let tag_value_id = with_new_heap_cell(builder, block, union_id)?; + let type_name_bytes = recursive_tag_union_name_bytes(tag_layout).as_bytes(); let type_name = TypeName(&type_name_bytes); env.type_names.insert(*tag_layout); - builder.add_make_named(block, MOD_APP, type_name, union_id) + builder.add_make_named(block, MOD_APP, type_name, tag_value_id) } Struct(fields) => build_tuple_value(builder, env, block, fields), UnionAtIndex { @@ -1531,16 +1531,20 @@ fn expr_spec<'a>( let type_name_bytes = recursive_tag_union_name_bytes(union_layout).as_bytes(); let type_name = TypeName(&type_name_bytes); + // unwrap the named wrapper let union_id = builder.add_unwrap_named(block, MOD_APP, type_name, tag_value_id)?; - let variant_id = builder.add_unwrap_union(block, union_id, *tag_id as u32)?; + + // now we have a tuple (cell, union { ... }); decompose + let heap_cell = builder.add_get_tuple_field(block, union_id, TAG_CELL_INDEX)?; + let union_data = builder.add_get_tuple_field(block, union_id, TAG_DATA_INDEX)?; // we're reading from this value, so touch the heap cell - let heap_cell = builder.add_get_tuple_field(block, variant_id, 0)?; builder.add_touch(block, heap_cell)?; - let tuple_value_id = builder.add_get_tuple_field(block, variant_id, 1)?; + // next, unwrap the union at the tag id that we've got + let variant_id = builder.add_unwrap_union(block, union_data, *tag_id as u32)?; - builder.add_get_tuple_field(block, tuple_value_id, index) + builder.add_get_tuple_field(block, variant_id, index) } UnionLayout::NonNullableUnwrapped { .. } => { let index = (*index) as u32; @@ -1551,16 +1555,20 @@ fn expr_spec<'a>( let type_name_bytes = recursive_tag_union_name_bytes(union_layout).as_bytes(); let type_name = TypeName(&type_name_bytes); - let variant_id = - builder.add_unwrap_named(block, MOD_APP, type_name, tag_value_id)?; + // a tuple ( cell, union { ... } ) + let union_id = builder.add_unwrap_named(block, MOD_APP, type_name, tag_value_id)?; + + // decompose + let heap_cell = builder.add_get_tuple_field(block, union_id, TAG_CELL_INDEX)?; + let union_data = builder.add_get_tuple_field(block, union_id, TAG_DATA_INDEX)?; // we're reading from this value, so touch the heap cell - let heap_cell = builder.add_get_tuple_field(block, variant_id, 0)?; builder.add_touch(block, heap_cell)?; - let tuple_value_id = builder.add_get_tuple_field(block, variant_id, 1)?; + // next, unwrap the union at the tag id that we've got + let variant_id = builder.add_unwrap_union(block, union_data, *tag_id as u32)?; - builder.add_get_tuple_field(block, tuple_value_id, index) + builder.add_get_tuple_field(block, variant_id, index) } }, StructAtIndex { @@ -1613,7 +1621,11 @@ fn expr_spec<'a>( builder.add_terminate(block, type_id) } - GetTagId { .. } => builder.add_make_tuple(block, &[]), + GetTagId { .. } => { + // TODO touch heap cell in recursive cases + + builder.add_make_tuple(block, &[]) + } } } @@ -1767,6 +1779,9 @@ const LIST_BAG_INDEX: u32 = 1; const DICT_CELL_INDEX: u32 = LIST_CELL_INDEX; const DICT_BAG_INDEX: u32 = LIST_BAG_INDEX; +const TAG_CELL_INDEX: u32 = 0; +const TAG_DATA_INDEX: u32 = 1; + fn with_new_heap_cell( builder: &mut FuncDefBuilder, block: BlockId, From ab1787937d051a695d6c993483197b848640e725 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 28 Nov 2021 22:59:23 +0100 Subject: [PATCH 9/9] shrink CallSpecId and UpdateModeId to u32; assuming a 4GiB file that should be more than enough --- compiler/mono/src/ir.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index 52e54bd195..5ba8154c2b 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -31,14 +31,14 @@ pub const PRETTY_PRINT_IR_SYMBOLS: bool = false; static_assertions::assert_eq_size!([u8; 4 * 8], Literal); #[cfg(not(target_arch = "aarch64"))] static_assertions::assert_eq_size!([u8; 3 * 8], Literal); -static_assertions::assert_eq_size!([u8; 11 * 8], Expr); +static_assertions::assert_eq_size!([u8; 10 * 8], Expr); #[cfg(not(target_arch = "aarch64"))] static_assertions::assert_eq_size!([u8; 19 * 8], Stmt); #[cfg(target_arch = "aarch64")] static_assertions::assert_eq_size!([u8; 20 * 8], Stmt); static_assertions::assert_eq_size!([u8; 6 * 8], ProcLayout); -static_assertions::assert_eq_size!([u8; 8 * 8], Call); -static_assertions::assert_eq_size!([u8; 6 * 8], CallType); +static_assertions::assert_eq_size!([u8; 7 * 8], Call); +static_assertions::assert_eq_size!([u8; 5 * 8], CallType); macro_rules! return_on_layout_error { ($env:expr, $layout_result:expr) => { @@ -995,7 +995,7 @@ pub struct Env<'a, 'i> { pub ident_ids: &'i mut IdentIds, pub ptr_bytes: u32, pub update_mode_ids: &'i mut UpdateModeIds, - pub call_specialization_counter: u64, + pub call_specialization_counter: u32, } impl<'a, 'i> Env<'a, 'i> { @@ -1282,29 +1282,29 @@ impl<'a> Call<'a> { #[derive(Clone, Copy, Debug, PartialEq)] pub struct CallSpecId { - id: u64, + id: u32, } impl CallSpecId { - pub fn to_bytes(self) -> [u8; 8] { + pub fn to_bytes(self) -> [u8; 4] { self.id.to_ne_bytes() } } #[derive(Clone, Copy, Debug, PartialEq)] pub struct UpdateModeId { - id: u64, + id: u32, } impl UpdateModeId { - pub fn to_bytes(self) -> [u8; 8] { + pub fn to_bytes(self) -> [u8; 4] { self.id.to_ne_bytes() } } #[derive(Clone, Copy, Debug, PartialEq)] pub struct UpdateModeIds { - next: u64, + next: u32, } impl UpdateModeIds {