Merge pull request #4851 from JTeeuwissen/main

replace borrowed boolean with ownership enum
This commit is contained in:
Folkert de Vries 2023-01-09 23:24:39 +01:00 committed by GitHub
commit 61a2091b27
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 85 additions and 58 deletions

View file

@ -9,6 +9,7 @@ use roc_collections::all::{MutMap, MutSet};
use roc_error_macros::internal_error; use roc_error_macros::internal_error;
use roc_module::symbol::Symbol; use roc_module::symbol::Symbol;
use roc_mono::{ use roc_mono::{
borrow::Ownership,
ir::{JoinPointId, Param}, ir::{JoinPointId, Param},
layout::{Builtin, Layout, STLayoutInterner, TagIdIntType, UnionLayout}, layout::{Builtin, Layout, STLayoutInterner, TagIdIntType, UnionLayout},
}; };
@ -1012,11 +1013,11 @@ impl<
param_storage.reserve(params.len()); param_storage.reserve(params.len());
for Param { for Param {
symbol, symbol,
borrow, ownership,
layout, layout,
} in params } in params
{ {
if *borrow { if *ownership == Ownership::Borrowed {
// These probably need to be passed by pointer/reference? // These probably need to be passed by pointer/reference?
// Otherwise, we probably need to copy back to the param at the end of the joinpoint. // Otherwise, we probably need to copy back to the param at the end of the joinpoint.
todo!("joinpoints with borrowed parameters"); todo!("joinpoints with borrowed parameters");

View file

@ -15,12 +15,22 @@ use roc_module::symbol::Symbol;
pub(crate) const OWNED: bool = false; pub(crate) const OWNED: bool = false;
pub(crate) const BORROWED: bool = true; pub(crate) const BORROWED: bool = true;
/// For reference-counted types (lists, (big) strings, recursive tags), owning a value #[derive(Clone, Copy, Debug, PartialEq, Eq)]
/// means incrementing its reference count. Hence, we prefer borrowing for these types pub enum Ownership {
fn should_borrow_layout(layout: &Layout) -> bool { Owned,
layout.is_refcounted() Borrowed,
} }
impl Ownership {
/// For reference-counted types (lists, (big) strings, recursive tags), owning a value
/// means incrementing its reference count. Hence, we prefer borrowing for these types
fn from_layout(layout: &Layout) -> Self {
match layout.is_refcounted() {
true => Ownership::Borrowed,
false => Ownership::Owned,
}
}
}
pub fn infer_borrow<'a>( pub fn infer_borrow<'a>(
arena: &'a Bump, arena: &'a Bump,
procs: &MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>, procs: &MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>,
@ -106,7 +116,7 @@ pub struct ParamOffset(usize);
impl From<ParamOffset> for usize { impl From<ParamOffset> for usize {
fn from(id: ParamOffset) -> Self { fn from(id: ParamOffset) -> Self {
id.0 as usize id.0
} }
} }
@ -220,7 +230,7 @@ impl<'a> ParamMap<'a> {
fn init_borrow_params(arena: &'a Bump, ps: &'a [Param<'a>]) -> &'a [Param<'a>] { fn init_borrow_params(arena: &'a Bump, ps: &'a [Param<'a>]) -> &'a [Param<'a>] {
Vec::from_iter_in( Vec::from_iter_in(
ps.iter().map(|p| Param { ps.iter().map(|p| Param {
borrow: p.layout.is_refcounted(), ownership: Ownership::from_layout(&p.layout),
layout: p.layout, layout: p.layout,
symbol: p.symbol, symbol: p.symbol,
}), }),
@ -232,7 +242,7 @@ impl<'a> ParamMap<'a> {
fn init_borrow_args(arena: &'a Bump, ps: &'a [(Layout<'a>, Symbol)]) -> &'a [Param<'a>] { fn init_borrow_args(arena: &'a Bump, ps: &'a [(Layout<'a>, Symbol)]) -> &'a [Param<'a>] {
Vec::from_iter_in( Vec::from_iter_in(
ps.iter().map(|(layout, symbol)| Param { ps.iter().map(|(layout, symbol)| Param {
borrow: should_borrow_layout(layout), ownership: Ownership::from_layout(layout),
layout: *layout, layout: *layout,
symbol: *symbol, symbol: *symbol,
}), }),
@ -247,7 +257,7 @@ impl<'a> ParamMap<'a> {
) -> &'a [Param<'a>] { ) -> &'a [Param<'a>] {
Vec::from_iter_in( Vec::from_iter_in(
ps.iter().map(|(layout, symbol)| Param { ps.iter().map(|(layout, symbol)| Param {
borrow: false, ownership: Ownership::Owned,
layout: *layout, layout: *layout,
symbol: *symbol, symbol: *symbol,
}), }),
@ -390,12 +400,12 @@ impl<'a> BorrowInfState<'a> {
fn update_param_map_help(&mut self, ps: &[Param<'a>]) -> &'a [Param<'a>] { 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); let mut new_ps = Vec::with_capacity_in(ps.len(), self.arena);
new_ps.extend(ps.iter().map(|p| { new_ps.extend(ps.iter().map(|p| {
if !p.borrow { if p.ownership == Ownership::Owned {
*p *p
} else if self.is_owned(p.symbol) { } else if self.is_owned(p.symbol) {
self.modified = true; self.modified = true;
let mut p = *p; let mut p = *p;
p.borrow = false; p.ownership = Ownership::Owned;
p p
} else { } else {
@ -412,15 +422,15 @@ impl<'a> BorrowInfState<'a> {
start: ParamOffset, start: ParamOffset,
length: usize, length: usize,
) { ) {
let index: usize = start.into(); let ParamOffset(index) = start;
let ps = &mut param_map.declarations[index..][..length]; let ps = &mut param_map.declarations[index..][..length];
for p in ps.iter_mut() { for p in ps.iter_mut() {
if !p.borrow { if p.ownership == Ownership::Owned {
// do nothing // do nothing
} else if self.is_owned(p.symbol) { } else if self.is_owned(p.symbol) {
self.modified = true; self.modified = true;
p.borrow = false; p.ownership = Ownership::Owned;
} else { } else {
// do nothing // do nothing
} }
@ -440,7 +450,7 @@ impl<'a> BorrowInfState<'a> {
debug_assert_eq!(xs.len(), ps.len()); debug_assert_eq!(xs.len(), ps.len());
for (x, p) in xs.iter().zip(ps.iter()) { for (x, p) in xs.iter().zip(ps.iter()) {
if !p.borrow { if p.ownership == Ownership::Owned {
self.own_var(*x); self.own_var(*x);
} }
} }
@ -568,44 +578,44 @@ impl<'a> BorrowInfState<'a> {
match op { match op {
ListMap { xs } => { ListMap { xs } => {
// own the list if the function wants to own the element // own the list if the function wants to own the element
if !function_ps[0].borrow { if function_ps[0].ownership == Ownership::Owned {
self.own_var(*xs); self.own_var(*xs);
} }
} }
ListMap2 { xs, ys } => { ListMap2 { xs, ys } => {
// own the lists if the function wants to own the element // own the lists if the function wants to own the element
if !function_ps[0].borrow { if function_ps[0].ownership == Ownership::Owned {
self.own_var(*xs); self.own_var(*xs);
} }
if !function_ps[1].borrow { if function_ps[1].ownership == Ownership::Owned {
self.own_var(*ys); self.own_var(*ys);
} }
} }
ListMap3 { xs, ys, zs } => { ListMap3 { xs, ys, zs } => {
// own the lists if the function wants to own the element // own the lists if the function wants to own the element
if !function_ps[0].borrow { if function_ps[0].ownership == Ownership::Owned {
self.own_var(*xs); self.own_var(*xs);
} }
if !function_ps[1].borrow { if function_ps[1].ownership == Ownership::Owned {
self.own_var(*ys); self.own_var(*ys);
} }
if !function_ps[2].borrow { if function_ps[2].ownership == Ownership::Owned {
self.own_var(*zs); self.own_var(*zs);
} }
} }
ListMap4 { xs, ys, zs, ws } => { ListMap4 { xs, ys, zs, ws } => {
// own the lists if the function wants to own the element // own the lists if the function wants to own the element
if !function_ps[0].borrow { if function_ps[0].ownership == Ownership::Owned {
self.own_var(*xs); self.own_var(*xs);
} }
if !function_ps[1].borrow { if function_ps[1].ownership == Ownership::Owned {
self.own_var(*ys); self.own_var(*ys);
} }
if !function_ps[2].borrow { if function_ps[2].ownership == Ownership::Owned {
self.own_var(*zs); self.own_var(*zs);
} }
if !function_ps[3].borrow { if function_ps[3].ownership == Ownership::Owned {
self.own_var(*ws); self.own_var(*ws);
} }
} }
@ -617,7 +627,9 @@ impl<'a> BorrowInfState<'a> {
// own the closure environment if the function needs to own it // own the closure environment if the function needs to own it
let function_env_position = op.function_arity(); let function_env_position = op.function_arity();
if let Some(false) = function_ps.get(function_env_position).map(|p| p.borrow) { if let Some(Ownership::Owned) =
function_ps.get(function_env_position).map(|p| p.ownership)
{
self.own_var(passed_function.captured_environment); self.own_var(passed_function.captured_environment);
} }
} }

View file

@ -2,6 +2,7 @@ use bumpalo::collections::vec::Vec;
use roc_module::low_level::LowLevel; use roc_module::low_level::LowLevel;
use roc_module::symbol::{IdentIds, Symbol}; use roc_module::symbol::{IdentIds, Symbol};
use crate::borrow::Ownership;
use crate::ir::{ use crate::ir::{
BranchInfo, Call, CallType, Expr, JoinPointId, Literal, Param, Stmt, UpdateModeId, BranchInfo, Call, CallType, Expr, JoinPointId, Literal, Param, Stmt, UpdateModeId,
}; };
@ -418,7 +419,7 @@ fn eq_tag_union_help<'a>(
} else { } else {
let loop_params_iter = operands.iter().map(|arg| Param { let loop_params_iter = operands.iter().map(|arg| Param {
symbol: *arg, symbol: *arg,
borrow: true, ownership: Ownership::Borrowed,
layout: Layout::Union(union_layout), layout: Layout::Union(union_layout),
}); });
@ -718,13 +719,13 @@ fn eq_list<'a>(
let param_addr1 = Param { let param_addr1 = Param {
symbol: addr1, symbol: addr1,
borrow: false, ownership: Ownership::Owned,
layout: layout_isize, layout: layout_isize,
}; };
let param_addr2 = Param { let param_addr2 = Param {
symbol: addr2, symbol: addr2,
borrow: false, ownership: Ownership::Owned,
layout: layout_isize, layout: layout_isize,
}; };

View file

@ -6,6 +6,7 @@ use roc_module::low_level::{LowLevel, LowLevel::*};
use roc_module::symbol::{IdentIds, Symbol}; use roc_module::symbol::{IdentIds, Symbol};
use roc_target::PtrWidth; use roc_target::PtrWidth;
use crate::borrow::Ownership;
use crate::code_gen_help::let_lowlevel; use crate::code_gen_help::let_lowlevel;
use crate::ir::{ use crate::ir::{
BranchInfo, Call, CallType, Expr, JoinPointId, Literal, ModifyRc, Param, Stmt, UpdateModeId, BranchInfo, Call, CallType, Expr, JoinPointId, Literal, ModifyRc, Param, Stmt, UpdateModeId,
@ -944,7 +945,7 @@ fn refcount_list_elems<'a>(
let param_addr = Param { let param_addr = Param {
symbol: addr, symbol: addr,
borrow: false, ownership: Ownership::Owned,
layout: layout_isize, layout: layout_isize,
}; };
@ -1602,7 +1603,7 @@ fn refcount_union_tailrec<'a>(
let jp_param = Param { let jp_param = Param {
symbol: next_ptr, symbol: next_ptr,
borrow: true, ownership: Ownership::Borrowed,
layout, layout,
}; };
@ -1622,7 +1623,7 @@ fn refcount_union_tailrec<'a>(
let loop_init = Stmt::Jump(tailrec_loop, root.arena.alloc([initial_structure])); let loop_init = Stmt::Jump(tailrec_loop, root.arena.alloc([initial_structure]));
let loop_param = Param { let loop_param = Param {
symbol: current, symbol: current,
borrow: true, ownership: Ownership::Borrowed,
layout: Layout::Union(union_layout), layout: Layout::Union(union_layout),
}; };

View file

@ -347,7 +347,7 @@ impl<'a, 'r> Ctx<'a, 'r> {
for Param { for Param {
symbol, symbol,
layout, layout,
borrow: _, ownership: _,
} in parameters } in parameters
{ {
ctx.insert(*symbol, *layout); ctx.insert(*symbol, *layout);
@ -369,7 +369,7 @@ impl<'a, 'r> Ctx<'a, 'r> {
for (arg, param) in symbols.iter().zip(parameters.iter()) { for (arg, param) in symbols.iter().zip(parameters.iter()) {
let Param { let Param {
symbol: _, symbol: _,
borrow: _, ownership: _,
layout, layout,
} = param; } = param;
self.check_sym_layout(*arg, *layout, UseKind::JumpArg); self.check_sym_layout(*arg, *layout, UseKind::JumpArg);

View file

@ -1,3 +1,4 @@
use crate::borrow::Ownership;
use crate::ir::{ use crate::ir::{
build_list_index_probe, BranchInfo, Call, CallType, DestructType, Env, Expr, JoinPointId, build_list_index_probe, BranchInfo, Call, CallType, DestructType, Env, Expr, JoinPointId,
ListIndex, Literal, Param, Pattern, Procs, Stmt, ListIndex, Literal, Param, Pattern, Procs, Stmt,
@ -1906,7 +1907,7 @@ fn decide_to_branching<'a>(
let param = Param { let param = Param {
symbol: test_symbol, symbol: test_symbol,
layout: Layout::Builtin(Builtin::Bool), layout: Layout::Builtin(Builtin::Bool),
borrow: false, ownership: Ownership::Owned,
}; };
let join = Stmt::Join { let join = Stmt::Join {

View file

@ -1,4 +1,4 @@
use crate::borrow::{ParamMap, BORROWED, OWNED}; use crate::borrow::{Ownership, ParamMap, BORROWED, OWNED};
use crate::ir::{ use crate::ir::{
CallType, Expr, HigherOrderLowLevel, JoinPointId, ModifyRc, Param, Proc, ProcLayout, Stmt, CallType, Expr, HigherOrderLowLevel, JoinPointId, ModifyRc, Param, Proc, ProcLayout, Stmt,
UpdateModeIds, UpdateModeIds,
@ -61,13 +61,13 @@ impl DataFunction {
use DataFunction::*; use DataFunction::*;
let data_borrowed = !vars[&lowlevel_argument].consume; let data_borrowed = !vars[&lowlevel_argument].consume;
let function_borrows = passed_function_argument.borrow; let function_ownership = passed_function_argument.ownership;
match (data_borrowed, function_borrows) { match (data_borrowed, function_ownership) {
(BORROWED, BORROWED) => DataBorrowedFunctionBorrows, (BORROWED, Ownership::Borrowed) => DataBorrowedFunctionBorrows,
(BORROWED, OWNED) => DataBorrowedFunctionOwns, (BORROWED, Ownership::Owned) => DataBorrowedFunctionOwns,
(OWNED, BORROWED) => DataOwnedFunctionBorrows, (OWNED, Ownership::Borrowed) => DataOwnedFunctionBorrows,
(OWNED, OWNED) => DataOwnedFunctionOwns, (OWNED, Ownership::Owned) => DataOwnedFunctionOwns,
} }
} }
} }
@ -302,7 +302,10 @@ where
fn is_borrow_param(x: Symbol, ys: &[Symbol], ps: &[Param]) -> bool { fn is_borrow_param(x: Symbol, ys: &[Symbol], ps: &[Param]) -> bool {
// default to owned arguments // default to owned arguments
let is_owned = |i: usize| match ps.get(i) { let is_owned = |i: usize| match ps.get(i) {
Some(param) => !param.borrow, Some(param) => match param.ownership {
Ownership::Owned => true,
Ownership::Borrowed => false,
},
None => unreachable!("or?"), None => unreachable!("or?"),
}; };
is_borrow_param_help(x, ys, is_owned) is_borrow_param_help(x, ys, is_owned)
@ -473,7 +476,10 @@ impl<'a, 'i> Context<'a, 'i> {
) -> &'a Stmt<'a> { ) -> &'a Stmt<'a> {
// default to owned arguments // default to owned arguments
let pred = |i: usize| match ps.get(i) { let pred = |i: usize| match ps.get(i) {
Some(param) => !param.borrow, Some(param) => match param.ownership {
Ownership::Owned => true,
Ownership::Borrowed => false,
},
None => unreachable!("or?"), None => unreachable!("or?"),
}; };
self.add_inc_before_help(xs, pred, b, live_vars_after) self.add_inc_before_help(xs, pred, b, live_vars_after)
@ -992,7 +998,10 @@ impl<'a, 'i> Context<'a, 'i> {
for p in ps.iter() { for p in ps.iter() {
let info = VarInfo { let info = VarInfo {
reference: p.layout.contains_refcounted(self.layout_interner), reference: p.layout.contains_refcounted(self.layout_interner),
consume: !p.borrow, consume: match p.ownership {
Ownership::Owned => true,
Ownership::Borrowed => false,
},
persistent: false, persistent: false,
reset: false, reset: false,
}; };
@ -1014,7 +1023,7 @@ impl<'a, 'i> Context<'a, 'i> {
b_live_vars: &LiveVarSet, b_live_vars: &LiveVarSet,
) -> &'a Stmt<'a> { ) -> &'a Stmt<'a> {
for p in ps.iter() { for p in ps.iter() {
if !p.borrow if p.ownership == Ownership::Owned
&& p.layout.contains_refcounted(self.layout_interner) && p.layout.contains_refcounted(self.layout_interner)
&& !b_live_vars.contains(&p.symbol) && !b_live_vars.contains(&p.symbol)
{ {
@ -1334,7 +1343,7 @@ fn create_holl_call<'a>(
arguments: &'a [Symbol], arguments: &'a [Symbol],
) -> Expr<'a> { ) -> Expr<'a> {
let call = crate::ir::Call { let call = crate::ir::Call {
call_type: if let Some(OWNED) = param.map(|p| p.borrow) { call_type: if let Some(Ownership::Owned) = param.map(|p| p.ownership) {
let mut passed_function = holl.passed_function; let mut passed_function = holl.passed_function;
passed_function.owns_captured_environment = true; passed_function.owns_captured_environment = true;
@ -1519,7 +1528,7 @@ fn visit_proc<'a, 'i>(
None => Vec::from_iter_in( None => Vec::from_iter_in(
proc.args.iter().cloned().map(|(layout, symbol)| Param { proc.args.iter().cloned().map(|(layout, symbol)| Param {
symbol, symbol,
borrow: false, ownership: Ownership::Owned,
layout, layout,
}), }),
arena, arena,

View file

@ -1,5 +1,6 @@
#![allow(clippy::manual_map)] #![allow(clippy::manual_map)]
use crate::borrow::Ownership;
use crate::layout::{ use crate::layout::{
self, Builtin, ClosureCallOptions, ClosureRepresentation, EnumDispatch, LambdaName, LambdaSet, self, Builtin, ClosureCallOptions, ClosureRepresentation, EnumDispatch, LambdaName, LambdaSet,
Layout, LayoutCache, LayoutInterner, LayoutProblem, Niche, RawFunctionLayout, STLayoutInterner, Layout, LayoutCache, LayoutInterner, LayoutProblem, Niche, RawFunctionLayout, STLayoutInterner,
@ -1525,14 +1526,14 @@ pub struct JoinPointId(pub Symbol);
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Param<'a> { pub struct Param<'a> {
pub symbol: Symbol, pub symbol: Symbol,
pub borrow: bool, pub ownership: Ownership,
pub layout: Layout<'a>, pub layout: Layout<'a>,
} }
impl<'a> Param<'a> { impl<'a> Param<'a> {
pub const EMPTY: Self = Param { pub const EMPTY: Self = Param {
symbol: Symbol::EMPTY_PARAM, symbol: Symbol::EMPTY_PARAM,
borrow: false, ownership: Ownership::Owned,
layout: Layout::UNIT, layout: Layout::UNIT,
}; };
} }
@ -4545,7 +4546,7 @@ pub fn with_hole<'a>(
let param = Param { let param = Param {
symbol: assigned, symbol: assigned,
layout, layout,
borrow: false, ownership: Ownership::Owned,
}; };
Stmt::Join { Stmt::Join {
@ -4610,7 +4611,7 @@ pub fn with_hole<'a>(
let param = Param { let param = Param {
symbol: assigned, symbol: assigned,
layout, layout,
borrow: false, ownership: Ownership::Owned,
}; };
Stmt::Join { Stmt::Join {
@ -10402,7 +10403,7 @@ where
let param = Param { let param = Param {
symbol: assigned, symbol: assigned,
layout: return_layout, layout: return_layout,
borrow: false, ownership: Ownership::Owned,
}; };
Stmt::Join { Stmt::Join {
@ -10626,7 +10627,7 @@ fn union_lambda_set_to_switch<'a>(
let param = Param { let param = Param {
symbol: assigned, symbol: assigned,
layout: *return_layout, layout: *return_layout,
borrow: false, ownership: Ownership::Owned,
}; };
Stmt::Join { Stmt::Join {
@ -10777,7 +10778,7 @@ fn enum_lambda_set_to_switch<'a>(
let param = Param { let param = Param {
symbol: assigned, symbol: assigned,
layout: *return_layout, layout: *return_layout,
borrow: false, ownership: Ownership::Owned,
}; };
Stmt::Join { Stmt::Join {
@ -10880,7 +10881,7 @@ where
let param = Param { let param = Param {
symbol: assigned, symbol: assigned,
layout: return_layout, layout: return_layout,
borrow: false, ownership: Ownership::Owned,
}; };
Stmt::Join { Stmt::Join {

View file

@ -1,5 +1,6 @@
#![allow(clippy::manual_map)] #![allow(clippy::manual_map)]
use crate::borrow::Ownership;
use crate::ir::{CallType, Expr, JoinPointId, Param, Stmt}; use crate::ir::{CallType, Expr, JoinPointId, Param, Stmt};
use crate::layout::{LambdaName, Layout}; use crate::layout::{LambdaName, Layout};
use bumpalo::collections::Vec; use bumpalo::collections::Vec;
@ -46,7 +47,7 @@ pub fn make_tail_recursive<'a>(
args.iter().map(|(layout, symbol, _)| Param { args.iter().map(|(layout, symbol, _)| Param {
symbol: *symbol, symbol: *symbol,
layout: *layout, layout: *layout,
borrow: true, ownership: Ownership::Borrowed,
}), }),
arena, arena,
) )