From 48d2f53eb199067fee5ca67bb1b574e1bf3a511d Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 25 Jul 2021 12:50:42 +0200 Subject: [PATCH 01/15] create a new heap cell after modification --- compiler/mono/src/alias_analysis.rs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/compiler/mono/src/alias_analysis.rs b/compiler/mono/src/alias_analysis.rs index 2f43fd13db..efe7c01712 100644 --- a/compiler/mono/src/alias_analysis.rs +++ b/compiler/mono/src/alias_analysis.rs @@ -842,7 +842,19 @@ fn lowlevel_spec( builder.add_bag_insert(block, bag, to_insert)?; - Ok(list) + let new_cell = builder.add_new_heap_cell(block)?; + builder.add_make_tuple(block, &[new_cell, bag]) + } + ListSwap => { + let list = env.symbols[&arguments[0]]; + + let bag = builder.add_get_tuple_field(block, list, LIST_BAG_INDEX)?; + let cell = builder.add_get_tuple_field(block, list, LIST_CELL_INDEX)?; + + 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]) } ListAppend => { let list = env.symbols[&arguments[0]]; @@ -853,9 +865,11 @@ fn lowlevel_spec( let _unit = builder.add_update(block, update_mode_var, cell)?; + // TODO new heap cell builder.add_bag_insert(block, bag, to_insert)?; - Ok(list) + let new_cell = builder.add_new_heap_cell(block)?; + builder.add_make_tuple(block, &[new_cell, bag]) } DictEmpty => { match layout { @@ -887,7 +901,6 @@ fn lowlevel_spec( let cell = builder.add_get_tuple_field(block, dict, DICT_CELL_INDEX)?; let _unit = builder.add_touch(block, cell)?; - builder.add_bag_get(block, bag) } DictInsert => { @@ -904,7 +917,8 @@ fn lowlevel_spec( builder.add_bag_insert(block, bag, key_value)?; - Ok(dict) + let new_cell = builder.add_new_heap_cell(block)?; + builder.add_make_tuple(block, &[new_cell, bag]) } _other => { // println!("missing {:?}", _other); From 5bb66a6b8e1a8de35870513c761d964def7dd213 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 25 Jul 2021 13:24:11 +0200 Subject: [PATCH 02/15] intern layouts --- compiler/mono/src/borrow.rs | 58 +++++++++++++++++++++++++++--------- compiler/mono/src/inc_dec.rs | 22 +++++++------- 2 files changed, 54 insertions(+), 26 deletions(-) diff --git a/compiler/mono/src/borrow.rs b/compiler/mono/src/borrow.rs index be0aa9bb1d..07554e25c7 100644 --- a/compiler/mono/src/borrow.rs +++ b/compiler/mono/src/borrow.rs @@ -2,7 +2,7 @@ use crate::ir::{Expr, JoinPointId, Param, Proc, ProcLayout, Stmt}; use crate::layout::Layout; use bumpalo::collections::Vec; use bumpalo::Bump; -use roc_collections::all::{MutMap, MutSet}; +use roc_collections::all::{default_hasher, MutMap, MutSet}; use roc_module::low_level::LowLevel; use roc_module::symbol::Symbol; @@ -20,7 +20,15 @@ pub fn infer_borrow<'a>( arena: &'a Bump, procs: &MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>, ) -> ParamMap<'a> { + // intern the layouts + let mut declaration_to_index = MutMap::with_capacity_and_hasher(procs.len(), default_hasher()); + + for (i, key) in procs.keys().enumerate() { + declaration_to_index.insert(*key, DeclarationId(i)); + } + let mut param_map = ParamMap { + declaration_to_index, items: MutMap::default(), }; @@ -66,19 +74,25 @@ pub fn infer_borrow<'a>( } #[derive(Debug, PartialEq, Eq, Hash, Clone)] -pub enum Key<'a> { - Declaration(Symbol, ProcLayout<'a>), +pub enum Key { + Declaration(DeclarationId), JoinPoint(JoinPointId), } +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +pub struct DeclarationId(usize); + #[derive(Debug, Clone, Default)] pub struct ParamMap<'a> { - items: MutMap, &'a [Param<'a>]>, + declaration_to_index: MutMap<(Symbol, ProcLayout<'a>), DeclarationId>, + items: MutMap]>, + // declarations: Vec<'a, &'a [Param<'a>]>, + // join_points: Vec<'a, &'a [Param<'a>]>, } impl<'a> IntoIterator for ParamMap<'a> { - type Item = (Key<'a>, &'a [Param<'a>]); - type IntoIter = , &'a [Param<'a>]> as IntoIterator>::IntoIter; + type Item = (Key, &'a [Param<'a>]); + type IntoIter = ]> as IntoIterator>::IntoIter; fn into_iter(self) -> Self::IntoIter { self.items.into_iter() @@ -86,9 +100,8 @@ impl<'a> IntoIterator for ParamMap<'a> { } impl<'a> IntoIterator for &'a ParamMap<'a> { - type Item = (&'a Key<'a>, &'a &'a [Param<'a>]); - type IntoIter = - <&'a std::collections::HashMap, &'a [Param<'a>]> as IntoIterator>::IntoIter; + type Item = (&'a Key, &'a &'a [Param<'a>]); + type IntoIter = <&'a std::collections::HashMap]> as IntoIterator>::IntoIter; fn into_iter(self) -> Self::IntoIter { self.items.iter() @@ -97,7 +110,8 @@ impl<'a> IntoIterator for &'a ParamMap<'a> { impl<'a> ParamMap<'a> { pub fn get_symbol(&self, symbol: Symbol, layout: ProcLayout<'a>) -> Option<&'a [Param<'a>]> { - let key = Key::Declaration(symbol, layout); + let index = self.declaration_to_index[&(symbol, layout)]; + let key = Key::Declaration(index); self.items.get(&key).copied() } @@ -109,6 +123,10 @@ impl<'a> ParamMap<'a> { None => unreachable!("join point not in param map: {:?}", id), } } + + pub fn iter_symbols(&'a self) -> impl Iterator { + self.declaration_to_index.iter().map(|t| &t.0 .0) + } } impl<'a> ParamMap<'a> { @@ -156,8 +174,11 @@ impl<'a> ParamMap<'a> { self.visit_proc_always_owned(arena, proc, key); return; } + + let index = self.declaration_to_index[&key]; + let already_in_there = self.items.insert( - Key::Declaration(proc.name, key.1), + Key::Declaration(index), Self::init_borrow_args(arena, proc.args), ); debug_assert!(already_in_there.is_none()); @@ -171,8 +192,10 @@ impl<'a> ParamMap<'a> { proc: &Proc<'a>, key: (Symbol, ProcLayout<'a>), ) { + let index = self.declaration_to_index[&key]; + let already_in_there = self.items.insert( - Key::Declaration(proc.name, key.1), + Key::Declaration(index), Self::init_borrow_args_always_owned(arena, proc.args), ); debug_assert!(already_in_there.is_none()); @@ -263,7 +286,14 @@ impl<'a> BorrowInfState<'a> { } } - fn update_param_map(&mut self, k: Key<'a>) { + fn update_param_map_declaration(&mut self, symbol: Symbol, layout: ProcLayout<'a>) { + let index = self.param_map.declaration_to_index[&(symbol, layout)]; + let key = Key::Declaration(index); + + self.update_param_map(key) + } + + fn update_param_map(&mut self, k: Key) { let arena = self.arena; if let Some(ps) = self.param_map.items.get(&k) { let ps = Vec::from_iter_in( @@ -733,7 +763,7 @@ impl<'a> BorrowInfState<'a> { self.owned.entry(proc.name).or_default(); self.collect_stmt(&proc.body); - self.update_param_map(Key::Declaration(proc.name, layout)); + self.update_param_map_declaration(proc.name, layout); self.param_set = old; } diff --git a/compiler/mono/src/inc_dec.rs b/compiler/mono/src/inc_dec.rs index 4cbc8b5bec..2acb4a87c4 100644 --- a/compiler/mono/src/inc_dec.rs +++ b/compiler/mono/src/inc_dec.rs @@ -247,18 +247,16 @@ impl<'a> Context<'a> { pub fn new(arena: &'a Bump, param_map: &'a ParamMap<'a>) -> Self { let mut vars = MutMap::default(); - for (key, _) in param_map.into_iter() { - if let crate::borrow::Key::Declaration(symbol, _) = key { - vars.insert( - *symbol, - VarInfo { - reference: false, // assume function symbols are global constants - persistent: true, // assume function symbols are global constants - consume: false, // no need to consume this variable - reset: false, // reset symbols cannot be passed as function arguments - }, - ); - } + for symbol in param_map.iter_symbols() { + vars.insert( + *symbol, + VarInfo { + reference: false, // assume function symbols are global constants + persistent: true, // assume function symbols are global constants + consume: false, // no need to consume this variable + reset: false, // reset symbols cannot be passed as function arguments + }, + ); } Self { From 138af15da5c53390ac117bb979e71ab7718fc211 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 25 Jul 2021 14:10:27 +0200 Subject: [PATCH 03/15] use vector instead of map --- compiler/mono/src/borrow.rs | 110 ++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 60 deletions(-) diff --git a/compiler/mono/src/borrow.rs b/compiler/mono/src/borrow.rs index 07554e25c7..fc7a80f33f 100644 --- a/compiler/mono/src/borrow.rs +++ b/compiler/mono/src/borrow.rs @@ -29,7 +29,8 @@ pub fn infer_borrow<'a>( let mut param_map = ParamMap { declaration_to_index, - items: MutMap::default(), + join_points: MutMap::default(), + declarations: bumpalo::vec![in arena; &[] as &[_]; procs.len()], }; for (key, proc) in procs { @@ -82,14 +83,20 @@ pub enum Key { #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] pub struct DeclarationId(usize); -#[derive(Debug, Clone, Default)] -pub struct ParamMap<'a> { - declaration_to_index: MutMap<(Symbol, ProcLayout<'a>), DeclarationId>, - items: MutMap]>, - // declarations: Vec<'a, &'a [Param<'a>]>, - // join_points: Vec<'a, &'a [Param<'a>]>, +impl From for usize { + fn from(id: DeclarationId) -> Self { + id.0 as usize + } } +#[derive(Debug, Clone)] +pub struct ParamMap<'a> { + declaration_to_index: MutMap<(Symbol, ProcLayout<'a>), DeclarationId>, + declarations: Vec<'a, &'a [Param<'a>]>, + join_points: MutMap]>, +} + +/* impl<'a> IntoIterator for ParamMap<'a> { type Item = (Key, &'a [Param<'a>]); type IntoIter = ]> as IntoIterator>::IntoIter; @@ -107,18 +114,16 @@ impl<'a> IntoIterator for &'a ParamMap<'a> { self.items.iter() } } +*/ impl<'a> ParamMap<'a> { pub fn get_symbol(&self, symbol: Symbol, layout: ProcLayout<'a>) -> Option<&'a [Param<'a>]> { - let index = self.declaration_to_index[&(symbol, layout)]; - let key = Key::Declaration(index); + let index: usize = self.declaration_to_index[&(symbol, layout)].into(); - self.items.get(&key).copied() + self.declarations.get(index).copied() } pub fn get_join_point(&self, id: JoinPointId) -> &'a [Param<'a>] { - let key = Key::JoinPoint(id); - - match self.items.get(&key) { + match self.join_points.get(&id) { Some(slice) => slice, None => unreachable!("join point not in param map: {:?}", id), } @@ -175,13 +180,8 @@ impl<'a> ParamMap<'a> { return; } - let index = self.declaration_to_index[&key]; - - let already_in_there = self.items.insert( - Key::Declaration(index), - Self::init_borrow_args(arena, proc.args), - ); - debug_assert!(already_in_there.is_none()); + let index: usize = self.declaration_to_index[&key].into(); + self.declarations[index] = Self::init_borrow_args(arena, proc.args); self.visit_stmt(arena, proc.name, &proc.body); } @@ -192,13 +192,8 @@ impl<'a> ParamMap<'a> { proc: &Proc<'a>, key: (Symbol, ProcLayout<'a>), ) { - let index = self.declaration_to_index[&key]; - - let already_in_there = self.items.insert( - Key::Declaration(index), - Self::init_borrow_args_always_owned(arena, proc.args), - ); - debug_assert!(already_in_there.is_none()); + let index: usize = self.declaration_to_index[&key].into(); + self.declarations[index] = Self::init_borrow_args_always_owned(arena, proc.args); self.visit_stmt(arena, proc.name, &proc.body); } @@ -216,14 +211,8 @@ impl<'a> ParamMap<'a> { remainder: v, body: b, } => { - let already_in_there = self - .items - .insert(Key::JoinPoint(*j), Self::init_borrow_params(arena, xs)); - debug_assert!( - already_in_there.is_none(), - "join point {:?} is already defined!", - j - ); + self.join_points + .insert(*j, Self::init_borrow_params(arena, xs)); stack.push(v); stack.push(b); @@ -286,35 +275,36 @@ impl<'a> BorrowInfState<'a> { } } - fn update_param_map_declaration(&mut self, symbol: Symbol, layout: ProcLayout<'a>) { - let index = self.param_map.declaration_to_index[&(symbol, layout)]; - let key = Key::Declaration(index); + fn update_param_map_help(&mut self, ps: &[Param<'a>]) -> &'a [Param<'a>] { + let mut new_ps = Vec::with_capacity_in(ps.len(), self.arena); + new_ps.extend(ps.iter().map(|p| { + if !p.borrow { + *p + } else if self.is_owned(p.symbol) { + self.modified = true; + let mut p = p.clone(); + p.borrow = false; - self.update_param_map(key) + p + } else { + *p + } + })); + + new_ps.into_bump_slice() } - fn update_param_map(&mut self, k: Key) { - let arena = self.arena; - if let Some(ps) = self.param_map.items.get(&k) { - let ps = Vec::from_iter_in( - ps.iter().map(|p| { - if !p.borrow { - p.clone() - } else if self.is_owned(p.symbol) { - self.modified = true; - let mut p = p.clone(); - p.borrow = false; + fn update_param_map_declaration(&mut self, symbol: Symbol, layout: ProcLayout<'a>) { + let index: usize = self.param_map.declaration_to_index[&(symbol, layout)].into(); - p - } else { - p.clone() - } - }), - arena, - ); + let ps = self.param_map.declarations[index]; + self.param_map.declarations[index] = self.update_param_map_help(ps); + } - self.param_map.items.insert(k, ps.into_bump_slice()); - } + fn update_param_map_join_point(&mut self, id: JoinPointId) { + let ps = self.param_map.join_points[&id]; + let new_ps = self.update_param_map_help(ps); + self.param_map.join_points.insert(id, new_ps); } /// This looks at an application `f x1 x2 x3` @@ -697,7 +687,7 @@ impl<'a> BorrowInfState<'a> { self.update_param_set(ys); self.collect_stmt(v); self.param_set = old; - self.update_param_map(Key::JoinPoint(*j)); + self.update_param_map_join_point(*j); self.collect_stmt(b); } From b9a3fd7f8acb3c1171388ebed382c32d18bff987 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 25 Jul 2021 14:14:44 +0200 Subject: [PATCH 04/15] cleanup --- compiler/mono/src/borrow.rs | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/compiler/mono/src/borrow.rs b/compiler/mono/src/borrow.rs index fc7a80f33f..6b0035de47 100644 --- a/compiler/mono/src/borrow.rs +++ b/compiler/mono/src/borrow.rs @@ -74,12 +74,6 @@ pub fn infer_borrow<'a>( env.param_map } -#[derive(Debug, PartialEq, Eq, Hash, Clone)] -pub enum Key { - Declaration(DeclarationId), - JoinPoint(JoinPointId), -} - #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] pub struct DeclarationId(usize); @@ -92,30 +86,11 @@ impl From for usize { #[derive(Debug, Clone)] pub struct ParamMap<'a> { declaration_to_index: MutMap<(Symbol, ProcLayout<'a>), DeclarationId>, + // IDEA: flatten the declarations into just one flat array declarations: Vec<'a, &'a [Param<'a>]>, join_points: MutMap]>, } -/* -impl<'a> IntoIterator for ParamMap<'a> { - type Item = (Key, &'a [Param<'a>]); - type IntoIter = ]> as IntoIterator>::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.items.into_iter() - } -} - -impl<'a> IntoIterator for &'a ParamMap<'a> { - type Item = (&'a Key, &'a &'a [Param<'a>]); - type IntoIter = <&'a std::collections::HashMap]> as IntoIterator>::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.items.iter() - } -} -*/ - impl<'a> ParamMap<'a> { pub fn get_symbol(&self, symbol: Symbol, layout: ProcLayout<'a>) -> Option<&'a [Param<'a>]> { let index: usize = self.declaration_to_index[&(symbol, layout)].into(); From a801558f222aa410a0f6e9cb4876a57f994e8fbf Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 25 Jul 2021 15:18:27 +0200 Subject: [PATCH 05/15] store declaration parameters in flat array --- compiler/module/src/symbol.rs | 3 + compiler/mono/src/borrow.rs | 142 ++++++++++++++++++++++------------ 2 files changed, 97 insertions(+), 48 deletions(-) diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index 9b7ac01c14..847501b1ec 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -774,6 +774,9 @@ define_builtins! { // a caller (wrapper) for comparison 21 GENERIC_COMPARE_REF: "#generic_compare_ref" + + // used to initialize paramters in borrow.rs + 22 EMPTY_PARAM: "#empty_param" } 1 NUM: "Num" => { 0 NUM_NUM: "Num" imported // the Num.Num type alias diff --git a/compiler/mono/src/borrow.rs b/compiler/mono/src/borrow.rs index 6b0035de47..7c8aabdb00 100644 --- a/compiler/mono/src/borrow.rs +++ b/compiler/mono/src/borrow.rs @@ -23,14 +23,17 @@ pub fn infer_borrow<'a>( // intern the layouts let mut declaration_to_index = MutMap::with_capacity_and_hasher(procs.len(), default_hasher()); - for (i, key) in procs.keys().enumerate() { + let mut i = 0; + for key in procs.keys() { declaration_to_index.insert(*key, DeclarationId(i)); + + i += key.1.arguments.len(); } let mut param_map = ParamMap { declaration_to_index, join_points: MutMap::default(), - declarations: bumpalo::vec![in arena; &[] as &[_]; procs.len()], + declarations: bumpalo::vec![in arena; Param::EMPTY; i], }; for (key, proc) in procs { @@ -42,7 +45,6 @@ pub fn infer_borrow<'a>( param_set: MutSet::default(), owned: MutMap::default(), modified: false, - param_map, arena, }; @@ -59,7 +61,7 @@ pub fn infer_borrow<'a>( // mutually recursive functions (or just make all their arguments owned) for (key, proc) in procs { - env.collect_proc(proc, key.1); + env.collect_proc(&mut param_map, proc, key.1); } if !env.modified { @@ -71,7 +73,7 @@ pub fn infer_borrow<'a>( } } - env.param_map + param_map } #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] @@ -85,17 +87,23 @@ impl From for usize { #[derive(Debug, Clone)] pub struct ParamMap<'a> { + /// Map a (Symbol, ProcLayout) pair to the starting index in the `declarations` array declaration_to_index: MutMap<(Symbol, ProcLayout<'a>), DeclarationId>, - // IDEA: flatten the declarations into just one flat array - declarations: Vec<'a, &'a [Param<'a>]>, + /// the parameters of all functions in a single flat array. + /// + /// - the map above gives the index of the first parameter for the function + /// - the length of the ProcLayout's argument field gives the total number of parameters + /// + /// These can be read by taking a slice into this array, and can also be updated in-place + declarations: Vec<'a, Param<'a>>, join_points: MutMap]>, } impl<'a> ParamMap<'a> { - pub fn get_symbol(&self, symbol: Symbol, layout: ProcLayout<'a>) -> Option<&'a [Param<'a>]> { + pub fn get_symbol(&self, symbol: Symbol, layout: ProcLayout<'a>) -> Option<&[Param<'a>]> { let index: usize = self.declaration_to_index[&(symbol, layout)].into(); - self.declarations.get(index).copied() + self.declarations.get(index..index + layout.arguments.len()) } pub fn get_join_point(&self, id: JoinPointId) -> &'a [Param<'a>] { match self.join_points.get(&id) { @@ -156,7 +164,14 @@ impl<'a> ParamMap<'a> { } let index: usize = self.declaration_to_index[&key].into(); - self.declarations[index] = Self::init_borrow_args(arena, proc.args); + + for (i, param) in Self::init_borrow_args(arena, proc.args) + .iter() + .copied() + .enumerate() + { + self.declarations[index + i] = param; + } self.visit_stmt(arena, proc.name, &proc.body); } @@ -168,7 +183,14 @@ impl<'a> ParamMap<'a> { key: (Symbol, ProcLayout<'a>), ) { let index: usize = self.declaration_to_index[&key].into(); - self.declarations[index] = Self::init_borrow_args_always_owned(arena, proc.args); + + for (i, param) in Self::init_borrow_args_always_owned(arena, proc.args) + .iter() + .copied() + .enumerate() + { + self.declarations[index + i] = param; + } self.visit_stmt(arena, proc.name, &proc.body); } @@ -224,7 +246,6 @@ struct BorrowInfState<'a> { param_set: MutSet, owned: MutMap>, modified: bool, - param_map: ParamMap<'a>, arena: &'a Bump, } @@ -269,17 +290,31 @@ impl<'a> BorrowInfState<'a> { new_ps.into_bump_slice() } - fn update_param_map_declaration(&mut self, symbol: Symbol, layout: ProcLayout<'a>) { - let index: usize = self.param_map.declaration_to_index[&(symbol, layout)].into(); + fn update_param_map_declaration( + &mut self, + param_map: &mut ParamMap<'a>, + symbol: Symbol, + layout: ProcLayout<'a>, + ) { + let index: usize = param_map.declaration_to_index[&(symbol, layout)].into(); + let ps = &mut param_map.declarations[index..][..layout.arguments.len()]; - let ps = self.param_map.declarations[index]; - self.param_map.declarations[index] = self.update_param_map_help(ps); + for p in ps.iter_mut() { + if !p.borrow { + // do nothing + } else if self.is_owned(p.symbol) { + self.modified = true; + p.borrow = false; + } else { + // do nothing + } + } } - fn update_param_map_join_point(&mut self, id: JoinPointId) { - let ps = self.param_map.join_points[&id]; + fn update_param_map_join_point(&mut self, param_map: &mut ParamMap<'a>, id: JoinPointId) { + let ps = param_map.join_points[&id]; let new_ps = self.update_param_map_help(ps); - self.param_map.join_points.insert(id, new_ps); + param_map.join_points.insert(id, new_ps); } /// This looks at an application `f x1 x2 x3` @@ -346,7 +381,7 @@ impl<'a> BorrowInfState<'a> { /// /// and determines whether z and which of the symbols used in e /// must be taken as owned parameters - fn collect_call(&mut self, z: Symbol, e: &crate::ir::Call<'a>) { + fn collect_call(&mut self, param_map: &mut ParamMap<'a>, z: Symbol, e: &crate::ir::Call<'a>) { use crate::ir::CallType::*; let crate::ir::Call { @@ -364,8 +399,7 @@ impl<'a> BorrowInfState<'a> { let top_level = ProcLayout::new(self.arena, arg_layouts, *ret_layout); // get the borrow signature of the applied function - let ps = self - .param_map + let ps = param_map .get_symbol(*name, top_level) .expect("function is defined"); @@ -381,6 +415,7 @@ impl<'a> BorrowInfState<'a> { ps.len(), arguments.len() ); + self.own_args_using_params(arguments, ps); } @@ -411,7 +446,7 @@ impl<'a> BorrowInfState<'a> { match op { ListMap | ListKeepIf | ListKeepOks | ListKeepErrs => { - match self.param_map.get_symbol(arguments[1], closure_layout) { + match param_map.get_symbol(arguments[1], closure_layout) { Some(function_ps) => { // own the list if the function wants to own the element if !function_ps[0].borrow { @@ -427,7 +462,7 @@ impl<'a> BorrowInfState<'a> { } } ListMapWithIndex => { - match self.param_map.get_symbol(arguments[1], closure_layout) { + match param_map.get_symbol(arguments[1], closure_layout) { Some(function_ps) => { // own the list if the function wants to own the element if !function_ps[1].borrow { @@ -442,7 +477,7 @@ impl<'a> BorrowInfState<'a> { None => unreachable!(), } } - ListMap2 => match self.param_map.get_symbol(arguments[2], closure_layout) { + ListMap2 => match param_map.get_symbol(arguments[2], closure_layout) { Some(function_ps) => { // own the lists if the function wants to own the element if !function_ps[0].borrow { @@ -460,7 +495,7 @@ impl<'a> BorrowInfState<'a> { } None => unreachable!(), }, - ListMap3 => match self.param_map.get_symbol(arguments[3], closure_layout) { + ListMap3 => match param_map.get_symbol(arguments[3], closure_layout) { Some(function_ps) => { // own the lists if the function wants to own the element if !function_ps[0].borrow { @@ -481,7 +516,7 @@ impl<'a> BorrowInfState<'a> { None => unreachable!(), }, ListSortWith => { - match self.param_map.get_symbol(arguments[1], closure_layout) { + match param_map.get_symbol(arguments[1], closure_layout) { Some(function_ps) => { // always own the input list self.own_var(arguments[0]); @@ -495,7 +530,7 @@ impl<'a> BorrowInfState<'a> { } } ListWalk | ListWalkUntil | ListWalkBackwards | DictWalk => { - match self.param_map.get_symbol(arguments[2], closure_layout) { + match param_map.get_symbol(arguments[2], closure_layout) { Some(function_ps) => { // own the data structure if the function wants to own the element if !function_ps[0].borrow { @@ -537,7 +572,7 @@ impl<'a> BorrowInfState<'a> { } } - fn collect_expr(&mut self, z: Symbol, e: &Expr<'a>) { + fn collect_expr(&mut self, param_map: &mut ParamMap<'a>, z: Symbol, e: &Expr<'a>) { use Expr::*; match e { @@ -565,7 +600,7 @@ impl<'a> BorrowInfState<'a> { self.own_var(z); } - Call(call) => self.collect_call(z, call), + Call(call) => self.collect_call(param_map, z, call), Literal(_) | RuntimeErrorFunction(_) => {} @@ -608,7 +643,13 @@ impl<'a> BorrowInfState<'a> { } #[allow(clippy::many_single_char_names)] - fn preserve_tail_call(&mut self, x: Symbol, v: &Expr<'a>, b: &Stmt<'a>) { + fn preserve_tail_call( + &mut self, + param_map: &mut ParamMap<'a>, + x: Symbol, + v: &Expr<'a>, + b: &Stmt<'a>, + ) { if let ( Expr::Call(crate::ir::Call { call_type: @@ -629,7 +670,7 @@ impl<'a> BorrowInfState<'a> { if self.current_proc == *g && x == *z { // anonymous functions (for which the ps may not be known) // can never be tail-recursive, so this is fine - if let Some(ps) = self.param_map.get_symbol(*g, top_level) { + if let Some(ps) = param_map.get_symbol(*g, top_level) { self.own_params_using_args(ys, ps) } } @@ -648,7 +689,7 @@ impl<'a> BorrowInfState<'a> { } } - fn collect_stmt(&mut self, stmt: &Stmt<'a>) { + fn collect_stmt(&mut self, param_map: &mut ParamMap<'a>, stmt: &Stmt<'a>) { use Stmt::*; match stmt { @@ -660,17 +701,17 @@ impl<'a> BorrowInfState<'a> { } => { let old = self.param_set.clone(); self.update_param_set(ys); - self.collect_stmt(v); + self.collect_stmt(param_map, v); self.param_set = old; - self.update_param_map_join_point(*j); + self.update_param_map_join_point(param_map, *j); - self.collect_stmt(b); + self.collect_stmt(param_map, b); } Let(x, v, _, b) => { - self.collect_stmt(b); - self.collect_expr(*x, v); - self.preserve_tail_call(*x, v, b); + self.collect_stmt(param_map, b); + self.collect_expr(param_map, *x, v); + self.preserve_tail_call(param_map, *x, v, b); } Invoke { @@ -681,17 +722,17 @@ impl<'a> BorrowInfState<'a> { fail, exception_id: _, } => { - self.collect_stmt(pass); - self.collect_stmt(fail); + self.collect_stmt(param_map, pass); + self.collect_stmt(param_map, fail); - self.collect_call(*symbol, call); + self.collect_call(param_map, *symbol, call); // TODO how to preserve the tail call of an invoke? // self.preserve_tail_call(*x, v, b); } Jump(j, ys) => { - let ps = self.param_map.get_join_point(*j); + let ps = param_map.get_join_point(*j); // for making sure the join point can reuse self.own_args_using_params(ys, ps); @@ -705,9 +746,9 @@ impl<'a> BorrowInfState<'a> { .. } => { for (_, _, b) in branches.iter() { - self.collect_stmt(b); + self.collect_stmt(param_map, b); } - self.collect_stmt(default_branch.1); + self.collect_stmt(param_map, default_branch.1); } Refcounting(_, _) => unreachable!("these have not been introduced yet"), @@ -717,7 +758,12 @@ impl<'a> BorrowInfState<'a> { } } - fn collect_proc(&mut self, proc: &Proc<'a>, layout: ProcLayout<'a>) { + fn collect_proc( + &mut self, + param_map: &mut ParamMap<'a>, + proc: &Proc<'a>, + layout: ProcLayout<'a>, + ) { let old = self.param_set.clone(); let ys = Vec::from_iter_in(proc.args.iter().map(|t| t.1), self.arena).into_bump_slice(); @@ -727,8 +773,8 @@ impl<'a> BorrowInfState<'a> { // ensure that current_proc is in the owned map self.owned.entry(proc.name).or_default(); - self.collect_stmt(&proc.body); - self.update_param_map_declaration(proc.name, layout); + self.collect_stmt(param_map, &proc.body); + self.update_param_map_declaration(param_map, proc.name, layout); self.param_set = old; } From 32ce399cc0aa15c7d7623fdfc8c72c2634740ba4 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 25 Jul 2021 20:16:30 +0200 Subject: [PATCH 06/15] topological sort before borrow analysis --- compiler/mono/src/borrow.rs | 256 ++++++++++++++++++++++++++++++------ 1 file changed, 219 insertions(+), 37 deletions(-) diff --git a/compiler/mono/src/borrow.rs b/compiler/mono/src/borrow.rs index 7c8aabdb00..9b9e46ef8f 100644 --- a/compiler/mono/src/borrow.rs +++ b/compiler/mono/src/borrow.rs @@ -23,17 +23,19 @@ pub fn infer_borrow<'a>( // intern the layouts let mut declaration_to_index = MutMap::with_capacity_and_hasher(procs.len(), default_hasher()); - let mut i = 0; - for key in procs.keys() { - declaration_to_index.insert(*key, DeclarationId(i)); + let mut param_map = { + let mut i = 0; + for key in procs.keys() { + declaration_to_index.insert(*key, ParamOffset(i)); - i += key.1.arguments.len(); - } + i += key.1.arguments.len(); + } - let mut param_map = ParamMap { - declaration_to_index, - join_points: MutMap::default(), - declarations: bumpalo::vec![in arena; Param::EMPTY; i], + ParamMap { + declaration_to_index, + join_points: MutMap::default(), + declarations: bumpalo::vec![in arena; Param::EMPTY; i], + } }; for (key, proc) in procs { @@ -48,28 +50,110 @@ pub fn infer_borrow<'a>( arena, }; - // This is a fixed-point analysis - // - // all functions initiall own all their parameters - // through a series of checks and heuristics, some arguments are set to borrowed - // when that doesn't lead to conflicts the change is kept, otherwise it may be reverted - // - // when the signatures no longer change, the analysis stops and returns the signatures - loop { - // sort the symbols (roughly) in definition order. - // TODO in the future I think we need to do this properly, and group - // mutually recursive functions (or just make all their arguments owned) + // next we first partition the functions into strongly connected components, then do a + // topological sort on these components, finally run the fix-point borrow analysis on each + // component (in top-sorted order, from primitives (std-lib) to main) - for (key, proc) in procs { - env.collect_proc(&mut param_map, proc, key.1); + let successor_map = &make_successor_mapping(arena, procs); + let successors = move |key: &Symbol| successor_map[key].iter().copied(); + + let mut symbols = Vec::with_capacity_in(procs.len(), arena); + symbols.extend(procs.keys().map(|x| x.0)); + + let sccs = ven_graph::strongly_connected_components(&symbols, successors); + + let mut symbol_to_component = MutMap::default(); + for (i, symbols) in sccs.iter().enumerate() { + for symbol in symbols { + symbol_to_component.insert(*symbol, i); + } + } + + let mut component_to_successors = Vec::with_capacity_in(sccs.len(), arena); + for (i, symbols) in sccs.iter().enumerate() { + // guess: every function has ~1 successor + let mut succs = Vec::with_capacity_in(symbols.len(), arena); + + for symbol in symbols { + for s in successors(symbol) { + let c = symbol_to_component[&s]; + + // don't insert self to prevent cycles + if c != i { + succs.push(c); + } + } } - if !env.modified { - // if there were no modifications, we're done - break; - } else { - // otherwise see if there are changes after another iteration - env.modified = false; + succs.sort_unstable(); + succs.dedup(); + + component_to_successors.push(succs); + } + + let mut components = Vec::with_capacity_in(component_to_successors.len(), arena); + components.extend(0..component_to_successors.len()); + + let mut groups = Vec::new_in(arena); + + let component_to_successors = &component_to_successors; + match ven_graph::topological_sort_into_groups(&components, |c: &usize| { + component_to_successors[*c].iter().copied() + }) { + Ok(component_groups) => { + let mut component_to_group = bumpalo::vec![in arena; usize::MAX; components.len()]; + + // for each component, store which group it is in + for (group_index, component_group) in component_groups.iter().enumerate() { + for component in component_group { + component_to_group[*component] = group_index; + } + } + + // prepare groups + groups.reserve(component_groups.len()); + for _ in 0..component_groups.len() { + groups.push(Vec::new_in(arena)); + } + + for (key, proc) in procs { + let symbol = key.0; + let offset = param_map.declaration_to_index[key]; + + // the component this symbol is a part of + let component = symbol_to_component[&symbol]; + + // now find the group that this component belongs to + let group = component_to_group[component]; + + groups[group].push((proc, offset)); + } + } + Err((_groups, _remainder)) => { + unreachable!("because we find strongly-connected components first"); + } + } + + for group in groups.into_iter().rev() { + // This is a fixed-point analysis + // + // all functions initiall own all their parameters + // through a series of checks and heuristics, some arguments are set to borrowed + // when that doesn't lead to conflicts the change is kept, otherwise it may be reverted + // + // when the signatures no longer change, the analysis stops and returns the signatures + loop { + for (proc, param_offset) in group.iter() { + env.collect_proc(&mut param_map, proc, *param_offset); + } + + if !env.modified { + // if there were no modifications, we're done + break; + } else { + // otherwise see if there are changes after another iteration + env.modified = false; + } } } @@ -77,10 +161,10 @@ pub fn infer_borrow<'a>( } #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] -pub struct DeclarationId(usize); +pub struct ParamOffset(usize); -impl From for usize { - fn from(id: DeclarationId) -> Self { +impl From for usize { + fn from(id: ParamOffset) -> Self { id.0 as usize } } @@ -88,7 +172,7 @@ impl From for usize { #[derive(Debug, Clone)] pub struct ParamMap<'a> { /// Map a (Symbol, ProcLayout) pair to the starting index in the `declarations` array - declaration_to_index: MutMap<(Symbol, ProcLayout<'a>), DeclarationId>, + declaration_to_index: MutMap<(Symbol, ProcLayout<'a>), ParamOffset>, /// the parameters of all functions in a single flat array. /// /// - the map above gives the index of the first parameter for the function @@ -294,10 +378,11 @@ impl<'a> BorrowInfState<'a> { &mut self, param_map: &mut ParamMap<'a>, symbol: Symbol, - layout: ProcLayout<'a>, + start: ParamOffset, + length: usize, ) { - let index: usize = param_map.declaration_to_index[&(symbol, layout)].into(); - let ps = &mut param_map.declarations[index..][..layout.arguments.len()]; + let index: usize = start.into(); + let ps = &mut param_map.declarations[index..][..length]; for p in ps.iter_mut() { if !p.borrow { @@ -762,7 +847,7 @@ impl<'a> BorrowInfState<'a> { &mut self, param_map: &mut ParamMap<'a>, proc: &Proc<'a>, - layout: ProcLayout<'a>, + param_offset: ParamOffset, ) { let old = self.param_set.clone(); @@ -774,7 +859,7 @@ impl<'a> BorrowInfState<'a> { self.owned.entry(proc.name).or_default(); self.collect_stmt(param_map, &proc.body); - self.update_param_map_declaration(param_map, proc.name, layout); + self.update_param_map_declaration(param_map, proc.name, param_offset, proc.args.len()); self.param_set = old; } @@ -868,3 +953,100 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] { ExpectTrue => arena.alloc_slice_copy(&[irrelevant]), } } + +fn make_successor_mapping<'a>( + arena: &'a Bump, + procs: &MutMap<(Symbol, ProcLayout<'_>), Proc<'a>>, +) -> MutMap> { + let mut result = MutMap::with_capacity_and_hasher(procs.len(), default_hasher()); + + for (key, proc) in procs { + let mut call_info = CallInfo { + keys: Vec::new_in(arena), + }; + call_info_stmt(arena, &proc.body, &mut call_info); + + let mut keys = call_info.keys; + keys.sort_unstable(); + keys.dedup(); + + result.insert(key.0, keys); + } + + result +} + +struct CallInfo<'a> { + // keys: MutSet<(Symbol, ProcLayout<'a>)>, + keys: Vec<'a, Symbol>, +} + +fn call_info_call<'a>(call: &crate::ir::Call<'a>, info: &mut CallInfo<'a>) { + use crate::ir::CallType::*; + + match call.call_type { + ByName { + name, + ret_layout, + arg_layouts, + .. + } => { + let proc_layout = crate::ir::ProcLayout { + arguments: arg_layouts, + result: ret_layout, + }; + + //let key = (name, proc_layout); + // info.keys.insert(key); + info.keys.push(name); + } + Foreign { .. } => {} + LowLevel { .. } => {} + HigherOrderLowLevel { .. } => {} + } +} + +fn call_info_stmt<'a>(arena: &'a Bump, stmt: &Stmt<'a>, info: &mut CallInfo<'a>) { + use Stmt::*; + + let mut stack = bumpalo::vec![ in arena; stmt ]; + + while let Some(stmt) = stack.pop() { + match stmt { + Join { + remainder: v, + body: b, + .. + } => { + stack.push(v); + stack.push(b); + } + Let(_, expr, _, cont) => { + if let Expr::Call(call) = expr { + call_info_call(call, info); + } + stack.push(cont); + } + Invoke { + call, pass, fail, .. + } => { + call_info_call(call, info); + stack.push(pass); + stack.push(fail); + } + Switch { + branches, + default_branch, + .. + } => { + stack.extend(branches.iter().map(|b| &b.2)); + stack.push(default_branch.1); + } + Refcounting(_, _) => unreachable!("these have not been introduced yet"), + + Ret(_) | Resume(_) | Jump(_, _) | RuntimeError(_) => { + // these are terminal, do nothing + } + } + } +} From 116960fbf488a1d9438d729edc657563d646ad53 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 25 Jul 2021 20:17:11 +0200 Subject: [PATCH 07/15] fix dependencies --- Cargo.lock | 3 +++ compiler/mono/Cargo.toml | 1 + compiler/mono/src/ir.rs | 10 +++++++++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index f0b1a3fe97..1844b3df3a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "ab_glyph" version = "0.2.11" @@ -3356,6 +3358,7 @@ dependencies = [ "roc_types", "roc_unify", "ven_ena", + "ven_graph", "ven_pretty", ] diff --git a/compiler/mono/Cargo.toml b/compiler/mono/Cargo.toml index cd0e0e6d77..9bd2127016 100644 --- a/compiler/mono/Cargo.toml +++ b/compiler/mono/Cargo.toml @@ -19,6 +19,7 @@ morphic_lib = { path = "../../vendor/morphic_lib" } bumpalo = { version = "3.6.1", features = ["collections"] } hashbrown = { version = "0.11.2", features = [ "bumpalo" ] } ven_ena = { path = "../../vendor/ena" } +ven_graph = { path = "../../vendor/pathfinding" } linked-hash-map = "0.5.4" [dev-dependencies] diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index 88186f6ecc..b4a5cd3681 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -848,13 +848,21 @@ impl<'a, 'i> Env<'a, 'i> { #[derive(Clone, Debug, PartialEq, Copy, Eq, Hash)] pub struct JoinPointId(pub Symbol); -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] pub struct Param<'a> { pub symbol: Symbol, pub borrow: bool, pub layout: Layout<'a>, } +impl<'a> Param<'a> { + pub const EMPTY: Self = Param { + symbol: Symbol::EMPTY_PARAM, + borrow: false, + layout: Layout::Struct(&[]), + }; +} + pub fn cond<'a>( env: &mut Env<'a, '_>, cond_symbol: Symbol, From 772c06156803b31553cc505184cec10e6d0aa1e0 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 25 Jul 2021 20:42:01 +0200 Subject: [PATCH 08/15] try to unroll chains of Lets --- compiler/mono/src/borrow.rs | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/compiler/mono/src/borrow.rs b/compiler/mono/src/borrow.rs index 9b9e46ef8f..74a013356f 100644 --- a/compiler/mono/src/borrow.rs +++ b/compiler/mono/src/borrow.rs @@ -793,10 +793,28 @@ impl<'a> BorrowInfState<'a> { self.collect_stmt(param_map, b); } - Let(x, v, _, b) => { + Let(x, v, _, mut b) => { + let mut stack = Vec::new_in(self.arena); + + stack.push((*x, v)); + + while let Stmt::Let(symbol, expr, _, tail) = b { + b = tail; + stack.push((*symbol, expr)); + } + self.collect_stmt(param_map, b); - self.collect_expr(param_map, *x, v); - self.preserve_tail_call(param_map, *x, v, b); + + let mut it = stack.into_iter().rev(); + + // collect the final expr, and see if we need to preserve a tail call + let (x, v) = it.next().unwrap(); + self.collect_expr(param_map, x, v); + self.preserve_tail_call(param_map, x, v, b); + + for (x, v) in it { + self.collect_expr(param_map, x, v); + } } Invoke { From c7d04c2a0008b46fe157ded7e666563910fa0060 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 25 Jul 2021 20:44:00 +0200 Subject: [PATCH 09/15] cleanup --- compiler/mono/src/borrow.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/compiler/mono/src/borrow.rs b/compiler/mono/src/borrow.rs index 74a013356f..d0c3aad97c 100644 --- a/compiler/mono/src/borrow.rs +++ b/compiler/mono/src/borrow.rs @@ -995,7 +995,6 @@ fn make_successor_mapping<'a>( } struct CallInfo<'a> { - // keys: MutSet<(Symbol, ProcLayout<'a>)>, keys: Vec<'a, Symbol>, } @@ -1009,13 +1008,6 @@ fn call_info_call<'a>(call: &crate::ir::Call<'a>, info: &mut CallInfo<'a>) { arg_layouts, .. } => { - let proc_layout = crate::ir::ProcLayout { - arguments: arg_layouts, - result: ret_layout, - }; - - //let key = (name, proc_layout); - // info.keys.insert(key); info.keys.push(name); } Foreign { .. } => {} From 7d0c1f5787a9e96fee48486c6e42a7ced42dc2f7 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 25 Jul 2021 20:50:40 +0200 Subject: [PATCH 10/15] remove unneeded `contains` --- compiler/mono/src/borrow.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/mono/src/borrow.rs b/compiler/mono/src/borrow.rs index d0c3aad97c..e9955f837a 100644 --- a/compiler/mono/src/borrow.rs +++ b/compiler/mono/src/borrow.rs @@ -337,10 +337,9 @@ impl<'a> BorrowInfState<'a> { pub fn own_var(&mut self, x: Symbol) { let current = self.owned.get_mut(&self.current_proc).unwrap(); - if current.contains(&x) { - // do nothing - } else { - current.insert(x); + if current.insert(x) { + // entered if key was not yet present. If so, the set is modified, + // hence we set this flag self.modified = true; } } From 204aa6f88adfb805b3105c359735a394610330d8 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 25 Jul 2021 20:53:45 +0200 Subject: [PATCH 11/15] remove extra lookup --- compiler/mono/src/borrow.rs | 43 +++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/compiler/mono/src/borrow.rs b/compiler/mono/src/borrow.rs index e9955f837a..e4ac58ba67 100644 --- a/compiler/mono/src/borrow.rs +++ b/compiler/mono/src/borrow.rs @@ -344,6 +344,25 @@ impl<'a> BorrowInfState<'a> { } } + /// if the extracted value is owned, then the surrounding structure must be too + fn if_is_owned_then_own(&mut self, extracted: Symbol, structure: Symbol) { + match self.owned.get_mut(&self.current_proc) { + None => unreachable!( + "the current procedure symbol {:?} is not in the owned map", + self.current_proc + ), + Some(set) => { + if set.contains(&extracted) { + if set.insert(structure) { + // entered if key was not yet present. If so, the set is modified, + // hence we set this flag + self.modified = true; + } + } + } + } + } + fn is_owned(&self, x: Symbol) -> bool { match self.owned.get(&self.current_proc) { None => unreachable!( @@ -690,38 +709,26 @@ impl<'a> BorrowInfState<'a> { StructAtIndex { structure: x, .. } => { // if the structure (record/tag/array) is owned, the extracted value is - if self.is_owned(*x) { - self.own_var(z); - } + self.if_is_owned_then_own(*x, z); // if the extracted value is owned, the structure must be too - if self.is_owned(z) { - self.own_var(*x); - } + self.if_is_owned_then_own(z, *x); } UnionAtIndex { structure: x, .. } => { // if the structure (record/tag/array) is owned, the extracted value is - if self.is_owned(*x) { - self.own_var(z); - } + self.if_is_owned_then_own(*x, z); // if the extracted value is owned, the structure must be too - if self.is_owned(z) { - self.own_var(*x); - } + self.if_is_owned_then_own(z, *x); } GetTagId { structure: x, .. } => { // if the structure (record/tag/array) is owned, the extracted value is - if self.is_owned(*x) { - self.own_var(z); - } + self.if_is_owned_then_own(*x, z); // if the extracted value is owned, the structure must be too - if self.is_owned(z) { - self.own_var(*x); - } + self.if_is_owned_then_own(z, *x); } } } From 079c95b993ee28c4967a82e3bd4fb3f12cf30744 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 25 Jul 2021 20:55:40 +0200 Subject: [PATCH 12/15] clippy --- compiler/mono/src/borrow.rs | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/compiler/mono/src/borrow.rs b/compiler/mono/src/borrow.rs index e4ac58ba67..cd7fbbf9ef 100644 --- a/compiler/mono/src/borrow.rs +++ b/compiler/mono/src/borrow.rs @@ -352,12 +352,10 @@ impl<'a> BorrowInfState<'a> { self.current_proc ), Some(set) => { - if set.contains(&extracted) { - if set.insert(structure) { - // entered if key was not yet present. If so, the set is modified, - // hence we set this flag - self.modified = true; - } + if set.contains(&extracted) && set.insert(structure) { + // entered if key was not yet present. If so, the set is modified, + // hence we set this flag + self.modified = true; } } } @@ -380,7 +378,7 @@ impl<'a> BorrowInfState<'a> { *p } else if self.is_owned(p.symbol) { self.modified = true; - let mut p = p.clone(); + let mut p = *p; p.borrow = false; p @@ -395,7 +393,6 @@ impl<'a> BorrowInfState<'a> { fn update_param_map_declaration( &mut self, param_map: &mut ParamMap<'a>, - symbol: Symbol, start: ParamOffset, length: usize, ) { @@ -883,7 +880,7 @@ impl<'a> BorrowInfState<'a> { self.owned.entry(proc.name).or_default(); self.collect_stmt(param_map, &proc.body); - self.update_param_map_declaration(param_map, proc.name, param_offset, proc.args.len()); + self.update_param_map_declaration(param_map, param_offset, proc.args.len()); self.param_set = old; } @@ -1008,12 +1005,7 @@ fn call_info_call<'a>(call: &crate::ir::Call<'a>, info: &mut CallInfo<'a>) { use crate::ir::CallType::*; match call.call_type { - ByName { - name, - ret_layout, - arg_layouts, - .. - } => { + ByName { name, .. } => { info.keys.push(name); } Foreign { .. } => {} From f76195d05c6560bc53d076a51561ecbfb2e28b0a Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 25 Jul 2021 21:13:14 +0200 Subject: [PATCH 13/15] cleanup --- compiler/mono/src/inc_dec.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/compiler/mono/src/inc_dec.rs b/compiler/mono/src/inc_dec.rs index 2acb4a87c4..cf0e06171b 100644 --- a/compiler/mono/src/inc_dec.rs +++ b/compiler/mono/src/inc_dec.rs @@ -1259,20 +1259,6 @@ fn update_jp_live_vars(j: JoinPointId, ys: &[Param], v: &Stmt<'_>, m: &mut JPLiv m.insert(j, j_live_vars); } -/// used to process the main function in the repl -pub fn visit_declaration<'a>( - arena: &'a Bump, - param_map: &'a ParamMap<'a>, - stmt: &'a Stmt<'a>, -) -> &'a Stmt<'a> { - let ctx = Context::new(arena, param_map); - - let params = &[] as &[_]; - let ctx = ctx.update_var_info_with_params(params); - let (b, b_live_vars) = ctx.visit_stmt(stmt); - ctx.add_dec_for_dead_params(params, b, &b_live_vars) -} - pub fn visit_proc<'a>( arena: &'a Bump, param_map: &'a ParamMap<'a>, From 31e1fe88705e779493853ade3dcdeb3fd6907216 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 25 Jul 2021 21:20:04 +0200 Subject: [PATCH 14/15] cache the initial context in inc_dec --- compiler/mono/src/inc_dec.rs | 17 ++++++++++++++--- compiler/mono/src/ir.rs | 12 +++--------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/compiler/mono/src/inc_dec.rs b/compiler/mono/src/inc_dec.rs index cf0e06171b..622946c0f4 100644 --- a/compiler/mono/src/inc_dec.rs +++ b/compiler/mono/src/inc_dec.rs @@ -1259,14 +1259,25 @@ fn update_jp_live_vars(j: JoinPointId, ys: &[Param], v: &Stmt<'_>, m: &mut JPLiv m.insert(j, j_live_vars); } -pub fn visit_proc<'a>( +pub fn visit_procs<'a>( arena: &'a Bump, param_map: &'a ParamMap<'a>, - proc: &mut Proc<'a>, - layout: ProcLayout<'a>, + procs: &mut MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>, ) { let ctx = Context::new(arena, param_map); + for (key, proc) in procs.iter_mut() { + visit_proc(arena, param_map, &ctx, proc, key.1); + } +} + +fn visit_proc<'a>( + arena: &'a Bump, + param_map: &'a ParamMap<'a>, + ctx: &Context<'a>, + proc: &mut Proc<'a>, + layout: ProcLayout<'a>, +) { let params = match param_map.get_symbol(proc.name, layout) { Some(slice) => slice, None => Vec::from_iter_in( diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index b4a5cd3681..1296aa3030 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -222,9 +222,7 @@ impl<'a> Proc<'a> { ) { let borrow_params = arena.alloc(crate::borrow::infer_borrow(arena, procs)); - for (key, proc) in procs.iter_mut() { - crate::inc_dec::visit_proc(arena, borrow_params, proc, key.1); - } + crate::inc_dec::visit_procs(arena, borrow_params, procs); } pub fn insert_reset_reuse_operations<'i>( @@ -430,9 +428,7 @@ impl<'a> Procs<'a> { let borrow_params = arena.alloc(crate::borrow::infer_borrow(arena, &result)); - for (key, proc) in result.iter_mut() { - crate::inc_dec::visit_proc(arena, borrow_params, proc, key.1); - } + crate::inc_dec::visit_procs(arena, borrow_params, &mut result); result } @@ -473,9 +469,7 @@ impl<'a> Procs<'a> { let borrow_params = arena.alloc(crate::borrow::infer_borrow(arena, &result)); - for (key, proc) in result.iter_mut() { - crate::inc_dec::visit_proc(arena, borrow_params, proc, key.1); - } + crate::inc_dec::visit_procs(arena, borrow_params, &mut result); (result, borrow_params) } From 5282dbf41aa6289683668592f18f33a622828034 Mon Sep 17 00:00:00 2001 From: Folkert Date: Sun, 25 Jul 2021 22:00:52 +0200 Subject: [PATCH 15/15] fix typo --- compiler/build/src/program.rs | 3 ++- compiler/module/src/symbol.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/build/src/program.rs b/compiler/build/src/program.rs index 82d7261950..48a0456693 100644 --- a/compiler/build/src/program.rs +++ b/compiler/build/src/program.rs @@ -116,9 +116,10 @@ pub fn gen_from_mono_module( } if name.starts_with("roc_builtins.dict") - || name.starts_with("dict.RocDict") || name.starts_with("roc_builtins.list") + || name.starts_with("roc_builtins.dec") || name.starts_with("list.RocList") + || name.starts_with("dict.RocDict") { function.add_attribute(AttributeLoc::Function, enum_attr); } diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index 847501b1ec..b8291d2a6f 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -775,7 +775,7 @@ define_builtins! { // a caller (wrapper) for comparison 21 GENERIC_COMPARE_REF: "#generic_compare_ref" - // used to initialize paramters in borrow.rs + // used to initialize parameters in borrow.rs 22 EMPTY_PARAM: "#empty_param" } 1 NUM: "Num" => {