mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 12:18:19 +00:00
Make all layouts interned in mono
This commit is contained in:
parent
dc6b7003a8
commit
fa8effd3e8
14 changed files with 932 additions and 866 deletions
|
@ -3092,6 +3092,7 @@ fn update<'a>(
|
|||
|
||||
Proc::insert_reset_reuse_operations(
|
||||
arena,
|
||||
&mut layout_interner,
|
||||
module_id,
|
||||
ident_ids,
|
||||
&mut update_mode_ids,
|
||||
|
@ -3430,7 +3431,7 @@ fn proc_layout_for<'a>(
|
|||
// is a function value
|
||||
roc_mono::ir::ProcLayout {
|
||||
arguments: &[],
|
||||
result: Layout::struct_no_name_order(&[]),
|
||||
result: Layout::UNIT,
|
||||
niche: Niche::NONE,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::hash::Hash;
|
|||
use crate::ir::{
|
||||
Expr, HigherOrderLowLevel, JoinPointId, Param, PassedFunction, Proc, ProcLayout, Stmt,
|
||||
};
|
||||
use crate::layout::Layout;
|
||||
use crate::layout::{InLayout, Layout, LayoutInterner, STLayoutInterner};
|
||||
use bumpalo::collections::Vec;
|
||||
use bumpalo::Bump;
|
||||
use roc_collections::all::{MutMap, MutSet};
|
||||
|
@ -33,6 +33,7 @@ impl Ownership {
|
|||
}
|
||||
pub fn infer_borrow<'a>(
|
||||
arena: &'a Bump,
|
||||
interner: &STLayoutInterner<'a>,
|
||||
procs: &MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>,
|
||||
host_exposed_procs: &[Symbol],
|
||||
) -> ParamMap<'a> {
|
||||
|
@ -49,7 +50,7 @@ pub fn infer_borrow<'a>(
|
|||
};
|
||||
|
||||
for (key, proc) in procs {
|
||||
param_map.visit_proc(arena, proc, *key);
|
||||
param_map.visit_proc(arena, interner, proc, *key);
|
||||
}
|
||||
|
||||
let mut env = BorrowInfState {
|
||||
|
@ -232,10 +233,14 @@ impl<'a> ParamMap<'a> {
|
|||
}
|
||||
|
||||
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,
|
||||
interner: &STLayoutInterner<'a>,
|
||||
ps: &'a [Param<'a>],
|
||||
) -> &'a [Param<'a>] {
|
||||
Vec::from_iter_in(
|
||||
ps.iter().map(|p| Param {
|
||||
ownership: Ownership::from_layout(&p.layout),
|
||||
ownership: Ownership::from_layout(&interner.get(p.layout)),
|
||||
layout: p.layout,
|
||||
symbol: p.symbol,
|
||||
}),
|
||||
|
@ -244,10 +249,14 @@ impl<'a> ParamMap<'a> {
|
|||
.into_bump_slice()
|
||||
}
|
||||
|
||||
fn init_borrow_args(arena: &'a Bump, ps: &'a [(Layout<'a>, Symbol)]) -> &'a [Param<'a>] {
|
||||
fn init_borrow_args(
|
||||
arena: &'a Bump,
|
||||
interner: &STLayoutInterner<'a>,
|
||||
ps: &'a [(InLayout<'a>, Symbol)],
|
||||
) -> &'a [Param<'a>] {
|
||||
Vec::from_iter_in(
|
||||
ps.iter().map(|(layout, symbol)| Param {
|
||||
ownership: Ownership::from_layout(layout),
|
||||
ownership: Ownership::from_layout(&interner.get(*layout)),
|
||||
layout: *layout,
|
||||
symbol: *symbol,
|
||||
}),
|
||||
|
@ -258,7 +267,7 @@ impl<'a> ParamMap<'a> {
|
|||
|
||||
fn init_borrow_args_always_owned(
|
||||
arena: &'a Bump,
|
||||
ps: &'a [(Layout<'a>, Symbol)],
|
||||
ps: &'a [(InLayout<'a>, Symbol)],
|
||||
) -> &'a [Param<'a>] {
|
||||
Vec::from_iter_in(
|
||||
ps.iter().map(|(layout, symbol)| Param {
|
||||
|
@ -271,15 +280,21 @@ impl<'a> ParamMap<'a> {
|
|||
.into_bump_slice()
|
||||
}
|
||||
|
||||
fn visit_proc(&mut self, arena: &'a Bump, proc: &Proc<'a>, key: (Symbol, ProcLayout<'a>)) {
|
||||
fn visit_proc(
|
||||
&mut self,
|
||||
arena: &'a Bump,
|
||||
interner: &STLayoutInterner<'a>,
|
||||
proc: &Proc<'a>,
|
||||
key: (Symbol, ProcLayout<'a>),
|
||||
) {
|
||||
if proc.must_own_arguments {
|
||||
self.visit_proc_always_owned(arena, proc, key);
|
||||
self.visit_proc_always_owned(arena, interner, proc, key);
|
||||
return;
|
||||
}
|
||||
|
||||
let index: usize = self.get_param_offset(key.0, key.1).into();
|
||||
|
||||
for (i, param) in Self::init_borrow_args(arena, proc.args)
|
||||
for (i, param) in Self::init_borrow_args(arena, interner, proc.args)
|
||||
.iter()
|
||||
.copied()
|
||||
.enumerate()
|
||||
|
@ -287,12 +302,13 @@ impl<'a> ParamMap<'a> {
|
|||
self.declarations[index + i] = param;
|
||||
}
|
||||
|
||||
self.visit_stmt(arena, proc.name.name(), &proc.body);
|
||||
self.visit_stmt(arena, interner, proc.name.name(), &proc.body);
|
||||
}
|
||||
|
||||
fn visit_proc_always_owned(
|
||||
&mut self,
|
||||
arena: &'a Bump,
|
||||
interner: &STLayoutInterner<'a>,
|
||||
proc: &Proc<'a>,
|
||||
key: (Symbol, ProcLayout<'a>),
|
||||
) {
|
||||
|
@ -306,10 +322,16 @@ impl<'a> ParamMap<'a> {
|
|||
self.declarations[index + i] = param;
|
||||
}
|
||||
|
||||
self.visit_stmt(arena, proc.name.name(), &proc.body);
|
||||
self.visit_stmt(arena, interner, proc.name.name(), &proc.body);
|
||||
}
|
||||
|
||||
fn visit_stmt(&mut self, arena: &'a Bump, _fnid: Symbol, stmt: &Stmt<'a>) {
|
||||
fn visit_stmt(
|
||||
&mut self,
|
||||
arena: &'a Bump,
|
||||
interner: &STLayoutInterner<'a>,
|
||||
_fnid: Symbol,
|
||||
stmt: &Stmt<'a>,
|
||||
) {
|
||||
use Stmt::*;
|
||||
|
||||
let mut stack = bumpalo::vec![in arena; stmt];
|
||||
|
@ -323,7 +345,7 @@ impl<'a> ParamMap<'a> {
|
|||
body: b,
|
||||
} => {
|
||||
self.join_points
|
||||
.insert(*j, Self::init_borrow_params(arena, xs));
|
||||
.insert(*j, Self::init_borrow_params(arena, interner, xs));
|
||||
|
||||
stack.push(v);
|
||||
stack.push(b);
|
||||
|
@ -527,8 +549,7 @@ impl<'a> BorrowInfState<'a> {
|
|||
arg_layouts,
|
||||
..
|
||||
} => {
|
||||
let top_level =
|
||||
ProcLayout::new(self.arena, arg_layouts, name.niche(), **ret_layout);
|
||||
let top_level = ProcLayout::new(self.arena, arg_layouts, name.niche(), *ret_layout);
|
||||
|
||||
// get the borrow signature of the applied function
|
||||
let ps = param_map
|
||||
|
@ -756,7 +777,7 @@ impl<'a> BorrowInfState<'a> {
|
|||
Stmt::Ret(z),
|
||||
) = (v, b)
|
||||
{
|
||||
let top_level = ProcLayout::new(self.arena, arg_layouts, g.niche(), **ret_layout);
|
||||
let top_level = ProcLayout::new(self.arena, arg_layouts, g.niche(), *ret_layout);
|
||||
|
||||
if self.current_proc == g.name() && x == *z {
|
||||
// anonymous functions (for which the ps may not be known)
|
||||
|
|
|
@ -20,9 +20,9 @@ pub fn eq_generic<'a>(
|
|||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout: Layout<'a>,
|
||||
layout: InLayout<'a>,
|
||||
) -> Stmt<'a> {
|
||||
let main_body = match layout {
|
||||
let main_body = match layout_interner.get(layout) {
|
||||
Layout::Builtin(Builtin::Int(_) | Builtin::Float(_) | Builtin::Bool | Builtin::Decimal) => {
|
||||
unreachable!(
|
||||
"No generated proc for `==`. Use direct code gen for {:?}",
|
||||
|
@ -142,7 +142,7 @@ fn eq_struct<'a>(
|
|||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
field_layouts: &'a [Layout<'a>],
|
||||
field_layouts: &'a [InLayout<'a>],
|
||||
) -> Stmt<'a> {
|
||||
let mut else_stmt = Stmt::Ret(Symbol::BOOL_TRUE);
|
||||
for (i, layout) in field_layouts.iter().enumerate().rev() {
|
||||
|
@ -277,7 +277,7 @@ fn eq_tag_union_help<'a>(
|
|||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
union_layout: UnionLayout<'a>,
|
||||
tag_layouts: &'a [&'a [Layout<'a>]],
|
||||
tag_layouts: &'a [&'a [InLayout<'a>]],
|
||||
nullable_id: Option<TagIdIntType>,
|
||||
) -> Stmt<'a> {
|
||||
let tailrec_loop = JoinPointId(root.create_symbol(ident_ids, "tailrec_loop"));
|
||||
|
@ -417,10 +417,11 @@ fn eq_tag_union_help<'a>(
|
|||
if is_non_recursive {
|
||||
compare_ptr_or_value
|
||||
} else {
|
||||
let union_layout = layout_interner.insert(Layout::Union(union_layout));
|
||||
let loop_params_iter = operands.iter().map(|arg| Param {
|
||||
symbol: *arg,
|
||||
ownership: Ownership::Borrowed,
|
||||
layout: Layout::Union(union_layout),
|
||||
layout: union_layout,
|
||||
});
|
||||
|
||||
let loop_start = Stmt::Jump(tailrec_loop, root.arena.alloc([ARG_1, ARG_2]));
|
||||
|
@ -442,7 +443,7 @@ fn eq_tag_fields<'a>(
|
|||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
tailrec_loop: JoinPointId,
|
||||
union_layout: UnionLayout<'a>,
|
||||
field_layouts: &'a [Layout<'a>],
|
||||
field_layouts: &'a [InLayout<'a>],
|
||||
operands: [Symbol; 2],
|
||||
tag_id: TagIdIntType,
|
||||
) -> Stmt<'a> {
|
||||
|
@ -450,7 +451,7 @@ fn eq_tag_fields<'a>(
|
|||
// (If there are more than one, the others will use non-tail recursion)
|
||||
let rec_ptr_index = field_layouts
|
||||
.iter()
|
||||
.position(|field| matches!(field, Layout::RecursivePointer));
|
||||
.position(|field| matches!(layout_interner.get(*field), Layout::RecursivePointer));
|
||||
|
||||
let (tailrec_index, innermost_stmt) = match rec_ptr_index {
|
||||
None => {
|
||||
|
@ -579,8 +580,6 @@ fn eq_boxed<'a>(
|
|||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
inner_layout: InLayout<'a>,
|
||||
) -> Stmt<'a> {
|
||||
let inner_layout = layout_interner.get(inner_layout);
|
||||
|
||||
let a = root.create_symbol(ident_ids, "a");
|
||||
let b = root.create_symbol(ident_ids, "b");
|
||||
let result = root.create_symbol(ident_ids, "result");
|
||||
|
@ -638,11 +637,9 @@ fn eq_list<'a>(
|
|||
let layout_isize = root.layout_isize;
|
||||
let arena = root.arena;
|
||||
|
||||
let elem_layout = layout_interner.get(elem_layout);
|
||||
|
||||
// A "Box" layout (heap pointer to a single list element)
|
||||
let box_union_layout = UnionLayout::NonNullableUnwrapped(root.arena.alloc([elem_layout]));
|
||||
let box_layout = Layout::Union(box_union_layout);
|
||||
let box_layout = layout_interner.insert(Layout::Union(box_union_layout));
|
||||
|
||||
// Compare lengths
|
||||
|
||||
|
@ -687,7 +684,10 @@ fn eq_list<'a>(
|
|||
// let size = literal int
|
||||
let size = root.create_symbol(ident_ids, "size");
|
||||
let size_expr = Expr::Literal(Literal::Int(
|
||||
(elem_layout.stack_size(layout_interner, root.target_info) as i128).to_ne_bytes(),
|
||||
(layout_interner
|
||||
.get(elem_layout)
|
||||
.stack_size(layout_interner, root.target_info) as i128)
|
||||
.to_ne_bytes(),
|
||||
));
|
||||
let size_stmt = |next| Stmt::Let(size, size_expr, layout_isize, next);
|
||||
|
||||
|
|
|
@ -9,14 +9,14 @@ use crate::ir::{
|
|||
SelfRecursive, Stmt, UpdateModeId,
|
||||
};
|
||||
use crate::layout::{
|
||||
Builtin, LambdaName, Layout, LayoutInterner, Niche, STLayoutInterner, UnionLayout,
|
||||
Builtin, InLayout, LambdaName, Layout, LayoutInterner, Niche, STLayoutInterner, UnionLayout,
|
||||
};
|
||||
|
||||
mod equality;
|
||||
mod refcount;
|
||||
|
||||
const LAYOUT_BOOL: Layout = Layout::Builtin(Builtin::Bool);
|
||||
const LAYOUT_UNIT: Layout = Layout::UNIT;
|
||||
const LAYOUT_BOOL: InLayout = Layout::BOOL;
|
||||
const LAYOUT_UNIT: InLayout = Layout::UNIT;
|
||||
|
||||
const ARG_1: Symbol = Symbol::ARG_1;
|
||||
const ARG_2: Symbol = Symbol::ARG_2;
|
||||
|
@ -43,7 +43,7 @@ impl HelperOp {
|
|||
#[derive(Debug)]
|
||||
struct Specialization<'a> {
|
||||
op: HelperOp,
|
||||
layout: Layout<'a>,
|
||||
layout: InLayout<'a>,
|
||||
symbol: Symbol,
|
||||
proc: Option<Proc<'a>>,
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ pub struct CodeGenHelp<'a> {
|
|||
arena: &'a Bump,
|
||||
home: ModuleId,
|
||||
target_info: TargetInfo,
|
||||
layout_isize: Layout<'a>,
|
||||
layout_isize: InLayout<'a>,
|
||||
union_refcount: UnionLayout<'a>,
|
||||
specializations: Vec<'a, Specialization<'a>>,
|
||||
debug_recursion_depth: usize,
|
||||
|
@ -121,11 +121,11 @@ impl<'a> CodeGenHelp<'a> {
|
|||
&mut self,
|
||||
ident_ids: &mut IdentIds,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout: Layout<'a>,
|
||||
layout: InLayout<'a>,
|
||||
modify: &ModifyRc,
|
||||
following: &'a Stmt<'a>,
|
||||
) -> (&'a Stmt<'a>, Vec<'a, (Symbol, ProcLayout<'a>)>) {
|
||||
if !refcount::is_rc_implemented_yet(layout_interner, &layout) {
|
||||
if !refcount::is_rc_implemented_yet(layout_interner, layout) {
|
||||
// Just a warning, so we can decouple backend development from refcounting development.
|
||||
// When we are closer to completion, we can change it to a panic.
|
||||
println!(
|
||||
|
@ -166,7 +166,7 @@ impl<'a> CodeGenHelp<'a> {
|
|||
&mut self,
|
||||
ident_ids: &mut IdentIds,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout: Layout<'a>,
|
||||
layout: InLayout<'a>,
|
||||
argument: Symbol,
|
||||
) -> (Expr<'a>, Vec<'a, (Symbol, ProcLayout<'a>)>) {
|
||||
let mut ctx = Context {
|
||||
|
@ -178,7 +178,7 @@ impl<'a> CodeGenHelp<'a> {
|
|||
let proc_name = self.find_or_create_proc(ident_ids, &mut ctx, layout_interner, layout);
|
||||
|
||||
let arguments = self.arena.alloc([argument]);
|
||||
let ret_layout = self.arena.alloc(layout);
|
||||
let ret_layout = layout;
|
||||
let arg_layouts = self.arena.alloc([layout]);
|
||||
let expr = Expr::Call(Call {
|
||||
call_type: CallType::ByName {
|
||||
|
@ -200,7 +200,7 @@ impl<'a> CodeGenHelp<'a> {
|
|||
&mut self,
|
||||
ident_ids: &mut IdentIds,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout: Layout<'a>,
|
||||
layout: InLayout<'a>,
|
||||
op: HelperOp,
|
||||
) -> (Symbol, Vec<'a, (Symbol, ProcLayout<'a>)>) {
|
||||
let mut ctx = Context {
|
||||
|
@ -220,7 +220,7 @@ impl<'a> CodeGenHelp<'a> {
|
|||
&mut self,
|
||||
ident_ids: &mut IdentIds,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout: &Layout<'a>,
|
||||
layout: InLayout<'a>,
|
||||
arguments: &'a [Symbol],
|
||||
) -> (Expr<'a>, Vec<'a, (Symbol, ProcLayout<'a>)>) {
|
||||
let mut ctx = Context {
|
||||
|
@ -230,7 +230,7 @@ impl<'a> CodeGenHelp<'a> {
|
|||
};
|
||||
|
||||
let expr = self
|
||||
.call_specialized_op(ident_ids, &mut ctx, layout_interner, *layout, arguments)
|
||||
.call_specialized_op(ident_ids, &mut ctx, layout_interner, layout, arguments)
|
||||
.unwrap();
|
||||
|
||||
(expr, ctx.new_linker_data)
|
||||
|
@ -247,7 +247,7 @@ impl<'a> CodeGenHelp<'a> {
|
|||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
called_layout: Layout<'a>,
|
||||
called_layout: InLayout<'a>,
|
||||
arguments: &'a [Symbol],
|
||||
) -> Option<Expr<'a>> {
|
||||
use HelperOp::*;
|
||||
|
@ -255,23 +255,23 @@ impl<'a> CodeGenHelp<'a> {
|
|||
// debug_assert!(self.debug_recursion_depth < 100);
|
||||
self.debug_recursion_depth += 1;
|
||||
|
||||
let layout = if matches!(called_layout, Layout::RecursivePointer) {
|
||||
let layout = if matches!(layout_interner.get(called_layout), Layout::RecursivePointer) {
|
||||
let union_layout = ctx.recursive_union.unwrap();
|
||||
Layout::Union(union_layout)
|
||||
layout_interner.insert(Layout::Union(union_layout))
|
||||
} else {
|
||||
called_layout
|
||||
};
|
||||
|
||||
if layout_needs_helper_proc(&layout, ctx.op) {
|
||||
if layout_needs_helper_proc(layout_interner, layout, ctx.op) {
|
||||
let proc_name = self.find_or_create_proc(ident_ids, ctx, layout_interner, layout);
|
||||
|
||||
let (ret_layout, arg_layouts): (&'a Layout<'a>, &'a [Layout<'a>]) = {
|
||||
let (ret_layout, arg_layouts): (InLayout<'a>, &'a [InLayout<'a>]) = {
|
||||
let arg = self.replace_rec_ptr(ctx, layout_interner, layout);
|
||||
match ctx.op {
|
||||
Dec | DecRef(_) => (&LAYOUT_UNIT, self.arena.alloc([arg])),
|
||||
Reset => (self.arena.alloc(layout), self.arena.alloc([layout])),
|
||||
Inc => (&LAYOUT_UNIT, self.arena.alloc([arg, self.layout_isize])),
|
||||
Eq => (&LAYOUT_BOOL, self.arena.alloc([arg, arg])),
|
||||
Dec | DecRef(_) => (LAYOUT_UNIT, self.arena.alloc([arg])),
|
||||
Reset => (layout, self.arena.alloc([layout])),
|
||||
Inc => (LAYOUT_UNIT, self.arena.alloc([arg, self.layout_isize])),
|
||||
Eq => (LAYOUT_BOOL, self.arena.alloc([arg, arg])),
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -302,7 +302,7 @@ impl<'a> CodeGenHelp<'a> {
|
|||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
orig_layout: Layout<'a>,
|
||||
orig_layout: InLayout<'a>,
|
||||
) -> Symbol {
|
||||
use HelperOp::*;
|
||||
|
||||
|
@ -320,7 +320,7 @@ impl<'a> CodeGenHelp<'a> {
|
|||
// Procs can be recursive, so we need to create the symbol before the body is complete
|
||||
// But with nested recursion, that means Symbols and Procs can end up in different orders.
|
||||
// We want the same order, especially for function indices in Wasm. So create an empty slot and fill it in later.
|
||||
let (proc_symbol, proc_layout) = self.create_proc_symbol(ident_ids, ctx, &layout);
|
||||
let (proc_symbol, proc_layout) = self.create_proc_symbol(ident_ids, ctx, layout);
|
||||
ctx.new_linker_data.push((proc_symbol, proc_layout));
|
||||
let spec_index = self.specializations.len();
|
||||
self.specializations.push(Specialization {
|
||||
|
@ -360,7 +360,7 @@ impl<'a> CodeGenHelp<'a> {
|
|||
),
|
||||
};
|
||||
|
||||
let args: &'a [(Layout<'a>, Symbol)] = {
|
||||
let args: &'a [(InLayout<'a>, Symbol)] = {
|
||||
let roc_value = (layout, ARG_1);
|
||||
match ctx.op {
|
||||
Inc => {
|
||||
|
@ -390,7 +390,7 @@ impl<'a> CodeGenHelp<'a> {
|
|||
&self,
|
||||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout: &Layout<'a>,
|
||||
layout: InLayout<'a>,
|
||||
) -> (Symbol, ProcLayout<'a>) {
|
||||
let debug_name = format!(
|
||||
"#help{}_{:?}_{:?}",
|
||||
|
@ -403,23 +403,23 @@ impl<'a> CodeGenHelp<'a> {
|
|||
|
||||
let proc_layout = match ctx.op {
|
||||
HelperOp::Inc => ProcLayout {
|
||||
arguments: self.arena.alloc([*layout, self.layout_isize]),
|
||||
arguments: self.arena.alloc([layout, self.layout_isize]),
|
||||
result: LAYOUT_UNIT,
|
||||
niche: Niche::NONE,
|
||||
},
|
||||
HelperOp::Dec => ProcLayout {
|
||||
arguments: self.arena.alloc([*layout]),
|
||||
arguments: self.arena.alloc([layout]),
|
||||
result: LAYOUT_UNIT,
|
||||
niche: Niche::NONE,
|
||||
},
|
||||
HelperOp::Reset => ProcLayout {
|
||||
arguments: self.arena.alloc([*layout]),
|
||||
result: *layout,
|
||||
arguments: self.arena.alloc([layout]),
|
||||
result: layout,
|
||||
niche: Niche::NONE,
|
||||
},
|
||||
HelperOp::DecRef(_) => unreachable!("No generated Proc for DecRef"),
|
||||
HelperOp::Eq => ProcLayout {
|
||||
arguments: self.arena.alloc([*layout, *layout]),
|
||||
arguments: self.arena.alloc([layout, layout]),
|
||||
result: LAYOUT_BOOL,
|
||||
niche: Niche::NONE,
|
||||
},
|
||||
|
@ -442,16 +442,15 @@ impl<'a> CodeGenHelp<'a> {
|
|||
&mut self,
|
||||
ctx: &Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout: Layout<'a>,
|
||||
) -> Layout<'a> {
|
||||
match layout {
|
||||
layout: InLayout<'a>,
|
||||
) -> InLayout<'a> {
|
||||
let layout = match layout_interner.get(layout) {
|
||||
Layout::Builtin(Builtin::List(v)) => {
|
||||
let v = self.replace_rec_ptr(ctx, layout_interner, layout_interner.get(v));
|
||||
let v = layout_interner.insert(v);
|
||||
let v = self.replace_rec_ptr(ctx, layout_interner, v);
|
||||
Layout::Builtin(Builtin::List(v))
|
||||
}
|
||||
|
||||
Layout::Builtin(_) => layout,
|
||||
Layout::Builtin(_) => return layout,
|
||||
|
||||
Layout::Struct {
|
||||
field_layouts,
|
||||
|
@ -482,54 +481,53 @@ impl<'a> CodeGenHelp<'a> {
|
|||
Layout::Union(_) => {
|
||||
// we always fully unroll recursive types. That means tha when we find a
|
||||
// recursive tag union we can replace it with the layout
|
||||
layout
|
||||
return layout;
|
||||
}
|
||||
|
||||
Layout::Boxed(inner) => {
|
||||
let inner = layout_interner.get(inner);
|
||||
let inner = self.replace_rec_ptr(ctx, layout_interner, inner);
|
||||
let inner = layout_interner.insert(inner);
|
||||
Layout::Boxed(inner)
|
||||
}
|
||||
|
||||
Layout::LambdaSet(lambda_set) => self.replace_rec_ptr(
|
||||
ctx,
|
||||
layout_interner,
|
||||
lambda_set.runtime_representation(layout_interner),
|
||||
),
|
||||
Layout::LambdaSet(lambda_set) => {
|
||||
return self.replace_rec_ptr(ctx, layout_interner, lambda_set.representation)
|
||||
}
|
||||
|
||||
// This line is the whole point of the function
|
||||
Layout::RecursivePointer => Layout::Union(ctx.recursive_union.unwrap()),
|
||||
}
|
||||
};
|
||||
layout_interner.insert(layout)
|
||||
}
|
||||
|
||||
fn union_tail_recursion_fields(
|
||||
&self,
|
||||
layout_interner: &STLayoutInterner<'a>,
|
||||
union: UnionLayout<'a>,
|
||||
) -> (bool, Vec<'a, Option<usize>>) {
|
||||
use UnionLayout::*;
|
||||
match union {
|
||||
NonRecursive(_) => (false, bumpalo::vec![in self.arena]),
|
||||
|
||||
Recursive(tags) => self.union_tail_recursion_fields_help(tags),
|
||||
Recursive(tags) => self.union_tail_recursion_fields_help(layout_interner, tags),
|
||||
|
||||
NonNullableUnwrapped(field_layouts) => {
|
||||
self.union_tail_recursion_fields_help(&[field_layouts])
|
||||
self.union_tail_recursion_fields_help(layout_interner, &[field_layouts])
|
||||
}
|
||||
|
||||
NullableWrapped {
|
||||
other_tags: tags, ..
|
||||
} => self.union_tail_recursion_fields_help(tags),
|
||||
} => self.union_tail_recursion_fields_help(layout_interner, tags),
|
||||
|
||||
NullableUnwrapped { other_fields, .. } => {
|
||||
self.union_tail_recursion_fields_help(&[other_fields])
|
||||
self.union_tail_recursion_fields_help(layout_interner, &[other_fields])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn union_tail_recursion_fields_help(
|
||||
&self,
|
||||
tags: &[&'a [Layout<'a>]],
|
||||
layout_interner: &STLayoutInterner<'a>,
|
||||
tags: &[&'a [InLayout<'a>]],
|
||||
) -> (bool, Vec<'a, Option<usize>>) {
|
||||
let mut can_use_tailrec = false;
|
||||
let mut tailrec_indices = Vec::with_capacity_in(tags.len(), self.arena);
|
||||
|
@ -537,7 +535,7 @@ impl<'a> CodeGenHelp<'a> {
|
|||
for fields in tags.iter() {
|
||||
let found_index = fields
|
||||
.iter()
|
||||
.position(|f| matches!(f, Layout::RecursivePointer));
|
||||
.position(|f| matches!(layout_interner.get(*f), Layout::RecursivePointer));
|
||||
tailrec_indices.push(found_index);
|
||||
can_use_tailrec |= found_index.is_some();
|
||||
}
|
||||
|
@ -548,7 +546,7 @@ impl<'a> CodeGenHelp<'a> {
|
|||
|
||||
fn let_lowlevel<'a>(
|
||||
arena: &'a Bump,
|
||||
result_layout: Layout<'a>,
|
||||
result_layout: InLayout<'a>,
|
||||
result: Symbol,
|
||||
op: LowLevel,
|
||||
arguments: &[Symbol],
|
||||
|
@ -568,8 +566,12 @@ fn let_lowlevel<'a>(
|
|||
)
|
||||
}
|
||||
|
||||
fn layout_needs_helper_proc(layout: &Layout, op: HelperOp) -> bool {
|
||||
match layout {
|
||||
fn layout_needs_helper_proc<'a>(
|
||||
layout_interner: &STLayoutInterner<'a>,
|
||||
layout: InLayout<'a>,
|
||||
op: HelperOp,
|
||||
) -> bool {
|
||||
match layout_interner.get(layout) {
|
||||
Layout::Builtin(Builtin::Int(_) | Builtin::Float(_) | Builtin::Bool | Builtin::Decimal) => {
|
||||
false
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#![allow(clippy::too_many_arguments)]
|
||||
|
||||
use bumpalo::collections::vec::Vec;
|
||||
use roc_builtins::bitcode::IntWidth;
|
||||
use roc_module::low_level::{LowLevel, LowLevel::*};
|
||||
use roc_module::symbol::{IdentIds, Symbol};
|
||||
use roc_target::PtrWidth;
|
||||
|
@ -17,19 +16,20 @@ use crate::layout::{
|
|||
|
||||
use super::{CodeGenHelp, Context, HelperOp};
|
||||
|
||||
const LAYOUT_BOOL: Layout = Layout::Builtin(Builtin::Bool);
|
||||
const LAYOUT_UNIT: Layout = Layout::UNIT;
|
||||
const LAYOUT_U32: Layout = Layout::Builtin(Builtin::Int(IntWidth::U32));
|
||||
const LAYOUT_BOOL: InLayout = Layout::BOOL;
|
||||
const LAYOUT_UNIT: InLayout = Layout::UNIT;
|
||||
const LAYOUT_U32: InLayout = Layout::U32;
|
||||
|
||||
// TODO: Replace usages with root.union_refcount
|
||||
const LAYOUT_PTR: Layout = Layout::RecursivePointer;
|
||||
// TODO(recursive-layouts): update once we have disjoint recursive pointers
|
||||
const LAYOUT_PTR: InLayout = Layout::RECURSIVE_PTR;
|
||||
|
||||
pub fn refcount_stmt<'a>(
|
||||
root: &mut CodeGenHelp<'a>,
|
||||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout: Layout<'a>,
|
||||
layout: InLayout<'a>,
|
||||
modify: &ModifyRc,
|
||||
following: &'a Stmt<'a>,
|
||||
) -> &'a Stmt<'a> {
|
||||
|
@ -77,7 +77,7 @@ pub fn refcount_stmt<'a>(
|
|||
}
|
||||
|
||||
ModifyRc::DecRef(structure) => {
|
||||
match layout {
|
||||
match layout_interner.get(layout) {
|
||||
// Str has no children, so we might as well do what we normally do and call the helper.
|
||||
Layout::Builtin(Builtin::Str) => {
|
||||
ctx.op = HelperOp::Dec;
|
||||
|
@ -128,12 +128,12 @@ pub fn refcount_generic<'a>(
|
|||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout: Layout<'a>,
|
||||
layout: InLayout<'a>,
|
||||
structure: Symbol,
|
||||
) -> Stmt<'a> {
|
||||
debug_assert!(is_rc_implemented_yet(layout_interner, &layout));
|
||||
debug_assert!(is_rc_implemented_yet(layout_interner, layout));
|
||||
|
||||
match layout {
|
||||
match layout_interner.get(layout) {
|
||||
Layout::Builtin(Builtin::Int(_) | Builtin::Float(_) | Builtin::Bool | Builtin::Decimal) => {
|
||||
// Generate a dummy function that immediately returns Unit
|
||||
// Some higher-order Zig builtins *always* call an RC function on List elements.
|
||||
|
@ -145,7 +145,7 @@ pub fn refcount_generic<'a>(
|
|||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
&layout,
|
||||
layout,
|
||||
elem_layout,
|
||||
structure,
|
||||
),
|
||||
|
@ -166,7 +166,7 @@ pub fn refcount_generic<'a>(
|
|||
structure,
|
||||
),
|
||||
Layout::LambdaSet(lambda_set) => {
|
||||
let runtime_layout = lambda_set.runtime_representation(layout_interner);
|
||||
let runtime_layout = lambda_set.representation;
|
||||
refcount_generic(
|
||||
root,
|
||||
ident_ids,
|
||||
|
@ -179,18 +179,15 @@ pub fn refcount_generic<'a>(
|
|||
Layout::RecursivePointer => unreachable!(
|
||||
"We should never call a refcounting helper on a RecursivePointer layout directly"
|
||||
),
|
||||
Layout::Boxed(inner_layout) => {
|
||||
let inner_layout = layout_interner.get(inner_layout);
|
||||
refcount_boxed(
|
||||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
&layout,
|
||||
&inner_layout,
|
||||
structure,
|
||||
)
|
||||
}
|
||||
Layout::Boxed(inner_layout) => refcount_boxed(
|
||||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
layout,
|
||||
inner_layout,
|
||||
structure,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -199,7 +196,7 @@ pub fn refcount_reset_proc_body<'a>(
|
|||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout: Layout<'a>,
|
||||
layout: InLayout<'a>,
|
||||
structure: Symbol,
|
||||
) -> Stmt<'a> {
|
||||
let rc_ptr = root.create_symbol(ident_ids, "rc_ptr");
|
||||
|
@ -208,7 +205,7 @@ pub fn refcount_reset_proc_body<'a>(
|
|||
let is_unique = root.create_symbol(ident_ids, "is_unique");
|
||||
let addr = root.create_symbol(ident_ids, "addr");
|
||||
|
||||
let union_layout = match layout {
|
||||
let union_layout = match layout_interner.get(layout) {
|
||||
Layout::Union(u) => u,
|
||||
_ => unimplemented!("Reset is only implemented for UnionLayout"),
|
||||
};
|
||||
|
@ -267,7 +264,10 @@ pub fn refcount_reset_proc_body<'a>(
|
|||
let alloc_addr_stmt = {
|
||||
let alignment = root.create_symbol(ident_ids, "alignment");
|
||||
let alignment_expr = Expr::Literal(Literal::Int(
|
||||
(layout.alignment_bytes(layout_interner, root.target_info) as i128).to_ne_bytes(),
|
||||
(layout_interner
|
||||
.get(layout)
|
||||
.alignment_bytes(layout_interner, root.target_info) as i128)
|
||||
.to_ne_bytes(),
|
||||
));
|
||||
let alloc_addr = root.create_symbol(ident_ids, "alloc_addr");
|
||||
let alloc_addr_expr = Expr::Call(Call {
|
||||
|
@ -420,41 +420,36 @@ pub fn refcount_reset_proc_body<'a>(
|
|||
// Check if refcounting is implemented yet. In the long term, this will be deleted.
|
||||
// In the short term, it helps us to skip refcounting and let it leak, so we can make
|
||||
// progress incrementally. Kept in sync with generate_procs using assertions.
|
||||
pub fn is_rc_implemented_yet<'a, I>(interner: &I, layout: &Layout<'a>) -> bool
|
||||
pub fn is_rc_implemented_yet<'a, I>(interner: &I, layout: InLayout<'a>) -> bool
|
||||
where
|
||||
I: LayoutInterner<'a>,
|
||||
{
|
||||
use UnionLayout::*;
|
||||
|
||||
match layout {
|
||||
Layout::Builtin(Builtin::List(elem_layout)) => {
|
||||
let elem_layout = interner.get(*elem_layout);
|
||||
is_rc_implemented_yet(interner, &elem_layout)
|
||||
}
|
||||
match interner.get(layout) {
|
||||
Layout::Builtin(Builtin::List(elem_layout)) => is_rc_implemented_yet(interner, elem_layout),
|
||||
Layout::Builtin(_) => true,
|
||||
Layout::Struct { field_layouts, .. } => field_layouts
|
||||
.iter()
|
||||
.all(|l| is_rc_implemented_yet(interner, l)),
|
||||
.all(|l| is_rc_implemented_yet(interner, *l)),
|
||||
Layout::Union(union_layout) => match union_layout {
|
||||
NonRecursive(tags) => tags
|
||||
.iter()
|
||||
.all(|fields| fields.iter().all(|l| is_rc_implemented_yet(interner, l))),
|
||||
.all(|fields| fields.iter().all(|l| is_rc_implemented_yet(interner, *l))),
|
||||
Recursive(tags) => tags
|
||||
.iter()
|
||||
.all(|fields| fields.iter().all(|l| is_rc_implemented_yet(interner, l))),
|
||||
.all(|fields| fields.iter().all(|l| is_rc_implemented_yet(interner, *l))),
|
||||
NonNullableUnwrapped(fields) => {
|
||||
fields.iter().all(|l| is_rc_implemented_yet(interner, l))
|
||||
fields.iter().all(|l| is_rc_implemented_yet(interner, *l))
|
||||
}
|
||||
NullableWrapped { other_tags, .. } => other_tags
|
||||
.iter()
|
||||
.all(|fields| fields.iter().all(|l| is_rc_implemented_yet(interner, l))),
|
||||
.all(|fields| fields.iter().all(|l| is_rc_implemented_yet(interner, *l))),
|
||||
NullableUnwrapped { other_fields, .. } => other_fields
|
||||
.iter()
|
||||
.all(|l| is_rc_implemented_yet(interner, l)),
|
||||
.all(|l| is_rc_implemented_yet(interner, *l)),
|
||||
},
|
||||
Layout::LambdaSet(lambda_set) => {
|
||||
is_rc_implemented_yet(interner, &lambda_set.runtime_representation(interner))
|
||||
}
|
||||
Layout::LambdaSet(lambda_set) => is_rc_implemented_yet(interner, lambda_set.representation),
|
||||
Layout::RecursivePointer => true,
|
||||
Layout::Boxed(_) => true,
|
||||
}
|
||||
|
@ -765,18 +760,16 @@ fn refcount_list<'a>(
|
|||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout: &Layout,
|
||||
layout: InLayout,
|
||||
elem_layout: InLayout<'a>,
|
||||
structure: Symbol,
|
||||
) -> Stmt<'a> {
|
||||
let layout_isize = root.layout_isize;
|
||||
let arena = root.arena;
|
||||
|
||||
let elem_layout = layout_interner.get(elem_layout);
|
||||
|
||||
// A "Box" layout (heap pointer to a single list element)
|
||||
let box_union_layout = UnionLayout::NonNullableUnwrapped(arena.alloc([elem_layout]));
|
||||
let box_layout = Layout::Union(box_union_layout);
|
||||
let box_layout = layout_interner.insert(Layout::Union(box_union_layout));
|
||||
|
||||
//
|
||||
// Check if the list is empty
|
||||
|
@ -816,7 +809,7 @@ fn refcount_list<'a>(
|
|||
//
|
||||
|
||||
let rc_ptr = root.create_symbol(ident_ids, "rc_ptr");
|
||||
let alignment = layout.alignment_bytes(layout_interner, root.target_info);
|
||||
let alignment = layout_interner.alignment_bytes(layout);
|
||||
|
||||
let ret_stmt = rc_return_stmt(root, ident_ids, ctx);
|
||||
let modify_list = modify_refcount(
|
||||
|
@ -837,22 +830,23 @@ fn refcount_list<'a>(
|
|||
arena.alloc(modify_list),
|
||||
);
|
||||
|
||||
let modify_elems_and_list = if elem_layout.is_refcounted() && !ctx.op.is_decref() {
|
||||
refcount_list_elems(
|
||||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
&elem_layout,
|
||||
LAYOUT_UNIT,
|
||||
box_union_layout,
|
||||
len,
|
||||
elements,
|
||||
get_rc_and_modify_list,
|
||||
)
|
||||
} else {
|
||||
get_rc_and_modify_list
|
||||
};
|
||||
let modify_elems_and_list =
|
||||
if layout_interner.get(elem_layout).is_refcounted() && !ctx.op.is_decref() {
|
||||
refcount_list_elems(
|
||||
root,
|
||||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
elem_layout,
|
||||
LAYOUT_UNIT,
|
||||
box_union_layout,
|
||||
len,
|
||||
elements,
|
||||
get_rc_and_modify_list,
|
||||
)
|
||||
} else {
|
||||
get_rc_and_modify_list
|
||||
};
|
||||
|
||||
//
|
||||
// Do nothing if the list is empty
|
||||
|
@ -893,8 +887,8 @@ fn refcount_list_elems<'a>(
|
|||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
elem_layout: &Layout<'a>,
|
||||
ret_layout: Layout<'a>,
|
||||
elem_layout: InLayout<'a>,
|
||||
ret_layout: InLayout<'a>,
|
||||
box_union_layout: UnionLayout<'a>,
|
||||
length: Symbol,
|
||||
elements: Symbol,
|
||||
|
@ -915,7 +909,7 @@ fn refcount_list_elems<'a>(
|
|||
// let size = literal int
|
||||
let elem_size = root.create_symbol(ident_ids, "elem_size");
|
||||
let elem_size_expr = Expr::Literal(Literal::Int(
|
||||
(elem_layout.stack_size(layout_interner, root.target_info) as i128).to_ne_bytes(),
|
||||
(layout_interner.stack_size(elem_layout) as i128).to_ne_bytes(),
|
||||
));
|
||||
let elem_size_stmt = |next| Stmt::Let(elem_size, elem_size_expr, layout_isize, next);
|
||||
|
||||
|
@ -955,7 +949,7 @@ fn refcount_list_elems<'a>(
|
|||
|
||||
// Cast integer to box pointer
|
||||
let box_ptr = root.create_symbol(ident_ids, "box");
|
||||
let box_layout = Layout::Union(box_union_layout);
|
||||
let box_layout = layout_interner.insert(Layout::Union(box_union_layout));
|
||||
let box_stmt = |next| let_lowlevel(arena, box_layout, box_ptr, PtrCast, &[addr], next);
|
||||
|
||||
// Dereference the box pointer to get the current element
|
||||
|
@ -966,7 +960,7 @@ fn refcount_list_elems<'a>(
|
|||
tag_id: 0,
|
||||
index: 0,
|
||||
};
|
||||
let elem_stmt = |next| Stmt::Let(elem, elem_expr, *elem_layout, next);
|
||||
let elem_stmt = |next| Stmt::Let(elem, elem_expr, elem_layout, next);
|
||||
|
||||
//
|
||||
// Modify element refcount
|
||||
|
@ -975,7 +969,7 @@ fn refcount_list_elems<'a>(
|
|||
let mod_elem_unit = root.create_symbol(ident_ids, "mod_elem_unit");
|
||||
let mod_elem_args = refcount_args(root, ctx, elem);
|
||||
let mod_elem_expr = root
|
||||
.call_specialized_op(ident_ids, ctx, layout_interner, *elem_layout, mod_elem_args)
|
||||
.call_specialized_op(ident_ids, ctx, layout_interner, elem_layout, mod_elem_args)
|
||||
.unwrap();
|
||||
let mod_elem_stmt = |next| Stmt::Let(mod_elem_unit, mod_elem_expr, LAYOUT_UNIT, next);
|
||||
|
||||
|
@ -1059,13 +1053,13 @@ fn refcount_struct<'a>(
|
|||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
field_layouts: &'a [Layout<'a>],
|
||||
field_layouts: &'a [InLayout<'a>],
|
||||
structure: Symbol,
|
||||
) -> Stmt<'a> {
|
||||
let mut stmt = rc_return_stmt(root, ident_ids, ctx);
|
||||
|
||||
for (i, field_layout) in field_layouts.iter().enumerate().rev() {
|
||||
if field_layout.contains_refcounted(layout_interner) {
|
||||
if layout_interner.contains_refcounted(*field_layout) {
|
||||
let field_val = root.create_symbol(ident_ids, &format!("field_val_{}", i));
|
||||
let field_val_expr = Expr::StructAtIndex {
|
||||
index: i as u64,
|
||||
|
@ -1121,7 +1115,7 @@ fn refcount_union<'a>(
|
|||
),
|
||||
|
||||
Recursive(tags) => {
|
||||
let (is_tailrec, tail_idx) = root.union_tail_recursion_fields(union);
|
||||
let (is_tailrec, tail_idx) = root.union_tail_recursion_fields(layout_interner, union);
|
||||
if is_tailrec && !ctx.op.is_decref() {
|
||||
refcount_union_tailrec(
|
||||
root,
|
||||
|
@ -1171,7 +1165,7 @@ fn refcount_union<'a>(
|
|||
nullable_id,
|
||||
} => {
|
||||
let null_id = Some(nullable_id);
|
||||
let (is_tailrec, tail_idx) = root.union_tail_recursion_fields(union);
|
||||
let (is_tailrec, tail_idx) = root.union_tail_recursion_fields(layout_interner, union);
|
||||
if is_tailrec && !ctx.op.is_decref() {
|
||||
refcount_union_tailrec(
|
||||
root,
|
||||
|
@ -1204,7 +1198,7 @@ fn refcount_union<'a>(
|
|||
} => {
|
||||
let null_id = Some(nullable_id as TagIdIntType);
|
||||
let tags = root.arena.alloc([other_fields]);
|
||||
let (is_tailrec, tail_idx) = root.union_tail_recursion_fields(union);
|
||||
let (is_tailrec, tail_idx) = root.union_tail_recursion_fields(layout_interner, union);
|
||||
if is_tailrec && !ctx.op.is_decref() {
|
||||
refcount_union_tailrec(
|
||||
root,
|
||||
|
@ -1243,7 +1237,7 @@ fn refcount_union_nonrec<'a>(
|
|||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
union_layout: UnionLayout<'a>,
|
||||
tag_layouts: &'a [&'a [Layout<'a>]],
|
||||
tag_layouts: &'a [&'a [InLayout<'a>]],
|
||||
structure: Symbol,
|
||||
) -> Stmt<'a> {
|
||||
let tag_id_layout = union_layout.tag_id_layout();
|
||||
|
@ -1289,11 +1283,11 @@ fn refcount_union_contents<'a>(
|
|||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
union_layout: UnionLayout<'a>,
|
||||
tag_layouts: &'a [&'a [Layout<'a>]],
|
||||
tag_layouts: &'a [&'a [InLayout<'a>]],
|
||||
null_id: Option<TagIdIntType>,
|
||||
structure: Symbol,
|
||||
tag_id_sym: Symbol,
|
||||
tag_id_layout: Layout<'a>,
|
||||
tag_id_layout: InLayout<'a>,
|
||||
next_stmt: Stmt<'a>,
|
||||
) -> Stmt<'a> {
|
||||
let jp_contents_modified = JoinPointId(root.create_symbol(ident_ids, "jp_contents_modified"));
|
||||
|
@ -1358,7 +1352,7 @@ fn refcount_union_rec<'a>(
|
|||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
union_layout: UnionLayout<'a>,
|
||||
tag_layouts: &'a [&'a [Layout<'a>]],
|
||||
tag_layouts: &'a [&'a [InLayout<'a>]],
|
||||
null_id: Option<TagIdIntType>,
|
||||
structure: Symbol,
|
||||
) -> Stmt<'a> {
|
||||
|
@ -1437,7 +1431,7 @@ fn refcount_union_tailrec<'a>(
|
|||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
union_layout: UnionLayout<'a>,
|
||||
tag_layouts: &'a [&'a [Layout<'a>]],
|
||||
tag_layouts: &'a [&'a [InLayout<'a>]],
|
||||
null_id: Option<TagIdIntType>,
|
||||
tailrec_indices: Vec<'a, Option<usize>>,
|
||||
initial_structure: Symbol,
|
||||
|
@ -1445,7 +1439,7 @@ fn refcount_union_tailrec<'a>(
|
|||
let tailrec_loop = JoinPointId(root.create_symbol(ident_ids, "tailrec_loop"));
|
||||
let current = root.create_symbol(ident_ids, "current");
|
||||
let next_ptr = root.create_symbol(ident_ids, "next_ptr");
|
||||
let layout = Layout::Union(union_layout);
|
||||
let layout = layout_interner.insert(Layout::Union(union_layout));
|
||||
|
||||
let tag_id_layout = union_layout.tag_id_layout();
|
||||
|
||||
|
@ -1490,7 +1484,7 @@ fn refcount_union_tailrec<'a>(
|
|||
)
|
||||
};
|
||||
|
||||
let alignment = layout.alignment_bytes(layout_interner, root.target_info);
|
||||
let alignment = layout_interner.alignment_bytes(layout);
|
||||
let modify_structure_stmt = modify_refcount(
|
||||
root,
|
||||
ident_ids,
|
||||
|
@ -1621,10 +1615,11 @@ fn refcount_union_tailrec<'a>(
|
|||
));
|
||||
|
||||
let loop_init = Stmt::Jump(tailrec_loop, root.arena.alloc([initial_structure]));
|
||||
let union_layout = layout_interner.insert(Layout::Union(union_layout));
|
||||
let loop_param = Param {
|
||||
symbol: current,
|
||||
ownership: Ownership::Borrowed,
|
||||
layout: Layout::Union(union_layout),
|
||||
layout: union_layout,
|
||||
};
|
||||
|
||||
Stmt::Join {
|
||||
|
@ -1641,7 +1636,7 @@ fn refcount_tag_fields<'a>(
|
|||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
union_layout: UnionLayout<'a>,
|
||||
field_layouts: &'a [Layout<'a>],
|
||||
field_layouts: &'a [InLayout<'a>],
|
||||
structure: Symbol,
|
||||
tag_id: TagIdIntType,
|
||||
following: Stmt<'a>,
|
||||
|
@ -1649,7 +1644,7 @@ fn refcount_tag_fields<'a>(
|
|||
let mut stmt = following;
|
||||
|
||||
for (i, field_layout) in field_layouts.iter().enumerate().rev() {
|
||||
if field_layout.contains_refcounted(layout_interner) {
|
||||
if layout_interner.contains_refcounted(*field_layout) {
|
||||
let field_val = root.create_symbol(ident_ids, &format!("field_{}_{}", tag_id, i));
|
||||
let field_val_expr = Expr::UnionAtIndex {
|
||||
union_layout,
|
||||
|
@ -1684,8 +1679,8 @@ fn refcount_boxed<'a>(
|
|||
ident_ids: &mut IdentIds,
|
||||
ctx: &mut Context<'a>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout: &Layout<'a>,
|
||||
inner_layout: &Layout<'a>,
|
||||
layout: InLayout<'a>,
|
||||
inner_layout: InLayout<'a>,
|
||||
outer: Symbol,
|
||||
) -> Stmt<'a> {
|
||||
let arena = root.arena;
|
||||
|
@ -1697,7 +1692,7 @@ fn refcount_boxed<'a>(
|
|||
//
|
||||
|
||||
let rc_ptr = root.create_symbol(ident_ids, "rc_ptr");
|
||||
let alignment = layout.alignment_bytes(layout_interner, root.target_info);
|
||||
let alignment = layout_interner.alignment_bytes(layout);
|
||||
let ret_stmt = rc_return_stmt(root, ident_ids, ctx);
|
||||
let modify_outer = modify_refcount(
|
||||
root,
|
||||
|
@ -1717,7 +1712,7 @@ fn refcount_boxed<'a>(
|
|||
arena.alloc(modify_outer),
|
||||
);
|
||||
|
||||
if inner_layout.is_refcounted() && !ctx.op.is_decref() {
|
||||
if layout_interner.is_refcounted(inner_layout) && !ctx.op.is_decref() {
|
||||
let inner = root.create_symbol(ident_ids, "inner");
|
||||
let inner_expr = Expr::ExprUnbox { symbol: outer };
|
||||
|
||||
|
@ -1728,7 +1723,7 @@ fn refcount_boxed<'a>(
|
|||
ident_ids,
|
||||
ctx,
|
||||
layout_interner,
|
||||
*inner_layout,
|
||||
inner_layout,
|
||||
mod_inner_args,
|
||||
)
|
||||
.unwrap();
|
||||
|
@ -1736,7 +1731,7 @@ fn refcount_boxed<'a>(
|
|||
Stmt::Let(
|
||||
inner,
|
||||
inner_expr,
|
||||
*inner_layout,
|
||||
inner_layout,
|
||||
arena.alloc(Stmt::Let(
|
||||
mod_inner_unit,
|
||||
mod_inner_expr,
|
||||
|
|
|
@ -10,7 +10,8 @@ use crate::{
|
|||
ModifyRc, Param, Proc, ProcLayout, Stmt,
|
||||
},
|
||||
layout::{
|
||||
Builtin, LambdaSet, Layout, LayoutInterner, STLayoutInterner, TagIdIntType, UnionLayout,
|
||||
Builtin, InLayout, LambdaSet, Layout, LayoutInterner, STLayoutInterner, TagIdIntType,
|
||||
UnionLayout,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -38,18 +39,18 @@ pub enum ProblemKind<'a> {
|
|||
},
|
||||
SymbolUseMismatch {
|
||||
symbol: Symbol,
|
||||
def_layout: Layout<'a>,
|
||||
def_layout: InLayout<'a>,
|
||||
def_line: usize,
|
||||
use_layout: Layout<'a>,
|
||||
use_layout: InLayout<'a>,
|
||||
use_kind: UseKind,
|
||||
},
|
||||
SymbolDefMismatch {
|
||||
symbol: Symbol,
|
||||
def_layout: Layout<'a>,
|
||||
expr_layout: Layout<'a>,
|
||||
def_layout: InLayout<'a>,
|
||||
expr_layout: InLayout<'a>,
|
||||
},
|
||||
BadSwitchConditionLayout {
|
||||
found_layout: Layout<'a>,
|
||||
found_layout: InLayout<'a>,
|
||||
},
|
||||
DuplicateSwitchBranch {},
|
||||
RedefinedJoinPoint {
|
||||
|
@ -158,7 +159,7 @@ pub fn check_procs<'a>(
|
|||
Problems(problems)
|
||||
}
|
||||
|
||||
type VEnv<'a> = VecMap<Symbol, (usize, Layout<'a>)>;
|
||||
type VEnv<'a> = VecMap<Symbol, (usize, InLayout<'a>)>;
|
||||
type JoinPoints<'a> = VecMap<JoinPointId, (usize, &'a [Param<'a>])>;
|
||||
type CallSpecIds = VecMap<CallSpecId, usize>;
|
||||
struct Ctx<'a, 'r> {
|
||||
|
@ -169,7 +170,7 @@ struct Ctx<'a, 'r> {
|
|||
proc_layout: ProcLayout<'a>,
|
||||
procs: &'r Procs<'a>,
|
||||
call_spec_ids: CallSpecIds,
|
||||
ret_layout: Layout<'a>,
|
||||
ret_layout: InLayout<'a>,
|
||||
venv: VEnv<'a>,
|
||||
joinpoints: JoinPoints<'a>,
|
||||
line: usize,
|
||||
|
@ -192,19 +193,19 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
|||
r
|
||||
}
|
||||
|
||||
fn resolve(&mut self, mut layout: Layout<'a>) -> Layout<'a> {
|
||||
fn resolve(&mut self, mut layout: InLayout<'a>) -> InLayout<'a> {
|
||||
// Note that we are more aggressive than the usual `runtime_representation`
|
||||
// here because we need strict equality, and so cannot unwrap lambda sets
|
||||
// lazily.
|
||||
loop {
|
||||
match layout {
|
||||
Layout::LambdaSet(ls) => layout = ls.runtime_representation(self.interner),
|
||||
layout => return layout,
|
||||
match self.interner.get(layout) {
|
||||
Layout::LambdaSet(ls) => layout = ls.representation,
|
||||
_ => return layout,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn insert(&mut self, symbol: Symbol, layout: Layout<'a>) {
|
||||
fn insert(&mut self, symbol: Symbol, layout: InLayout<'a>) {
|
||||
if let Some((old_line, _)) = self.venv.insert(symbol, (self.line, layout)) {
|
||||
self.problem(ProblemKind::RedefinedSymbol { symbol, old_line })
|
||||
}
|
||||
|
@ -219,7 +220,7 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
|||
fn with_sym_layout<T>(
|
||||
&mut self,
|
||||
symbol: Symbol,
|
||||
f: impl FnOnce(&mut Self, usize, Layout<'a>) -> Option<T>,
|
||||
f: impl FnOnce(&mut Self, usize, InLayout<'a>) -> Option<T>,
|
||||
) -> Option<T> {
|
||||
if let Some(&(def_line, layout)) = self.venv.get(&symbol) {
|
||||
f(self, def_line, layout)
|
||||
|
@ -229,7 +230,12 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_sym_layout(&mut self, symbol: Symbol, expected_layout: Layout<'a>, use_kind: UseKind) {
|
||||
fn check_sym_layout(
|
||||
&mut self,
|
||||
symbol: Symbol,
|
||||
expected_layout: InLayout<'a>,
|
||||
use_kind: UseKind,
|
||||
) {
|
||||
if let Some(&(def_line, layout)) = self.venv.get(&symbol) {
|
||||
if self.resolve(layout) != self.resolve(expected_layout) {
|
||||
self.problem(ProblemKind::SymbolUseMismatch {
|
||||
|
@ -278,7 +284,8 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
|||
ret_layout: _,
|
||||
} => {
|
||||
self.check_sym_layout(*cond_symbol, *cond_layout, UseKind::SwitchCond);
|
||||
match self.resolve(*cond_layout) {
|
||||
let layout = self.resolve(*cond_layout);
|
||||
match self.interner.get(layout) {
|
||||
Layout::Builtin(Builtin::Int(_)) => {}
|
||||
Layout::Builtin(Builtin::Bool) => {}
|
||||
_ => self.problem(ProblemKind::BadSwitchConditionLayout {
|
||||
|
@ -320,11 +327,7 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
|||
variables: _,
|
||||
remainder,
|
||||
} => {
|
||||
self.check_sym_layout(
|
||||
condition,
|
||||
Layout::Builtin(Builtin::Bool),
|
||||
UseKind::ExpectCond,
|
||||
);
|
||||
self.check_sym_layout(condition, Layout::BOOL, UseKind::ExpectCond);
|
||||
for sym in lookups.iter() {
|
||||
self.check_sym_exists(*sym);
|
||||
}
|
||||
|
@ -374,13 +377,11 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
|||
self.problem(ProblemKind::NoJoinPoint { id });
|
||||
}
|
||||
}
|
||||
&Stmt::Crash(sym, _) => {
|
||||
self.check_sym_layout(sym, Layout::Builtin(Builtin::Str), UseKind::CrashArg)
|
||||
}
|
||||
&Stmt::Crash(sym, _) => self.check_sym_layout(sym, Layout::STR, UseKind::CrashArg),
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expr(&mut self, e: &Expr<'a>) -> Option<Layout<'a>> {
|
||||
fn check_expr(&mut self, e: &Expr<'a>) -> Option<InLayout<'a>> {
|
||||
match e {
|
||||
Expr::Literal(_) => None,
|
||||
Expr::Call(call) => self.check_call(call),
|
||||
|
@ -390,7 +391,7 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
|||
arguments,
|
||||
} => {
|
||||
self.check_tag_expr(tag_layout, tag_id, arguments);
|
||||
Some(Layout::Union(tag_layout))
|
||||
Some(self.interner.insert(Layout::Union(tag_layout)))
|
||||
}
|
||||
Expr::Struct(syms) => {
|
||||
for sym in syms.iter() {
|
||||
|
@ -424,26 +425,29 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
|||
}
|
||||
}
|
||||
}
|
||||
let elem_layout = self.interner.insert(*elem_layout);
|
||||
Some(Layout::Builtin(Builtin::List(elem_layout)))
|
||||
Some(
|
||||
self.interner
|
||||
.insert(Layout::Builtin(Builtin::List(*elem_layout))),
|
||||
)
|
||||
}
|
||||
Expr::EmptyArray => {
|
||||
// TODO don't know what the element layout is
|
||||
None
|
||||
}
|
||||
&Expr::ExprBox { symbol } => self.with_sym_layout(symbol, |ctx, _def_line, layout| {
|
||||
let inner = ctx.interner.insert(layout);
|
||||
Some(Layout::Boxed(inner))
|
||||
let inner = layout;
|
||||
Some(ctx.interner.insert(Layout::Boxed(inner)))
|
||||
}),
|
||||
&Expr::ExprUnbox { symbol } => {
|
||||
self.with_sym_layout(symbol, |ctx, def_line, layout| match ctx.resolve(layout) {
|
||||
Layout::Boxed(inner) => Some(ctx.interner.get(inner)),
|
||||
&Expr::ExprUnbox { symbol } => self.with_sym_layout(symbol, |ctx, def_line, layout| {
|
||||
let layout = ctx.resolve(layout);
|
||||
match ctx.interner.get(layout) {
|
||||
Layout::Boxed(inner) => Some(inner),
|
||||
_ => {
|
||||
ctx.problem(ProblemKind::UnboxNotABox { symbol, def_line });
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}),
|
||||
&Expr::Reuse {
|
||||
symbol,
|
||||
update_tag_id: _,
|
||||
|
@ -452,9 +456,10 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
|||
tag_id: _,
|
||||
arguments: _,
|
||||
} => {
|
||||
self.check_sym_layout(symbol, Layout::Union(tag_layout), UseKind::TagReuse);
|
||||
let union = self.interner.insert(Layout::Union(tag_layout));
|
||||
self.check_sym_layout(symbol, union, UseKind::TagReuse);
|
||||
// TODO also check update arguments
|
||||
Some(Layout::Union(tag_layout))
|
||||
Some(union)
|
||||
}
|
||||
&Expr::Reset {
|
||||
symbol,
|
||||
|
@ -467,9 +472,10 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_struct_at_index(&mut self, structure: Symbol, index: u64) -> Option<Layout<'a>> {
|
||||
fn check_struct_at_index(&mut self, structure: Symbol, index: u64) -> Option<InLayout<'a>> {
|
||||
self.with_sym_layout(structure, |ctx, def_line, layout| {
|
||||
match ctx.resolve(layout) {
|
||||
let layout = ctx.resolve(layout);
|
||||
match ctx.interner.get(layout) {
|
||||
Layout::Struct { field_layouts, .. } => {
|
||||
if index as usize >= field_layouts.len() {
|
||||
ctx.problem(ProblemKind::StructIndexOOB {
|
||||
|
@ -500,9 +506,10 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
|||
union_layout: UnionLayout<'a>,
|
||||
tag_id: u16,
|
||||
index: u64,
|
||||
) -> Option<Layout<'a>> {
|
||||
) -> Option<InLayout<'a>> {
|
||||
let union = self.interner.insert(Layout::Union(union_layout));
|
||||
self.with_sym_layout(structure, |ctx, def_line, _layout| {
|
||||
ctx.check_sym_layout(structure, Layout::Union(union_layout), UseKind::TagExpr);
|
||||
ctx.check_sym_layout(structure, union, UseKind::TagExpr);
|
||||
|
||||
match get_tag_id_payloads(union_layout, tag_id) {
|
||||
TagPayloads::IdNotInUnion => {
|
||||
|
@ -537,7 +544,7 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
|||
})
|
||||
}
|
||||
|
||||
fn check_call(&mut self, call: &Call<'a>) -> Option<Layout<'a>> {
|
||||
fn check_call(&mut self, call: &Call<'a>) -> Option<InLayout<'a>> {
|
||||
let Call {
|
||||
call_type,
|
||||
arguments,
|
||||
|
@ -552,7 +559,7 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
|||
} => {
|
||||
let proc_layout = ProcLayout {
|
||||
arguments: arg_layouts,
|
||||
result: **ret_layout,
|
||||
result: *ret_layout,
|
||||
niche: name.niche(),
|
||||
};
|
||||
if !self.procs.contains_key(&(name.name(), proc_layout)) {
|
||||
|
@ -576,7 +583,7 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
|||
{
|
||||
self.problem(ProblemKind::DuplicateCallSpecId { old_call_line });
|
||||
}
|
||||
Some(**ret_layout)
|
||||
Some(*ret_layout)
|
||||
}
|
||||
CallType::HigherOrder(HigherOrderLowLevel {
|
||||
op: _,
|
||||
|
@ -590,7 +597,7 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
|||
CallType::Foreign {
|
||||
foreign_symbol: _,
|
||||
ret_layout,
|
||||
} => Some(**ret_layout),
|
||||
} => Some(*ret_layout),
|
||||
CallType::LowLevel {
|
||||
op: _,
|
||||
update_mode: _,
|
||||
|
@ -639,9 +646,9 @@ impl<'a, 'r> Ctx<'a, 'r> {
|
|||
fn resolve_recursive_layout<'a>(
|
||||
arena: &'a Bump,
|
||||
interner: &mut STLayoutInterner<'a>,
|
||||
layout: Layout<'a>,
|
||||
layout: InLayout<'a>,
|
||||
when_recursive: UnionLayout<'a>,
|
||||
) -> Layout<'a> {
|
||||
) -> InLayout<'a> {
|
||||
macro_rules! go {
|
||||
($lay:expr) => {
|
||||
resolve_recursive_layout(arena, interner, $lay, when_recursive)
|
||||
|
@ -649,7 +656,7 @@ fn resolve_recursive_layout<'a>(
|
|||
}
|
||||
|
||||
// TODO check if recursive pointer not in recursive union
|
||||
match layout {
|
||||
let layout = match interner.get(layout) {
|
||||
Layout::RecursivePointer => Layout::Union(when_recursive),
|
||||
Layout::Union(union_layout) => match union_layout {
|
||||
UnionLayout::NonRecursive(payloads) => {
|
||||
|
@ -667,12 +674,12 @@ fn resolve_recursive_layout<'a>(
|
|||
// This is the recursive layout.
|
||||
// TODO will need fixing to be modified once we support multiple
|
||||
// recursive pointers in one structure.
|
||||
layout
|
||||
return layout;
|
||||
}
|
||||
},
|
||||
Layout::Boxed(inner) => {
|
||||
let inner = go!(interner.get(inner));
|
||||
Layout::Boxed(interner.insert(inner))
|
||||
let inner = go!(inner);
|
||||
Layout::Boxed(inner)
|
||||
}
|
||||
Layout::Struct {
|
||||
field_order_hash,
|
||||
|
@ -689,16 +696,14 @@ fn resolve_recursive_layout<'a>(
|
|||
}
|
||||
Layout::Builtin(builtin) => match builtin {
|
||||
Builtin::List(inner) => {
|
||||
let inner =
|
||||
resolve_recursive_layout(arena, interner, interner.get(inner), when_recursive);
|
||||
let inner = interner.insert(inner);
|
||||
let inner = resolve_recursive_layout(arena, interner, inner, when_recursive);
|
||||
Layout::Builtin(Builtin::List(inner))
|
||||
}
|
||||
Builtin::Int(_)
|
||||
| Builtin::Float(_)
|
||||
| Builtin::Bool
|
||||
| Builtin::Decimal
|
||||
| Builtin::Str => layout,
|
||||
| Builtin::Str => return layout,
|
||||
},
|
||||
Layout::LambdaSet(LambdaSet {
|
||||
set,
|
||||
|
@ -706,10 +711,7 @@ fn resolve_recursive_layout<'a>(
|
|||
full_layout,
|
||||
}) => {
|
||||
let set = set.iter().map(|(symbol, captures)| {
|
||||
let captures = captures.iter().map(|lay_in| {
|
||||
let new_lay = go!(interner.get(*lay_in));
|
||||
interner.insert(new_lay)
|
||||
});
|
||||
let captures = captures.iter().map(|lay_in| go!(*lay_in));
|
||||
let captures = &*arena.alloc_slice_fill_iter(captures);
|
||||
(*symbol, captures)
|
||||
});
|
||||
|
@ -720,12 +722,14 @@ fn resolve_recursive_layout<'a>(
|
|||
full_layout,
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
interner.insert(layout)
|
||||
}
|
||||
|
||||
enum TagPayloads<'a> {
|
||||
IdNotInUnion,
|
||||
Payloads(&'a [Layout<'a>]),
|
||||
Payloads(&'a [InLayout<'a>]),
|
||||
}
|
||||
|
||||
fn get_tag_id_payloads(union_layout: UnionLayout, tag_id: TagIdIntType) -> TagPayloads {
|
||||
|
|
|
@ -157,7 +157,7 @@ where
|
|||
f.concat([
|
||||
format_symbol(f, interns, symbol),
|
||||
f.reflow(" defined here with layout "),
|
||||
def_layout.to_doc(f, interner, Parens::NotNeeded),
|
||||
interner.to_doc(def_layout, f, Parens::NotNeeded),
|
||||
]),
|
||||
)];
|
||||
f.concat([
|
||||
|
@ -165,7 +165,7 @@ where
|
|||
f.reflow(" used as a "),
|
||||
f.reflow(format_use_kind(use_kind)),
|
||||
f.reflow(" here with layout "),
|
||||
use_layout.to_doc(f, interner, Parens::NotNeeded),
|
||||
interner.to_doc(use_layout, f, Parens::NotNeeded),
|
||||
])
|
||||
}
|
||||
ProblemKind::SymbolDefMismatch {
|
||||
|
@ -178,9 +178,9 @@ where
|
|||
f.concat([
|
||||
format_symbol(f, interns, symbol),
|
||||
f.reflow(" is defined as "),
|
||||
def_layout.to_doc(f, interner, Parens::NotNeeded),
|
||||
interner.to_doc(def_layout, f, Parens::NotNeeded),
|
||||
f.reflow(" but its initializer is "),
|
||||
expr_layout.to_doc(f, interner, Parens::NotNeeded),
|
||||
interner.to_doc(expr_layout, f, Parens::NotNeeded),
|
||||
])
|
||||
}
|
||||
ProblemKind::BadSwitchConditionLayout { found_layout } => {
|
||||
|
@ -188,7 +188,7 @@ where
|
|||
docs_before = vec![];
|
||||
f.concat([
|
||||
f.reflow("This switch condition is a "),
|
||||
found_layout.to_doc(f, interner, Parens::NotNeeded),
|
||||
interner.to_doc(found_layout, f, Parens::NotNeeded),
|
||||
])
|
||||
}
|
||||
ProblemKind::DuplicateSwitchBranch {} => {
|
||||
|
@ -469,13 +469,13 @@ where
|
|||
let args = f.intersperse(
|
||||
arguments
|
||||
.iter()
|
||||
.map(|a| a.to_doc(f, interner, Parens::InFunction)),
|
||||
.map(|a| interner.to_doc(*a, f, Parens::InFunction)),
|
||||
f.reflow(", "),
|
||||
);
|
||||
let fun = f.concat([
|
||||
f.concat([f.reflow("("), args, f.reflow(")")]),
|
||||
f.reflow(" -> "),
|
||||
result.to_doc(f, interner, Parens::NotNeeded),
|
||||
interner.to_doc(result, f, Parens::NotNeeded),
|
||||
]);
|
||||
let niche = (f.text("("))
|
||||
.append(captures_niche.to_doc(f, interner))
|
||||
|
|
|
@ -4,7 +4,8 @@ use crate::ir::{
|
|||
ListIndex, Literal, Param, Pattern, Procs, Stmt,
|
||||
};
|
||||
use crate::layout::{
|
||||
Builtin, Layout, LayoutCache, LayoutInterner, TLLayoutInterner, TagIdIntType, UnionLayout,
|
||||
Builtin, InLayout, Layout, LayoutCache, LayoutInterner, TLLayoutInterner, TagIdIntType,
|
||||
UnionLayout,
|
||||
};
|
||||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||
use roc_collections::all::{MutMap, MutSet};
|
||||
|
@ -23,7 +24,10 @@ const RECORD_TAG_NAME: &str = "#Record";
|
|||
/// some normal branches and gives out a decision tree that has "labels" at all
|
||||
/// the leafs and a dictionary that maps these "labels" to the code that should
|
||||
/// run.
|
||||
fn compile<'a>(raw_branches: Vec<(Guard<'a>, Pattern<'a>, u64)>) -> DecisionTree<'a> {
|
||||
fn compile<'a>(
|
||||
interner: &TLLayoutInterner<'a>,
|
||||
raw_branches: Vec<(Guard<'a>, Pattern<'a>, u64)>,
|
||||
) -> DecisionTree<'a> {
|
||||
let formatted = raw_branches
|
||||
.into_iter()
|
||||
.map(|(guard, pattern, index)| Branch {
|
||||
|
@ -33,7 +37,7 @@ fn compile<'a>(raw_branches: Vec<(Guard<'a>, Pattern<'a>, u64)>) -> DecisionTree
|
|||
})
|
||||
.collect();
|
||||
|
||||
to_decision_tree(formatted)
|
||||
to_decision_tree(interner, formatted)
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
|
@ -96,7 +100,7 @@ enum Test<'a> {
|
|||
tag_id: TagIdIntType,
|
||||
ctor_name: CtorName,
|
||||
union: roc_exhaustive::Union,
|
||||
arguments: Vec<(Pattern<'a>, Layout<'a>)>,
|
||||
arguments: Vec<(Pattern<'a>, InLayout<'a>)>,
|
||||
},
|
||||
IsInt([u8; 16], IntWidth),
|
||||
IsFloat(u64, FloatWidth),
|
||||
|
@ -207,7 +211,10 @@ struct Branch<'a> {
|
|||
patterns: Vec<(Vec<PathInstruction>, Pattern<'a>)>,
|
||||
}
|
||||
|
||||
fn to_decision_tree(raw_branches: Vec<Branch>) -> DecisionTree {
|
||||
fn to_decision_tree<'a>(
|
||||
interner: &TLLayoutInterner<'a>,
|
||||
raw_branches: Vec<Branch<'a>>,
|
||||
) -> DecisionTree<'a> {
|
||||
let branches: Vec<_> = raw_branches.into_iter().map(flatten_patterns).collect();
|
||||
|
||||
debug_assert!(!branches.is_empty());
|
||||
|
@ -239,7 +246,7 @@ fn to_decision_tree(raw_branches: Vec<Branch>) -> DecisionTree {
|
|||
let default = if branches.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(Box::new(to_decision_tree(branches)))
|
||||
Some(Box::new(to_decision_tree(interner, branches)))
|
||||
};
|
||||
|
||||
DecisionTree::Decision {
|
||||
|
@ -256,7 +263,7 @@ fn to_decision_tree(raw_branches: Vec<Branch>) -> DecisionTree {
|
|||
let path = pick_path(&branches).clone();
|
||||
|
||||
let bs = branches.clone();
|
||||
let (edges, fallback) = gather_edges(branches, &path);
|
||||
let (edges, fallback) = gather_edges(interner, branches, &path);
|
||||
|
||||
let mut decision_edges: Vec<_> = edges
|
||||
.into_iter()
|
||||
|
@ -264,7 +271,7 @@ fn to_decision_tree(raw_branches: Vec<Branch>) -> DecisionTree {
|
|||
if bs == branches {
|
||||
panic!();
|
||||
} else {
|
||||
(test, to_decision_tree(branches))
|
||||
(test, to_decision_tree(interner, branches))
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
@ -280,12 +287,12 @@ fn to_decision_tree(raw_branches: Vec<Branch>) -> DecisionTree {
|
|||
([], _) => {
|
||||
// should be guaranteed by the patterns
|
||||
debug_assert!(!fallback.is_empty());
|
||||
to_decision_tree(fallback)
|
||||
to_decision_tree(interner, fallback)
|
||||
}
|
||||
(_, _) => break_out_guard(
|
||||
path,
|
||||
decision_edges,
|
||||
Some(Box::new(to_decision_tree(fallback))),
|
||||
Some(Box::new(to_decision_tree(interner, fallback))),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
@ -458,6 +465,7 @@ fn check_for_match(branches: &[Branch]) -> Match {
|
|||
|
||||
// my understanding: branches that we could jump to based on the pattern at the current path
|
||||
fn gather_edges<'a>(
|
||||
interner: &TLLayoutInterner<'a>,
|
||||
branches: Vec<Branch<'a>>,
|
||||
path: &[PathInstruction],
|
||||
) -> (Vec<(GuardedTest<'a>, Vec<Branch<'a>>)>, Vec<Branch<'a>>) {
|
||||
|
@ -467,7 +475,7 @@ fn gather_edges<'a>(
|
|||
|
||||
let all_edges = relevant_tests
|
||||
.into_iter()
|
||||
.map(|t| edges_for(path, &branches, t))
|
||||
.map(|t| edges_for(interner, path, &branches, t))
|
||||
.collect();
|
||||
|
||||
let fallbacks = if check {
|
||||
|
@ -661,6 +669,7 @@ fn test_at_path<'a>(
|
|||
|
||||
// understanding: if the test is successful, where could we go?
|
||||
fn edges_for<'a>(
|
||||
interner: &TLLayoutInterner<'a>,
|
||||
path: &[PathInstruction],
|
||||
branches: &[Branch<'a>],
|
||||
test: GuardedTest<'a>,
|
||||
|
@ -682,13 +691,14 @@ fn edges_for<'a>(
|
|||
};
|
||||
|
||||
for branch in it {
|
||||
new_branches.extend(to_relevant_branch(&test, path, branch));
|
||||
new_branches.extend(to_relevant_branch(interner, &test, path, branch));
|
||||
}
|
||||
|
||||
(test, new_branches)
|
||||
}
|
||||
|
||||
fn to_relevant_branch<'a>(
|
||||
interner: &TLLayoutInterner<'a>,
|
||||
guarded_test: &GuardedTest<'a>,
|
||||
path: &[PathInstruction],
|
||||
branch: &Branch<'a>,
|
||||
|
@ -712,13 +722,14 @@ fn to_relevant_branch<'a>(
|
|||
Some(branch.clone())
|
||||
}
|
||||
GuardedTest::TestNotGuarded { test } => {
|
||||
to_relevant_branch_help(test, path, start, end, branch, pattern)
|
||||
to_relevant_branch_help(interner, test, path, start, end, branch, pattern)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn to_relevant_branch_help<'a>(
|
||||
interner: &TLLayoutInterner<'a>,
|
||||
test: &Test<'a>,
|
||||
path: &[PathInstruction],
|
||||
mut start: Vec<(Vec<PathInstruction>, Pattern<'a>)>,
|
||||
|
@ -903,11 +914,15 @@ fn to_relevant_branch_help<'a>(
|
|||
|
||||
// the test matches the constructor of this pattern
|
||||
match layout {
|
||||
UnionLayout::NonRecursive(
|
||||
[[Layout::Struct {
|
||||
field_layouts: [_], ..
|
||||
}]],
|
||||
) => {
|
||||
UnionLayout::NonRecursive([[arg]])
|
||||
if matches!(
|
||||
interner.get(*arg),
|
||||
Layout::Struct {
|
||||
field_layouts: [_],
|
||||
..
|
||||
}
|
||||
) =>
|
||||
{
|
||||
// a one-element record equivalent
|
||||
// Theory: Unbox doesn't have any value for us
|
||||
debug_assert_eq!(arguments.len(), 1);
|
||||
|
@ -1274,15 +1289,15 @@ enum Choice<'a> {
|
|||
Jump(Label),
|
||||
}
|
||||
|
||||
type StoresVec<'a> = bumpalo::collections::Vec<'a, (Symbol, Layout<'a>, Expr<'a>)>;
|
||||
type StoresVec<'a> = bumpalo::collections::Vec<'a, (Symbol, InLayout<'a>, Expr<'a>)>;
|
||||
|
||||
pub fn optimize_when<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
procs: &mut Procs<'a>,
|
||||
layout_cache: &mut LayoutCache<'a>,
|
||||
cond_symbol: Symbol,
|
||||
cond_layout: Layout<'a>,
|
||||
ret_layout: Layout<'a>,
|
||||
cond_layout: InLayout<'a>,
|
||||
ret_layout: InLayout<'a>,
|
||||
opt_branches: bumpalo::collections::Vec<'a, (Pattern<'a>, Guard<'a>, Stmt<'a>)>,
|
||||
) -> Stmt<'a> {
|
||||
let (patterns, _indexed_branches) = opt_branches
|
||||
|
@ -1299,7 +1314,7 @@ pub fn optimize_when<'a>(
|
|||
|
||||
let indexed_branches: Vec<_> = _indexed_branches;
|
||||
|
||||
let decision_tree = compile(patterns);
|
||||
let decision_tree = compile(&layout_cache.interner, patterns);
|
||||
let decider = tree_to_decider(decision_tree);
|
||||
|
||||
// for each target (branch body), count in how many ways it can be reached
|
||||
|
@ -1361,11 +1376,11 @@ enum PathInstruction {
|
|||
|
||||
fn path_to_expr_help<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
layout_interner: &TLLayoutInterner<'a>,
|
||||
layout_interner: &mut TLLayoutInterner<'a>,
|
||||
mut symbol: Symbol,
|
||||
path: &[PathInstruction],
|
||||
mut layout: Layout<'a>,
|
||||
) -> (Symbol, StoresVec<'a>, Layout<'a>) {
|
||||
mut layout: InLayout<'a>,
|
||||
) -> (Symbol, StoresVec<'a>, InLayout<'a>) {
|
||||
let mut stores = bumpalo::collections::Vec::new_in(env.arena);
|
||||
|
||||
// let instructions = reverse_path(path);
|
||||
|
@ -1381,17 +1396,20 @@ fn path_to_expr_help<'a>(
|
|||
PathInstruction::TagIndex { index, tag_id } => {
|
||||
let index = *index;
|
||||
|
||||
match &layout {
|
||||
match layout_interner.get(layout) {
|
||||
Layout::Union(union_layout) => {
|
||||
let inner_expr = Expr::UnionAtIndex {
|
||||
tag_id: *tag_id,
|
||||
structure: symbol,
|
||||
index,
|
||||
union_layout: *union_layout,
|
||||
union_layout: union_layout,
|
||||
};
|
||||
|
||||
let inner_layout =
|
||||
union_layout.layout_at(*tag_id as TagIdIntType, index as usize);
|
||||
let inner_layout = union_layout.layout_at(
|
||||
layout_interner,
|
||||
*tag_id as TagIdIntType,
|
||||
index as usize,
|
||||
);
|
||||
|
||||
symbol = env.unique_symbol();
|
||||
stores.push((symbol, inner_layout, inner_expr));
|
||||
|
@ -1431,7 +1449,7 @@ fn path_to_expr_help<'a>(
|
|||
PathInstruction::ListIndex { index } => {
|
||||
let list_sym = symbol;
|
||||
|
||||
match layout {
|
||||
match layout_interner.get(layout) {
|
||||
Layout::Builtin(Builtin::List(elem_layout)) => {
|
||||
let (index_sym, new_stores) = build_list_index_probe(env, list_sym, index);
|
||||
|
||||
|
@ -1446,8 +1464,6 @@ fn path_to_expr_help<'a>(
|
|||
arguments: env.arena.alloc([list_sym, index_sym]),
|
||||
});
|
||||
|
||||
let elem_layout = layout_interner.get(elem_layout);
|
||||
|
||||
stores.push((load_sym, elem_layout, load_expr));
|
||||
|
||||
layout = elem_layout;
|
||||
|
@ -1464,9 +1480,9 @@ fn path_to_expr_help<'a>(
|
|||
|
||||
fn test_to_comparison<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
layout_interner: &TLLayoutInterner<'a>,
|
||||
layout_interner: &mut TLLayoutInterner<'a>,
|
||||
cond_symbol: Symbol,
|
||||
cond_layout: &Layout<'a>,
|
||||
cond_layout: &InLayout<'a>,
|
||||
path: &[PathInstruction],
|
||||
test: Test<'a>,
|
||||
) -> (StoresVec<'a>, Comparison, Option<ConstructorKnown<'a>>) {
|
||||
|
@ -1480,7 +1496,7 @@ fn test_to_comparison<'a>(
|
|||
// (e.g. record pattern guard matches)
|
||||
debug_assert!(union.alternatives.len() > 1);
|
||||
|
||||
match test_layout {
|
||||
match layout_interner.get(test_layout) {
|
||||
Layout::Union(union_layout) => {
|
||||
let lhs = Expr::Literal(Literal::Int((tag_id as i128).to_ne_bytes()));
|
||||
|
||||
|
@ -1544,7 +1560,7 @@ fn test_to_comparison<'a>(
|
|||
|
||||
let lhs = Expr::Literal(Literal::Byte(test_byte as u8));
|
||||
let lhs_symbol = env.unique_symbol();
|
||||
stores.push((lhs_symbol, Layout::u8(), lhs));
|
||||
stores.push((lhs_symbol, Layout::U8, lhs));
|
||||
|
||||
(stores, (lhs_symbol, Comparator::Eq, rhs_symbol), None)
|
||||
}
|
||||
|
@ -1552,7 +1568,7 @@ fn test_to_comparison<'a>(
|
|||
Test::IsBit(test_bit) => {
|
||||
let lhs = Expr::Literal(Literal::Bool(test_bit));
|
||||
let lhs_symbol = env.unique_symbol();
|
||||
stores.push((lhs_symbol, Layout::Builtin(Builtin::Bool), lhs));
|
||||
stores.push((lhs_symbol, Layout::BOOL, lhs));
|
||||
|
||||
(stores, (lhs_symbol, Comparator::Eq, rhs_symbol), None)
|
||||
}
|
||||
|
@ -1561,7 +1577,7 @@ fn test_to_comparison<'a>(
|
|||
let lhs = Expr::Literal(Literal::Str(env.arena.alloc(test_str)));
|
||||
let lhs_symbol = env.unique_symbol();
|
||||
|
||||
stores.push((lhs_symbol, Layout::Builtin(Builtin::Str), lhs));
|
||||
stores.push((lhs_symbol, Layout::STR, lhs));
|
||||
|
||||
(stores, (lhs_symbol, Comparator::Eq, rhs_symbol), None)
|
||||
}
|
||||
|
@ -1570,7 +1586,7 @@ fn test_to_comparison<'a>(
|
|||
let list_layout = test_layout;
|
||||
let list_sym = rhs_symbol;
|
||||
|
||||
match list_layout {
|
||||
match layout_interner.get(list_layout) {
|
||||
Layout::Builtin(Builtin::List(_elem_layout)) => {
|
||||
let real_len_expr = Expr::Call(Call {
|
||||
call_type: CallType::LowLevel {
|
||||
|
@ -1614,16 +1630,16 @@ enum Comparator {
|
|||
type Comparison = (Symbol, Comparator, Symbol);
|
||||
|
||||
type Tests<'a> = std::vec::Vec<(
|
||||
bumpalo::collections::Vec<'a, (Symbol, Layout<'a>, Expr<'a>)>,
|
||||
bumpalo::collections::Vec<'a, (Symbol, InLayout<'a>, Expr<'a>)>,
|
||||
Comparison,
|
||||
Option<ConstructorKnown<'a>>,
|
||||
)>;
|
||||
|
||||
fn stores_and_condition<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
layout_interner: &TLLayoutInterner<'a>,
|
||||
layout_interner: &mut TLLayoutInterner<'a>,
|
||||
cond_symbol: Symbol,
|
||||
cond_layout: &Layout<'a>,
|
||||
cond_layout: &InLayout<'a>,
|
||||
test_chain: Vec<(Vec<PathInstruction>, Test<'a>)>,
|
||||
) -> Tests<'a> {
|
||||
let mut tests: Tests = Vec::with_capacity(test_chain.len());
|
||||
|
@ -1646,8 +1662,8 @@ fn stores_and_condition<'a>(
|
|||
#[allow(clippy::too_many_arguments)]
|
||||
fn compile_test<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
ret_layout: Layout<'a>,
|
||||
stores: bumpalo::collections::Vec<'a, (Symbol, Layout<'a>, Expr<'a>)>,
|
||||
ret_layout: InLayout<'a>,
|
||||
stores: bumpalo::collections::Vec<'a, (Symbol, InLayout<'a>, Expr<'a>)>,
|
||||
lhs: Symbol,
|
||||
cmp: Comparator,
|
||||
rhs: Symbol,
|
||||
|
@ -1671,8 +1687,8 @@ fn compile_test<'a>(
|
|||
fn compile_test_help<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
branch_info: ConstructorKnown<'a>,
|
||||
ret_layout: Layout<'a>,
|
||||
stores: bumpalo::collections::Vec<'a, (Symbol, Layout<'a>, Expr<'a>)>,
|
||||
ret_layout: InLayout<'a>,
|
||||
stores: bumpalo::collections::Vec<'a, (Symbol, InLayout<'a>, Expr<'a>)>,
|
||||
lhs: Symbol,
|
||||
cmp: Comparator,
|
||||
rhs: Symbol,
|
||||
|
@ -1729,7 +1745,7 @@ fn compile_test_help<'a>(
|
|||
|
||||
cond = Stmt::Switch {
|
||||
cond_symbol: test_symbol,
|
||||
cond_layout: Layout::Builtin(Builtin::Bool),
|
||||
cond_layout: Layout::BOOL,
|
||||
ret_layout,
|
||||
branches,
|
||||
default_branch,
|
||||
|
@ -1748,12 +1764,7 @@ fn compile_test_help<'a>(
|
|||
});
|
||||
|
||||
// write to the test symbol
|
||||
cond = Stmt::Let(
|
||||
test_symbol,
|
||||
test,
|
||||
Layout::Builtin(Builtin::Bool),
|
||||
arena.alloc(cond),
|
||||
);
|
||||
cond = Stmt::Let(test_symbol, test, Layout::BOOL, arena.alloc(cond));
|
||||
|
||||
// stores are in top-to-bottom order, so we have to add them in reverse
|
||||
for (symbol, layout, expr) in stores.into_iter().rev() {
|
||||
|
@ -1765,7 +1776,7 @@ fn compile_test_help<'a>(
|
|||
|
||||
fn compile_tests<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
ret_layout: Layout<'a>,
|
||||
ret_layout: InLayout<'a>,
|
||||
tests: Tests<'a>,
|
||||
fail: &'a Stmt<'a>,
|
||||
mut cond: Stmt<'a>,
|
||||
|
@ -1789,13 +1800,13 @@ fn compile_tests<'a>(
|
|||
enum ConstructorKnown<'a> {
|
||||
Both {
|
||||
scrutinee: Symbol,
|
||||
layout: Layout<'a>,
|
||||
layout: InLayout<'a>,
|
||||
pass: TagIdIntType,
|
||||
fail: TagIdIntType,
|
||||
},
|
||||
OnlyPass {
|
||||
scrutinee: Symbol,
|
||||
layout: Layout<'a>,
|
||||
layout: InLayout<'a>,
|
||||
tag_id: TagIdIntType,
|
||||
},
|
||||
Neither,
|
||||
|
@ -1804,7 +1815,7 @@ enum ConstructorKnown<'a> {
|
|||
impl<'a> ConstructorKnown<'a> {
|
||||
fn from_test_chain(
|
||||
cond_symbol: Symbol,
|
||||
cond_layout: &Layout<'a>,
|
||||
cond_layout: InLayout<'a>,
|
||||
test_chain: &[(Vec<PathInstruction>, Test)],
|
||||
) -> Self {
|
||||
match test_chain {
|
||||
|
@ -1813,14 +1824,14 @@ impl<'a> ConstructorKnown<'a> {
|
|||
if union.alternatives.len() == 2 {
|
||||
// excluded middle: we also know the tag_id in the fail branch
|
||||
ConstructorKnown::Both {
|
||||
layout: *cond_layout,
|
||||
layout: cond_layout,
|
||||
scrutinee: cond_symbol,
|
||||
pass: *tag_id,
|
||||
fail: (*tag_id == 0) as _,
|
||||
}
|
||||
} else {
|
||||
ConstructorKnown::OnlyPass {
|
||||
layout: *cond_layout,
|
||||
layout: cond_layout,
|
||||
scrutinee: cond_symbol,
|
||||
tag_id: *tag_id,
|
||||
}
|
||||
|
@ -1842,8 +1853,8 @@ fn decide_to_branching<'a>(
|
|||
procs: &mut Procs<'a>,
|
||||
layout_cache: &mut LayoutCache<'a>,
|
||||
cond_symbol: Symbol,
|
||||
cond_layout: Layout<'a>,
|
||||
ret_layout: Layout<'a>,
|
||||
cond_layout: InLayout<'a>,
|
||||
ret_layout: InLayout<'a>,
|
||||
decider: Decider<'a, Choice<'a>>,
|
||||
jumps: &[(u64, JoinPointId, Stmt<'a>)],
|
||||
) -> Stmt<'a> {
|
||||
|
@ -1897,7 +1908,7 @@ fn decide_to_branching<'a>(
|
|||
let decide = crate::ir::cond(
|
||||
env,
|
||||
test_symbol,
|
||||
Layout::Builtin(Builtin::Bool),
|
||||
Layout::BOOL,
|
||||
pass_expr,
|
||||
fail_expr,
|
||||
ret_layout,
|
||||
|
@ -1906,7 +1917,7 @@ fn decide_to_branching<'a>(
|
|||
// calculate the guard value
|
||||
let param = Param {
|
||||
symbol: test_symbol,
|
||||
layout: Layout::Builtin(Builtin::Bool),
|
||||
layout: Layout::BOOL,
|
||||
ownership: Ownership::Owned,
|
||||
};
|
||||
|
||||
|
@ -1949,11 +1960,11 @@ fn decide_to_branching<'a>(
|
|||
);
|
||||
|
||||
let chain_branch_info =
|
||||
ConstructorKnown::from_test_chain(cond_symbol, &cond_layout, &test_chain);
|
||||
ConstructorKnown::from_test_chain(cond_symbol, cond_layout, &test_chain);
|
||||
|
||||
let tests = stores_and_condition(
|
||||
env,
|
||||
&layout_cache.interner,
|
||||
&mut layout_cache.interner,
|
||||
cond_symbol,
|
||||
&cond_layout,
|
||||
test_chain,
|
||||
|
@ -2004,8 +2015,13 @@ fn decide_to_branching<'a>(
|
|||
// the cond_layout can change in the process. E.g. if the cond is a Tag, we actually
|
||||
// switch on the tag discriminant (currently an i64 value)
|
||||
// NOTE the tag discriminant is not actually loaded, `cond` can point to a tag
|
||||
let (inner_cond_symbol, cond_stores_vec, inner_cond_layout) =
|
||||
path_to_expr_help(env, &layout_cache.interner, cond_symbol, &path, cond_layout);
|
||||
let (inner_cond_symbol, cond_stores_vec, inner_cond_layout) = path_to_expr_help(
|
||||
env,
|
||||
&mut layout_cache.interner,
|
||||
cond_symbol,
|
||||
&path,
|
||||
cond_layout,
|
||||
);
|
||||
|
||||
let default_branch = decide_to_branching(
|
||||
env,
|
||||
|
@ -2082,7 +2098,8 @@ fn decide_to_branching<'a>(
|
|||
|
||||
// We have learned more about the exact layout of the cond (based on the path)
|
||||
// but tests are still relative to the original cond symbol
|
||||
let mut switch = if let Layout::Union(union_layout) = inner_cond_layout {
|
||||
let inner_cond_layout_raw = layout_cache.get_in(inner_cond_layout);
|
||||
let mut switch = if let Layout::Union(union_layout) = inner_cond_layout_raw {
|
||||
let tag_id_symbol = env.unique_symbol();
|
||||
|
||||
let temp = Stmt::Switch {
|
||||
|
@ -2104,7 +2121,7 @@ fn decide_to_branching<'a>(
|
|||
union_layout.tag_id_layout(),
|
||||
env.arena.alloc(temp),
|
||||
)
|
||||
} else if let Layout::Builtin(Builtin::List(_)) = inner_cond_layout {
|
||||
} else if let Layout::Builtin(Builtin::List(_)) = inner_cond_layout_raw {
|
||||
let len_symbol = env.unique_symbol();
|
||||
|
||||
let switch = Stmt::Switch {
|
||||
|
@ -2150,7 +2167,7 @@ fn decide_to_branching<'a>(
|
|||
}
|
||||
|
||||
/*
|
||||
fn boolean_all<'a>(arena: &'a Bump, tests: Vec<(Expr<'a>, Expr<'a>, Layout<'a>)>) -> Expr<'a> {
|
||||
fn boolean_all<'a>(arena: &'a Bump, tests: Vec<(Expr<'a>, Expr<'a>, InLayout<'a>)>) -> Expr<'a> {
|
||||
let mut expr = Expr::Bool(true);
|
||||
|
||||
for (lhs, rhs, layout) in tests.into_iter().rev() {
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::ir::{
|
|||
CallType, Expr, HigherOrderLowLevel, JoinPointId, ModifyRc, Param, Proc, ProcLayout, Stmt,
|
||||
UpdateModeIds,
|
||||
};
|
||||
use crate::layout::{Layout, STLayoutInterner};
|
||||
use crate::layout::{InLayout, Layout, LayoutInterner, STLayoutInterner};
|
||||
use bumpalo::collections::Vec;
|
||||
use bumpalo::Bump;
|
||||
use roc_collections::all::{MutMap, MutSet};
|
||||
|
@ -559,7 +559,7 @@ impl<'a, 'i> Context<'a, 'i> {
|
|||
z: Symbol,
|
||||
call_type: crate::ir::CallType<'a>,
|
||||
arguments: &'a [Symbol],
|
||||
l: Layout<'a>,
|
||||
l: InLayout<'a>,
|
||||
b: &'a Stmt<'a>,
|
||||
b_live_vars: &LiveVarSet,
|
||||
) -> &'a Stmt<'a> {
|
||||
|
@ -600,8 +600,7 @@ impl<'a, 'i> Context<'a, 'i> {
|
|||
arg_layouts,
|
||||
..
|
||||
} => {
|
||||
let top_level =
|
||||
ProcLayout::new(self.arena, arg_layouts, name.niche(), **ret_layout);
|
||||
let top_level = ProcLayout::new(self.arena, arg_layouts, name.niche(), *ret_layout);
|
||||
|
||||
// get the borrow signature
|
||||
let ps = self
|
||||
|
@ -629,7 +628,7 @@ impl<'a, 'i> Context<'a, 'i> {
|
|||
z: Symbol,
|
||||
lowlevel: &'a crate::ir::HigherOrderLowLevel,
|
||||
arguments: &'a [Symbol],
|
||||
l: Layout<'a>,
|
||||
l: InLayout<'a>,
|
||||
b: &'a Stmt<'a>,
|
||||
b_live_vars: &LiveVarSet,
|
||||
) -> &'a Stmt<'a> {
|
||||
|
@ -857,7 +856,7 @@ impl<'a, 'i> Context<'a, 'i> {
|
|||
codegen: &mut CodegenTools<'i>,
|
||||
z: Symbol,
|
||||
v: Expr<'a>,
|
||||
l: Layout<'a>,
|
||||
l: InLayout<'a>,
|
||||
b: &'a Stmt<'a>,
|
||||
b_live_vars: &LiveVarSet,
|
||||
) -> (&'a Stmt<'a>, LiveVarSet) {
|
||||
|
@ -955,7 +954,7 @@ impl<'a, 'i> Context<'a, 'i> {
|
|||
(new_b, live_vars)
|
||||
}
|
||||
|
||||
fn update_var_info(&self, symbol: Symbol, layout: &Layout<'a>, expr: &Expr<'a>) -> Self {
|
||||
fn update_var_info(&self, symbol: Symbol, layout: &InLayout<'a>, expr: &Expr<'a>) -> Self {
|
||||
// is this value a constant? TODO do function pointers also fall into this category?
|
||||
let persistent = false;
|
||||
|
||||
|
@ -970,13 +969,13 @@ impl<'a, 'i> Context<'a, 'i> {
|
|||
fn update_var_info_help(
|
||||
&self,
|
||||
symbol: Symbol,
|
||||
layout: &Layout<'a>,
|
||||
layout: &InLayout<'a>,
|
||||
persistent: bool,
|
||||
consume: bool,
|
||||
reset: bool,
|
||||
) -> Self {
|
||||
// should we perform incs and decs on this value?
|
||||
let reference = layout.contains_refcounted(self.layout_interner);
|
||||
let reference = self.layout_interner.contains_refcounted(*layout);
|
||||
|
||||
let info = VarInfo {
|
||||
reference,
|
||||
|
@ -997,7 +996,7 @@ impl<'a, 'i> Context<'a, 'i> {
|
|||
|
||||
for p in ps.iter() {
|
||||
let info = VarInfo {
|
||||
reference: p.layout.contains_refcounted(self.layout_interner),
|
||||
reference: self.layout_interner.contains_refcounted(p.layout),
|
||||
consume: match p.ownership {
|
||||
Ownership::Owned => true,
|
||||
Ownership::Borrowed => false,
|
||||
|
@ -1024,7 +1023,7 @@ impl<'a, 'i> Context<'a, 'i> {
|
|||
) -> &'a Stmt<'a> {
|
||||
for p in ps.iter() {
|
||||
if p.ownership == Ownership::Owned
|
||||
&& p.layout.contains_refcounted(self.layout_interner)
|
||||
&& self.layout_interner.contains_refcounted(p.layout)
|
||||
&& !b_live_vars.contains(&p.symbol)
|
||||
{
|
||||
b = self.add_dec(p.symbol, b)
|
||||
|
@ -1300,7 +1299,7 @@ fn branch_on_list_uniqueness<'a, 'i>(
|
|||
arena: &'a Bump,
|
||||
codegen: &mut CodegenTools<'i>,
|
||||
list_symbol: Symbol,
|
||||
return_layout: Layout<'a>,
|
||||
return_layout: InLayout<'a>,
|
||||
then_branch_stmt: Stmt<'a>,
|
||||
else_branch_stmt: &'a Stmt<'a>,
|
||||
) -> Stmt<'a> {
|
||||
|
@ -1331,7 +1330,7 @@ fn branch_on_list_uniqueness<'a, 'i>(
|
|||
Stmt::Let(
|
||||
condition_symbol,
|
||||
Expr::Call(condition_call),
|
||||
Layout::bool(),
|
||||
Layout::BOOL,
|
||||
stmt,
|
||||
)
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -11,14 +11,11 @@ use roc_collections::{default_hasher, BumpMap};
|
|||
use roc_module::symbol::Symbol;
|
||||
use roc_target::TargetInfo;
|
||||
|
||||
use super::{Builtin, LambdaSet, Layout};
|
||||
|
||||
#[allow(unused)] // for now
|
||||
pub struct InLayouts(PhantomData<()>);
|
||||
use super::{Builtin, FieldOrderHash, LambdaSet, Layout, UnionLayout};
|
||||
|
||||
macro_rules! cache_interned_layouts {
|
||||
($($i:literal, $name:ident, $layout:expr)*; $total_constants:literal) => {
|
||||
impl InLayouts {
|
||||
impl<'a> Layout<'a> {
|
||||
$(
|
||||
#[allow(unused)] // for now
|
||||
pub const $name: InLayout<'static> = unsafe { InLayout::from_reserved_index($i) };
|
||||
|
@ -48,8 +45,8 @@ macro_rules! cache_interned_layouts {
|
|||
}
|
||||
|
||||
cache_interned_layouts! {
|
||||
0, VOID, Layout::VOID
|
||||
1, UNIT, Layout::UNIT
|
||||
0, VOID, Layout::VOID_NAKED
|
||||
1, UNIT, Layout::UNIT_NAKED
|
||||
2, BOOL, Layout::Builtin(Builtin::Bool)
|
||||
3, U8, Layout::Builtin(Builtin::Int(IntWidth::U8))
|
||||
4, U16, Layout::Builtin(Builtin::Int(IntWidth::U16))
|
||||
|
@ -64,13 +61,20 @@ cache_interned_layouts! {
|
|||
13, F32, Layout::Builtin(Builtin::Float(FloatWidth::F32))
|
||||
14, F64, Layout::Builtin(Builtin::Float(FloatWidth::F64))
|
||||
15, DEC, Layout::Builtin(Builtin::Decimal)
|
||||
16, STR, Layout::Builtin(Builtin::Str)
|
||||
17, RECURSIVE_PTR, Layout::RecursivePointer
|
||||
|
||||
; 16
|
||||
; 18
|
||||
}
|
||||
|
||||
impl InLayouts {
|
||||
#[allow(unused)] // for now
|
||||
pub const fn from_int_width(w: IntWidth) -> InLayout<'static> {
|
||||
impl<'a> Layout<'a> {
|
||||
pub(super) const VOID_NAKED: Self = Layout::Union(UnionLayout::NonRecursive(&[]));
|
||||
pub(super) const UNIT_NAKED: Self = Layout::Struct {
|
||||
field_layouts: &[],
|
||||
field_order_hash: FieldOrderHash::ZERO_FIELD_HASH,
|
||||
};
|
||||
|
||||
pub const fn int_width(w: IntWidth) -> InLayout<'static> {
|
||||
match w {
|
||||
IntWidth::U8 => Self::U8,
|
||||
IntWidth::U16 => Self::U16,
|
||||
|
@ -84,8 +88,7 @@ impl InLayouts {
|
|||
IntWidth::I128 => Self::I128,
|
||||
}
|
||||
}
|
||||
#[allow(unused)] // for now
|
||||
pub const fn from_float_width(w: FloatWidth) -> InLayout<'static> {
|
||||
pub const fn float_width(w: FloatWidth) -> InLayout<'static> {
|
||||
match w {
|
||||
FloatWidth::F32 => Self::F32,
|
||||
FloatWidth::F64 => Self::F64,
|
||||
|
@ -114,6 +117,9 @@ pub trait LayoutInterner<'a>: Sized {
|
|||
/// Retrieves a value from the interner.
|
||||
fn get(&self, key: InLayout<'a>) -> Layout<'a>;
|
||||
|
||||
//
|
||||
// Convenience methods
|
||||
|
||||
fn target_info(&self) -> TargetInfo;
|
||||
|
||||
fn alignment_bytes(&self, layout: InLayout<'a>) -> u32 {
|
||||
|
@ -123,6 +129,28 @@ pub trait LayoutInterner<'a>: Sized {
|
|||
fn stack_size(&self, layout: InLayout<'a>) -> u32 {
|
||||
self.get(layout).stack_size(self, self.target_info())
|
||||
}
|
||||
|
||||
fn contains_refcounted(&self, layout: InLayout<'a>) -> bool {
|
||||
self.get(layout).contains_refcounted(self)
|
||||
}
|
||||
|
||||
fn is_refcounted(&self, layout: InLayout<'a>) -> bool {
|
||||
self.get(layout).is_refcounted()
|
||||
}
|
||||
|
||||
fn to_doc<'b, D, A>(
|
||||
&self,
|
||||
layout: InLayout<'a>,
|
||||
alloc: &'b D,
|
||||
parens: crate::ir::Parens,
|
||||
) -> ven_pretty::DocBuilder<'b, D, A>
|
||||
where
|
||||
D: ven_pretty::DocAllocator<'b, A>,
|
||||
D::Doc: Clone,
|
||||
A: Clone,
|
||||
{
|
||||
self.get(layout).to_doc(alloc, self, parens)
|
||||
}
|
||||
}
|
||||
|
||||
/// An interned layout.
|
||||
|
@ -227,7 +255,7 @@ fn make_normalized_lamdba_set<'a>(
|
|||
LambdaSet {
|
||||
set,
|
||||
representation,
|
||||
full_layout: InLayouts::VOID,
|
||||
full_layout: Layout::VOID,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ use crate::inc_dec::{collect_stmt, occurring_variables_expr, JPLiveVarMap, LiveV
|
|||
use crate::ir::{
|
||||
BranchInfo, Call, Expr, ListLiteralElement, Proc, Stmt, UpdateModeId, UpdateModeIds,
|
||||
};
|
||||
use crate::layout::{Layout, TagIdIntType, UnionLayout};
|
||||
use crate::layout::{Layout, LayoutInterner, STLayoutInterner, TagIdIntType, UnionLayout};
|
||||
use bumpalo::collections::Vec;
|
||||
use bumpalo::Bump;
|
||||
use roc_collections::all::MutSet;
|
||||
|
@ -25,6 +25,7 @@ use roc_module::symbol::{IdentIds, ModuleId, Symbol};
|
|||
|
||||
pub fn insert_reset_reuse<'a, 'i>(
|
||||
arena: &'a Bump,
|
||||
interner: &'i mut STLayoutInterner<'a>,
|
||||
home: ModuleId,
|
||||
ident_ids: &'i mut IdentIds,
|
||||
update_mode_ids: &'i mut UpdateModeIds,
|
||||
|
@ -32,6 +33,7 @@ pub fn insert_reset_reuse<'a, 'i>(
|
|||
) -> Proc<'a> {
|
||||
let mut env = Env {
|
||||
arena,
|
||||
interner,
|
||||
home,
|
||||
ident_ids,
|
||||
update_mode_ids,
|
||||
|
@ -65,6 +67,7 @@ fn may_reuse(tag_layout: UnionLayout, tag_id: TagIdIntType, other: &CtorInfo) ->
|
|||
#[derive(Debug)]
|
||||
struct Env<'a, 'i> {
|
||||
arena: &'a Bump,
|
||||
interner: &'i mut STLayoutInterner<'a>,
|
||||
|
||||
/// required for creating new `Symbol`s
|
||||
home: ModuleId,
|
||||
|
@ -332,7 +335,7 @@ fn insert_reset<'a>(
|
|||
update_mode: w.update_mode,
|
||||
};
|
||||
|
||||
let layout = Layout::Union(union_layout);
|
||||
let layout = env.interner.insert(Layout::Union(union_layout));
|
||||
|
||||
stmt = env
|
||||
.arena
|
||||
|
@ -612,11 +615,11 @@ fn function_r_branch_body<'a, 'i>(
|
|||
scrutinee,
|
||||
layout,
|
||||
tag_id,
|
||||
} => match layout {
|
||||
} => match env.interner.get(*layout) {
|
||||
Layout::Union(UnionLayout::NonRecursive(_)) => temp,
|
||||
Layout::Union(union_layout) if !union_layout.tag_is_null(*tag_id) => {
|
||||
let ctor_info = CtorInfo {
|
||||
layout: *union_layout,
|
||||
layout: union_layout,
|
||||
id: *tag_id,
|
||||
};
|
||||
function_d(env, *scrutinee, &ctor_info, temp)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use crate::borrow::Ownership;
|
||||
use crate::ir::{CallType, Expr, JoinPointId, Param, Stmt};
|
||||
use crate::layout::{LambdaName, Layout};
|
||||
use crate::layout::{InLayout, LambdaName};
|
||||
use bumpalo::collections::Vec;
|
||||
use bumpalo::Bump;
|
||||
use roc_module::symbol::Symbol;
|
||||
|
@ -34,8 +34,8 @@ pub fn make_tail_recursive<'a>(
|
|||
id: JoinPointId,
|
||||
needle: LambdaName,
|
||||
stmt: Stmt<'a>,
|
||||
args: &'a [(Layout<'a>, Symbol, Symbol)],
|
||||
ret_layout: Layout,
|
||||
args: &'a [(InLayout<'a>, Symbol, Symbol)],
|
||||
ret_layout: InLayout<'a>,
|
||||
) -> Option<Stmt<'a>> {
|
||||
let allocated = arena.alloc(stmt);
|
||||
|
||||
|
@ -73,8 +73,8 @@ fn insert_jumps<'a>(
|
|||
stmt: &'a Stmt<'a>,
|
||||
goal_id: JoinPointId,
|
||||
needle: LambdaName,
|
||||
needle_arguments: &'a [(Layout<'a>, Symbol, Symbol)],
|
||||
needle_result: Layout,
|
||||
needle_arguments: &'a [(InLayout<'a>, Symbol, Symbol)],
|
||||
needle_result: InLayout<'a>,
|
||||
) -> Option<&'a Stmt<'a>> {
|
||||
use Stmt::*;
|
||||
|
||||
|
@ -101,7 +101,7 @@ fn insert_jumps<'a>(
|
|||
}),
|
||||
_,
|
||||
Stmt::Ret(rsym),
|
||||
) if symbol == rsym && is_equal_function(*fsym, arg_layouts, **ret_layout) => {
|
||||
) if symbol == rsym && is_equal_function(*fsym, arg_layouts, *ret_layout) => {
|
||||
// replace the call and return with a jump
|
||||
|
||||
let jump = Stmt::Jump(goal_id, arguments);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue