mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-21 15:59:20 +03:00
Merge pull request #2096 from rtfeldman/alias-analysis-pull-heap-cell-out
alias analysis: recursive tag union refactor
This commit is contained in:
commit
adb8ff881c
@ -686,8 +686,8 @@ where
|
||||
self.set_last_seen(*sym, stmt, &owning_symbol);
|
||||
}
|
||||
}
|
||||
Expr::Reset(sym) => {
|
||||
self.set_last_seen(*sym, stmt, &owning_symbol);
|
||||
Expr::Reset { symbol, .. } => {
|
||||
self.set_last_seen(*symbol, stmt, &owning_symbol);
|
||||
}
|
||||
Expr::EmptyArray => {}
|
||||
Expr::RuntimeErrorFunction(_) => {}
|
||||
|
@ -1108,7 +1108,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
|
||||
..
|
||||
} => build_tag(env, scope, union_layout, *tag_id, arguments, None, parent),
|
||||
|
||||
Reset(symbol) => {
|
||||
Reset { symbol, .. } => {
|
||||
let (tag_ptr, layout) = load_symbol_and_layout(scope, symbol);
|
||||
let tag_ptr = tag_ptr.into_pointer_value();
|
||||
|
||||
|
@ -20,6 +20,7 @@ use roc_module::symbol::{
|
||||
};
|
||||
use roc_mono::ir::{
|
||||
CapturedSymbols, EntryPoint, ExternalSpecializations, PartialProc, Proc, ProcLayout, Procs,
|
||||
UpdateModeIds,
|
||||
};
|
||||
use roc_mono::layout::{Layout, LayoutCache, LayoutProblem};
|
||||
use roc_parse::ast::{self, StrLiteral, TypeAnnotation};
|
||||
@ -835,6 +836,7 @@ enum Msg<'a> {
|
||||
external_specializations_requested: BumpMap<ModuleId, ExternalSpecializations>,
|
||||
procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>,
|
||||
problems: Vec<roc_mono::ir::MonoProblem>,
|
||||
update_mode_ids: UpdateModeIds,
|
||||
module_timing: ModuleTiming,
|
||||
subs: Subs,
|
||||
},
|
||||
@ -2098,6 +2100,7 @@ fn update<'a>(
|
||||
MadeSpecializations {
|
||||
module_id,
|
||||
mut ident_ids,
|
||||
mut update_mode_ids,
|
||||
subs,
|
||||
procedures,
|
||||
external_specializations_requested,
|
||||
@ -2124,6 +2127,7 @@ fn update<'a>(
|
||||
arena,
|
||||
module_id,
|
||||
&mut ident_ids,
|
||||
&mut update_mode_ids,
|
||||
&mut state.procedures,
|
||||
);
|
||||
|
||||
@ -3922,6 +3926,7 @@ fn make_specializations<'a>(
|
||||
) -> Msg<'a> {
|
||||
let make_specializations_start = SystemTime::now();
|
||||
let mut mono_problems = Vec::new();
|
||||
let mut update_mode_ids = UpdateModeIds::new();
|
||||
// do the thing
|
||||
let mut mono_env = roc_mono::ir::Env {
|
||||
arena,
|
||||
@ -3930,7 +3935,7 @@ fn make_specializations<'a>(
|
||||
home,
|
||||
ident_ids: &mut ident_ids,
|
||||
ptr_bytes,
|
||||
update_mode_counter: 0,
|
||||
update_mode_ids: &mut update_mode_ids,
|
||||
// call_specialization_counter=0 is reserved
|
||||
call_specialization_counter: 1,
|
||||
};
|
||||
@ -3973,6 +3978,7 @@ fn make_specializations<'a>(
|
||||
layout_cache,
|
||||
procedures,
|
||||
problems: mono_problems,
|
||||
update_mode_ids,
|
||||
subs,
|
||||
external_specializations_requested,
|
||||
module_timing,
|
||||
@ -4016,6 +4022,7 @@ fn build_pending_specializations<'a>(
|
||||
};
|
||||
|
||||
let mut mono_problems = std::vec::Vec::new();
|
||||
let mut update_mode_ids = UpdateModeIds::new();
|
||||
let mut subs = solved_subs.into_inner();
|
||||
let mut mono_env = roc_mono::ir::Env {
|
||||
arena,
|
||||
@ -4024,7 +4031,7 @@ fn build_pending_specializations<'a>(
|
||||
home,
|
||||
ident_ids: &mut ident_ids,
|
||||
ptr_bytes,
|
||||
update_mode_counter: 0,
|
||||
update_mode_ids: &mut update_mode_ids,
|
||||
// call_specialization_counter=0 is reserved
|
||||
call_specialization_counter: 1,
|
||||
};
|
||||
|
@ -210,12 +210,15 @@ where
|
||||
|
||||
let mut builder = TypeDefBuilder::new();
|
||||
|
||||
let variant_types = build_variant_types(&mut builder, &union_layout)?;
|
||||
let variant_types = recursive_variant_types(&mut builder, &union_layout)?;
|
||||
let root_type = if let UnionLayout::NonNullableUnwrapped(_) = union_layout {
|
||||
debug_assert_eq!(variant_types.len(), 1);
|
||||
variant_types[0]
|
||||
} else {
|
||||
builder.add_union_type(&variant_types)?
|
||||
let data_type = builder.add_union_type(&variant_types)?;
|
||||
let cell_type = builder.add_heap_cell_type();
|
||||
|
||||
builder.add_tuple_type(&[cell_type, data_type])?
|
||||
};
|
||||
|
||||
let type_def = builder.build(root_type)?;
|
||||
@ -867,8 +870,7 @@ fn call_spec(
|
||||
|
||||
builder.add_update(block, update_mode_var, cell)?;
|
||||
|
||||
let new_cell = builder.add_new_heap_cell(block)?;
|
||||
builder.add_make_tuple(block, &[new_cell, bag])
|
||||
with_new_heap_cell(builder, block, bag)
|
||||
};
|
||||
|
||||
let state_layout = Layout::Builtin(Builtin::List(&arg_layouts[0]));
|
||||
@ -998,9 +1000,8 @@ fn call_spec(
|
||||
builder.add_recursive_touch(block, removed_element)?;
|
||||
|
||||
let new_bag = builder.add_get_tuple_field(block, removed, 0)?;
|
||||
let new_cell = builder.add_new_heap_cell(block)?;
|
||||
|
||||
builder.add_make_tuple(block, &[new_cell, new_bag])
|
||||
with_new_heap_cell(builder, block, new_bag)
|
||||
};
|
||||
|
||||
let state_layout = Layout::Builtin(Builtin::List(&arg_layouts[0]));
|
||||
@ -1181,8 +1182,7 @@ fn list_append(
|
||||
|
||||
let new_bag = builder.add_bag_insert(block, bag, to_insert)?;
|
||||
|
||||
let new_cell = builder.add_new_heap_cell(block)?;
|
||||
builder.add_make_tuple(block, &[new_cell, new_bag])
|
||||
with_new_heap_cell(builder, block, new_bag)
|
||||
}
|
||||
|
||||
fn lowlevel_spec(
|
||||
@ -1268,8 +1268,7 @@ fn lowlevel_spec(
|
||||
|
||||
builder.add_bag_insert(block, bag, to_insert)?;
|
||||
|
||||
let new_cell = builder.add_new_heap_cell(block)?;
|
||||
builder.add_make_tuple(block, &[new_cell, bag])
|
||||
with_new_heap_cell(builder, block, bag)
|
||||
}
|
||||
ListSwap => {
|
||||
let list = env.symbols[&arguments[0]];
|
||||
@ -1279,8 +1278,7 @@ fn lowlevel_spec(
|
||||
|
||||
let _unit = builder.add_update(block, update_mode_var, cell)?;
|
||||
|
||||
let new_cell = builder.add_new_heap_cell(block)?;
|
||||
builder.add_make_tuple(block, &[new_cell, bag])
|
||||
with_new_heap_cell(builder, block, bag)
|
||||
}
|
||||
ListReverse => {
|
||||
let list = env.symbols[&arguments[0]];
|
||||
@ -1290,8 +1288,7 @@ fn lowlevel_spec(
|
||||
|
||||
let _unit = builder.add_update(block, update_mode_var, cell)?;
|
||||
|
||||
let new_cell = builder.add_new_heap_cell(block)?;
|
||||
builder.add_make_tuple(block, &[new_cell, bag])
|
||||
with_new_heap_cell(builder, block, bag)
|
||||
}
|
||||
ListAppend => {
|
||||
let list = env.symbols[&arguments[0]];
|
||||
@ -1359,8 +1356,7 @@ fn lowlevel_spec(
|
||||
|
||||
builder.add_bag_insert(block, bag, key_value)?;
|
||||
|
||||
let new_cell = builder.add_new_heap_cell(block)?;
|
||||
builder.add_make_tuple(block, &[new_cell, bag])
|
||||
with_new_heap_cell(builder, block, bag)
|
||||
}
|
||||
_other => {
|
||||
// println!("missing {:?}", _other);
|
||||
@ -1381,13 +1377,10 @@ fn recursive_tag_variant(
|
||||
) -> Result<TypeId> {
|
||||
let when_recursive = WhenRecursive::Loop(*union_layout);
|
||||
|
||||
let data_id = build_recursive_tuple_type(builder, fields, &when_recursive)?;
|
||||
let cell_id = builder.add_heap_cell_type();
|
||||
|
||||
builder.add_tuple_type(&[cell_id, data_id])
|
||||
build_recursive_tuple_type(builder, fields, &when_recursive)
|
||||
}
|
||||
|
||||
fn build_variant_types(
|
||||
fn recursive_variant_types(
|
||||
builder: &mut impl TypeContext,
|
||||
union_layout: &UnionLayout,
|
||||
) -> Result<Vec<TypeId>> {
|
||||
@ -1396,12 +1389,8 @@ fn build_variant_types(
|
||||
let mut result;
|
||||
|
||||
match union_layout {
|
||||
NonRecursive(tags) => {
|
||||
result = Vec::with_capacity(tags.len());
|
||||
|
||||
for tag in tags.iter() {
|
||||
result.push(build_tuple_type(builder, tag)?);
|
||||
}
|
||||
NonRecursive(_) => {
|
||||
unreachable!()
|
||||
}
|
||||
Recursive(tags) => {
|
||||
result = Vec::with_capacity(tags.len());
|
||||
@ -1425,8 +1414,7 @@ fn build_variant_types(
|
||||
result.push(recursive_tag_variant(builder, union_layout, tag)?);
|
||||
}
|
||||
|
||||
let unit = builder.add_tuple_type(&[])?;
|
||||
result.push(unit);
|
||||
result.push(recursive_tag_variant(builder, union_layout, &[])?);
|
||||
|
||||
for tag in tags[cutoff..].iter() {
|
||||
result.push(recursive_tag_variant(builder, union_layout, tag)?);
|
||||
@ -1436,7 +1424,7 @@ fn build_variant_types(
|
||||
nullable_id,
|
||||
other_fields: fields,
|
||||
} => {
|
||||
let unit = builder.add_tuple_type(&[])?;
|
||||
let unit = recursive_tag_variant(builder, union_layout, &[])?;
|
||||
let other_type = recursive_tag_variant(builder, union_layout, fields)?;
|
||||
|
||||
if *nullable_id {
|
||||
@ -1482,18 +1470,16 @@ fn expr_spec<'a>(
|
||||
tag_id,
|
||||
arguments,
|
||||
} => {
|
||||
let variant_types = build_variant_types(builder, tag_layout)?;
|
||||
|
||||
let data_id = build_tuple_value(builder, env, block, arguments)?;
|
||||
let cell_id = builder.add_new_heap_cell(block)?;
|
||||
|
||||
let value_id = match tag_layout {
|
||||
UnionLayout::NonRecursive(_) => {
|
||||
UnionLayout::NonRecursive(tags) => {
|
||||
let variant_types = non_recursive_variant_types(builder, tags)?;
|
||||
let value_id = build_tuple_value(builder, env, block, arguments)?;
|
||||
return builder.add_make_union(block, &variant_types, *tag_id as u32, value_id);
|
||||
}
|
||||
UnionLayout::NonNullableUnwrapped(_) => {
|
||||
let value_id = builder.add_make_tuple(block, &[cell_id, data_id])?;
|
||||
let value_id = data_id;
|
||||
|
||||
let type_name_bytes = recursive_tag_union_name_bytes(tag_layout).as_bytes();
|
||||
let type_name = TypeName(&type_name_bytes);
|
||||
@ -1502,32 +1488,24 @@ fn expr_spec<'a>(
|
||||
|
||||
return builder.add_make_named(block, MOD_APP, type_name, value_id);
|
||||
}
|
||||
UnionLayout::Recursive(_) => builder.add_make_tuple(block, &[cell_id, data_id])?,
|
||||
UnionLayout::NullableWrapped { nullable_id, .. } => {
|
||||
if *tag_id == *nullable_id as _ {
|
||||
data_id
|
||||
} else {
|
||||
builder.add_make_tuple(block, &[cell_id, data_id])?
|
||||
}
|
||||
}
|
||||
UnionLayout::NullableUnwrapped { nullable_id, .. } => {
|
||||
if *tag_id == *nullable_id as _ {
|
||||
data_id
|
||||
} else {
|
||||
builder.add_make_tuple(block, &[cell_id, data_id])?
|
||||
}
|
||||
}
|
||||
UnionLayout::Recursive(_) => data_id,
|
||||
UnionLayout::NullableWrapped { .. } => data_id,
|
||||
UnionLayout::NullableUnwrapped { .. } => data_id,
|
||||
};
|
||||
|
||||
let variant_types = recursive_variant_types(builder, tag_layout)?;
|
||||
|
||||
let union_id =
|
||||
builder.add_make_union(block, &variant_types, *tag_id as u32, value_id)?;
|
||||
|
||||
let tag_value_id = with_new_heap_cell(builder, block, union_id)?;
|
||||
|
||||
let type_name_bytes = recursive_tag_union_name_bytes(tag_layout).as_bytes();
|
||||
let type_name = TypeName(&type_name_bytes);
|
||||
|
||||
env.type_names.insert(*tag_layout);
|
||||
|
||||
builder.add_make_named(block, MOD_APP, type_name, union_id)
|
||||
builder.add_make_named(block, MOD_APP, type_name, tag_value_id)
|
||||
}
|
||||
Struct(fields) => build_tuple_value(builder, env, block, fields),
|
||||
UnionAtIndex {
|
||||
@ -1553,16 +1531,20 @@ fn expr_spec<'a>(
|
||||
let type_name_bytes = recursive_tag_union_name_bytes(union_layout).as_bytes();
|
||||
let type_name = TypeName(&type_name_bytes);
|
||||
|
||||
// unwrap the named wrapper
|
||||
let union_id = builder.add_unwrap_named(block, MOD_APP, type_name, tag_value_id)?;
|
||||
let variant_id = builder.add_unwrap_union(block, union_id, *tag_id as u32)?;
|
||||
|
||||
// now we have a tuple (cell, union { ... }); decompose
|
||||
let heap_cell = builder.add_get_tuple_field(block, union_id, TAG_CELL_INDEX)?;
|
||||
let union_data = builder.add_get_tuple_field(block, union_id, TAG_DATA_INDEX)?;
|
||||
|
||||
// we're reading from this value, so touch the heap cell
|
||||
let heap_cell = builder.add_get_tuple_field(block, variant_id, 0)?;
|
||||
builder.add_touch(block, heap_cell)?;
|
||||
|
||||
let tuple_value_id = builder.add_get_tuple_field(block, variant_id, 1)?;
|
||||
// next, unwrap the union at the tag id that we've got
|
||||
let variant_id = builder.add_unwrap_union(block, union_data, *tag_id as u32)?;
|
||||
|
||||
builder.add_get_tuple_field(block, tuple_value_id, index)
|
||||
builder.add_get_tuple_field(block, variant_id, index)
|
||||
}
|
||||
UnionLayout::NonNullableUnwrapped { .. } => {
|
||||
let index = (*index) as u32;
|
||||
@ -1573,16 +1555,20 @@ fn expr_spec<'a>(
|
||||
let type_name_bytes = recursive_tag_union_name_bytes(union_layout).as_bytes();
|
||||
let type_name = TypeName(&type_name_bytes);
|
||||
|
||||
let variant_id =
|
||||
builder.add_unwrap_named(block, MOD_APP, type_name, tag_value_id)?;
|
||||
// a tuple ( cell, union { ... } )
|
||||
let union_id = builder.add_unwrap_named(block, MOD_APP, type_name, tag_value_id)?;
|
||||
|
||||
// decompose
|
||||
let heap_cell = builder.add_get_tuple_field(block, union_id, TAG_CELL_INDEX)?;
|
||||
let union_data = builder.add_get_tuple_field(block, union_id, TAG_DATA_INDEX)?;
|
||||
|
||||
// we're reading from this value, so touch the heap cell
|
||||
let heap_cell = builder.add_get_tuple_field(block, variant_id, 0)?;
|
||||
builder.add_touch(block, heap_cell)?;
|
||||
|
||||
let tuple_value_id = builder.add_get_tuple_field(block, variant_id, 1)?;
|
||||
// next, unwrap the union at the tag id that we've got
|
||||
let variant_id = builder.add_unwrap_union(block, union_data, *tag_id as u32)?;
|
||||
|
||||
builder.add_get_tuple_field(block, tuple_value_id, index)
|
||||
builder.add_get_tuple_field(block, variant_id, index)
|
||||
}
|
||||
},
|
||||
StructAtIndex {
|
||||
@ -1613,9 +1599,7 @@ fn expr_spec<'a>(
|
||||
if all_constants {
|
||||
new_static_list(builder, block)
|
||||
} else {
|
||||
let cell = builder.add_new_heap_cell(block)?;
|
||||
|
||||
builder.add_make_tuple(block, &[cell, bag])
|
||||
with_new_heap_cell(builder, block, bag)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1626,7 +1610,7 @@ fn expr_spec<'a>(
|
||||
}
|
||||
_ => unreachable!("empty array does not have a list layout"),
|
||||
},
|
||||
Reset(symbol) => {
|
||||
Reset { symbol, .. } => {
|
||||
let type_id = layout_spec(builder, layout)?;
|
||||
let value_id = env.symbols[symbol];
|
||||
|
||||
@ -1637,7 +1621,11 @@ fn expr_spec<'a>(
|
||||
|
||||
builder.add_terminate(block, type_id)
|
||||
}
|
||||
GetTagId { .. } => builder.add_make_tuple(block, &[]),
|
||||
GetTagId { .. } => {
|
||||
// TODO touch heap cell in recursive cases
|
||||
|
||||
builder.add_make_tuple(block, &[])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1658,6 +1646,19 @@ fn layout_spec(builder: &mut impl TypeContext, layout: &Layout) -> Result<TypeId
|
||||
layout_spec_help(builder, layout, &WhenRecursive::Unreachable)
|
||||
}
|
||||
|
||||
fn non_recursive_variant_types(
|
||||
builder: &mut impl TypeContext,
|
||||
tags: &[&[Layout]],
|
||||
) -> Result<Vec<TypeId>> {
|
||||
let mut result = Vec::with_capacity(tags.len());
|
||||
|
||||
for tag in tags.iter() {
|
||||
result.push(build_tuple_type(builder, tag)?);
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn layout_spec_help(
|
||||
builder: &mut impl TypeContext,
|
||||
layout: &Layout,
|
||||
@ -1674,8 +1675,6 @@ fn layout_spec_help(
|
||||
when_recursive,
|
||||
),
|
||||
Union(union_layout) => {
|
||||
let variant_types = build_variant_types(builder, union_layout)?;
|
||||
|
||||
match union_layout {
|
||||
UnionLayout::NonRecursive(&[]) => {
|
||||
// must model Void as Unit, otherwise we run into problems where
|
||||
@ -1683,7 +1682,10 @@ fn layout_spec_help(
|
||||
// which is of course not possible
|
||||
builder.add_tuple_type(&[])
|
||||
}
|
||||
UnionLayout::NonRecursive(_) => builder.add_union_type(&variant_types),
|
||||
UnionLayout::NonRecursive(tags) => {
|
||||
let variant_types = non_recursive_variant_types(builder, tags)?;
|
||||
builder.add_union_type(&variant_types)
|
||||
}
|
||||
UnionLayout::Recursive(_)
|
||||
| UnionLayout::NullableUnwrapped { .. }
|
||||
| UnionLayout::NullableWrapped { .. }
|
||||
@ -1777,10 +1779,21 @@ const LIST_BAG_INDEX: u32 = 1;
|
||||
const DICT_CELL_INDEX: u32 = LIST_CELL_INDEX;
|
||||
const DICT_BAG_INDEX: u32 = LIST_BAG_INDEX;
|
||||
|
||||
fn new_list(builder: &mut FuncDefBuilder, block: BlockId, element_type: TypeId) -> Result<ValueId> {
|
||||
const TAG_CELL_INDEX: u32 = 0;
|
||||
const TAG_DATA_INDEX: u32 = 1;
|
||||
|
||||
fn with_new_heap_cell(
|
||||
builder: &mut FuncDefBuilder,
|
||||
block: BlockId,
|
||||
value: ValueId,
|
||||
) -> Result<ValueId> {
|
||||
let cell = builder.add_new_heap_cell(block)?;
|
||||
builder.add_make_tuple(block, &[cell, value])
|
||||
}
|
||||
|
||||
fn new_list(builder: &mut FuncDefBuilder, block: BlockId, element_type: TypeId) -> Result<ValueId> {
|
||||
let bag = builder.add_empty_bag(block, element_type)?;
|
||||
builder.add_make_tuple(block, &[cell, bag])
|
||||
with_new_heap_cell(builder, block, bag)
|
||||
}
|
||||
|
||||
fn new_dict(
|
||||
@ -1789,10 +1802,9 @@ fn new_dict(
|
||||
key_type: TypeId,
|
||||
value_type: TypeId,
|
||||
) -> Result<ValueId> {
|
||||
let cell = builder.add_new_heap_cell(block)?;
|
||||
let element_type = builder.add_tuple_type(&[key_type, value_type])?;
|
||||
let bag = builder.add_empty_bag(block, element_type)?;
|
||||
builder.add_make_tuple(block, &[cell, bag])
|
||||
with_new_heap_cell(builder, block, bag)
|
||||
}
|
||||
|
||||
fn new_static_string(builder: &mut FuncDefBuilder, block: BlockId) -> Result<ValueId> {
|
||||
|
@ -726,7 +726,7 @@ impl<'a> BorrowInfState<'a> {
|
||||
// the function must take it as an owned parameter
|
||||
self.own_args_if_param(xs);
|
||||
}
|
||||
Reset(x) => {
|
||||
Reset { symbol: x, .. } => {
|
||||
self.own_var(z);
|
||||
self.own_var(*x);
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ pub fn occurring_variables_expr(expr: &Expr<'_>, result: &mut MutSet<Symbol>) {
|
||||
result.extend(arguments.iter().copied());
|
||||
result.insert(*symbol);
|
||||
}
|
||||
Reset(x) => {
|
||||
Reset { symbol: x, .. } => {
|
||||
result.insert(*x);
|
||||
}
|
||||
|
||||
@ -761,7 +761,7 @@ impl<'a> Context<'a> {
|
||||
self.arena.alloc(Stmt::Let(z, v, l, b))
|
||||
}
|
||||
|
||||
EmptyArray | Literal(_) | Reset(_) | RuntimeErrorFunction(_) => {
|
||||
EmptyArray | Literal(_) | Reset { .. } | RuntimeErrorFunction(_) => {
|
||||
// EmptyArray is always stack-allocated
|
||||
// function pointers are persistent
|
||||
self.arena.alloc(Stmt::Let(z, v, l, b))
|
||||
@ -779,7 +779,7 @@ impl<'a> Context<'a> {
|
||||
// must this value be consumed?
|
||||
let consume = consume_expr(&self.vars, expr);
|
||||
|
||||
let reset = matches!(expr, Expr::Reset(_));
|
||||
let reset = matches!(expr, Expr::Reset { .. });
|
||||
|
||||
self.update_var_info_help(symbol, layout, persistent, consume, reset)
|
||||
}
|
||||
|
@ -37,8 +37,8 @@ static_assertions::assert_eq_size!([u8; 19 * 8], Stmt);
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
static_assertions::assert_eq_size!([u8; 20 * 8], Stmt);
|
||||
static_assertions::assert_eq_size!([u8; 6 * 8], ProcLayout);
|
||||
static_assertions::assert_eq_size!([u8; 8 * 8], Call);
|
||||
static_assertions::assert_eq_size!([u8; 6 * 8], CallType);
|
||||
static_assertions::assert_eq_size!([u8; 7 * 8], Call);
|
||||
static_assertions::assert_eq_size!([u8; 5 * 8], CallType);
|
||||
|
||||
macro_rules! return_on_layout_error {
|
||||
($env:expr, $layout_result:expr) => {
|
||||
@ -318,11 +318,17 @@ impl<'a> Proc<'a> {
|
||||
arena: &'a Bump,
|
||||
home: ModuleId,
|
||||
ident_ids: &'i mut IdentIds,
|
||||
update_mode_ids: &'i mut UpdateModeIds,
|
||||
procs: &mut MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>,
|
||||
) {
|
||||
for (_, proc) in procs.iter_mut() {
|
||||
let new_proc =
|
||||
crate::reset_reuse::insert_reset_reuse(arena, home, ident_ids, proc.clone());
|
||||
let new_proc = crate::reset_reuse::insert_reset_reuse(
|
||||
arena,
|
||||
home,
|
||||
ident_ids,
|
||||
update_mode_ids,
|
||||
proc.clone(),
|
||||
);
|
||||
*proc = new_proc;
|
||||
}
|
||||
}
|
||||
@ -988,8 +994,8 @@ pub struct Env<'a, 'i> {
|
||||
pub home: ModuleId,
|
||||
pub ident_ids: &'i mut IdentIds,
|
||||
pub ptr_bytes: u32,
|
||||
pub update_mode_counter: u64,
|
||||
pub call_specialization_counter: u64,
|
||||
pub update_mode_ids: &'i mut UpdateModeIds,
|
||||
pub call_specialization_counter: u32,
|
||||
}
|
||||
|
||||
impl<'a, 'i> Env<'a, 'i> {
|
||||
@ -1000,13 +1006,7 @@ impl<'a, 'i> Env<'a, 'i> {
|
||||
}
|
||||
|
||||
pub fn next_update_mode_id(&mut self) -> UpdateModeId {
|
||||
let id = UpdateModeId {
|
||||
id: self.update_mode_counter,
|
||||
};
|
||||
|
||||
self.update_mode_counter += 1;
|
||||
|
||||
id
|
||||
self.update_mode_ids.next_id()
|
||||
}
|
||||
|
||||
pub fn next_call_specialization_id(&mut self) -> CallSpecId {
|
||||
@ -1282,26 +1282,43 @@ impl<'a> Call<'a> {
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct CallSpecId {
|
||||
id: u64,
|
||||
id: u32,
|
||||
}
|
||||
|
||||
impl CallSpecId {
|
||||
pub fn to_bytes(self) -> [u8; 8] {
|
||||
pub fn to_bytes(self) -> [u8; 4] {
|
||||
self.id.to_ne_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct UpdateModeId {
|
||||
id: u64,
|
||||
id: u32,
|
||||
}
|
||||
|
||||
impl UpdateModeId {
|
||||
pub fn to_bytes(self) -> [u8; 8] {
|
||||
pub fn to_bytes(self) -> [u8; 4] {
|
||||
self.id.to_ne_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct UpdateModeIds {
|
||||
next: u32,
|
||||
}
|
||||
|
||||
impl UpdateModeIds {
|
||||
pub const fn new() -> Self {
|
||||
Self { next: 0 }
|
||||
}
|
||||
|
||||
pub fn next_id(&mut self) -> UpdateModeId {
|
||||
let id = UpdateModeId { id: self.next };
|
||||
self.next += 1;
|
||||
id
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum CallType<'a> {
|
||||
ByName {
|
||||
@ -1390,13 +1407,17 @@ pub enum Expr<'a> {
|
||||
Reuse {
|
||||
symbol: Symbol,
|
||||
update_tag_id: bool,
|
||||
update_mode: UpdateModeId,
|
||||
// normal Tag fields
|
||||
tag_layout: UnionLayout<'a>,
|
||||
tag_name: TagName,
|
||||
tag_id: TagIdIntType,
|
||||
arguments: &'a [Symbol],
|
||||
},
|
||||
Reset(Symbol),
|
||||
Reset {
|
||||
symbol: Symbol,
|
||||
update_mode: UpdateModeId,
|
||||
},
|
||||
|
||||
RuntimeErrorFunction(&'a str),
|
||||
}
|
||||
@ -1491,6 +1512,7 @@ impl<'a> Expr<'a> {
|
||||
symbol,
|
||||
tag_name,
|
||||
arguments,
|
||||
update_mode,
|
||||
..
|
||||
} => {
|
||||
let doc_tag = match tag_name {
|
||||
@ -1508,11 +1530,19 @@ impl<'a> Expr<'a> {
|
||||
.text("Reuse ")
|
||||
.append(symbol_to_doc(alloc, *symbol))
|
||||
.append(alloc.space())
|
||||
.append(format!("{:?}", update_mode))
|
||||
.append(alloc.space())
|
||||
.append(doc_tag)
|
||||
.append(alloc.space())
|
||||
.append(alloc.intersperse(it, " "))
|
||||
}
|
||||
Reset(symbol) => alloc.text("Reset ").append(symbol_to_doc(alloc, *symbol)),
|
||||
Reset {
|
||||
symbol,
|
||||
update_mode,
|
||||
} => alloc.text(format!(
|
||||
"Reset {{ symbol: {:?}, id: {} }}",
|
||||
symbol, update_mode.id
|
||||
)),
|
||||
|
||||
Struct(args) => {
|
||||
let it = args.iter().map(|s| symbol_to_doc(alloc, *s));
|
||||
@ -5715,7 +5745,7 @@ fn substitute_in_expr<'a>(
|
||||
}
|
||||
}
|
||||
|
||||
Reuse { .. } | Reset(_) => unreachable!("reset/reuse have not been introduced yet"),
|
||||
Reuse { .. } | Reset { .. } => unreachable!("reset/reuse have not been introduced yet"),
|
||||
|
||||
Struct(args) => {
|
||||
let mut did_change = false;
|
||||
|
@ -1,5 +1,7 @@
|
||||
use crate::inc_dec::{collect_stmt, occurring_variables_expr, JPLiveVarMap, LiveVarSet};
|
||||
use crate::ir::{BranchInfo, Call, Expr, ListLiteralElement, Proc, Stmt};
|
||||
use crate::ir::{
|
||||
BranchInfo, Call, Expr, ListLiteralElement, Proc, Stmt, UpdateModeId, UpdateModeIds,
|
||||
};
|
||||
use crate::layout::{Layout, TagIdIntType, UnionLayout};
|
||||
use bumpalo::collections::Vec;
|
||||
use bumpalo::Bump;
|
||||
@ -10,12 +12,14 @@ pub fn insert_reset_reuse<'a, 'i>(
|
||||
arena: &'a Bump,
|
||||
home: ModuleId,
|
||||
ident_ids: &'i mut IdentIds,
|
||||
update_mode_ids: &'i mut UpdateModeIds,
|
||||
mut proc: Proc<'a>,
|
||||
) -> Proc<'a> {
|
||||
let mut env = Env {
|
||||
arena,
|
||||
home,
|
||||
ident_ids,
|
||||
update_mode_ids,
|
||||
jp_live_vars: Default::default(),
|
||||
};
|
||||
|
||||
@ -50,6 +54,7 @@ struct Env<'a, 'i> {
|
||||
/// required for creating new `Symbol`s
|
||||
home: ModuleId,
|
||||
ident_ids: &'i mut IdentIds,
|
||||
update_mode_ids: &'i mut UpdateModeIds,
|
||||
|
||||
jp_live_vars: JPLiveVarMap,
|
||||
}
|
||||
@ -64,7 +69,7 @@ impl<'a, 'i> Env<'a, 'i> {
|
||||
|
||||
fn function_s<'a, 'i>(
|
||||
env: &mut Env<'a, 'i>,
|
||||
w: Symbol,
|
||||
w: Opportunity,
|
||||
c: &CtorInfo<'a>,
|
||||
stmt: &'a Stmt<'a>,
|
||||
) -> &'a Stmt<'a> {
|
||||
@ -84,7 +89,8 @@ fn function_s<'a, 'i>(
|
||||
let update_tag_id = true;
|
||||
|
||||
let new_expr = Expr::Reuse {
|
||||
symbol: w,
|
||||
symbol: w.symbol,
|
||||
update_mode: w.update_mode,
|
||||
update_tag_id,
|
||||
tag_layout: *tag_layout,
|
||||
tag_id: *tag_id,
|
||||
@ -175,13 +181,22 @@ fn function_s<'a, 'i>(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct Opportunity {
|
||||
symbol: Symbol,
|
||||
update_mode: UpdateModeId,
|
||||
}
|
||||
|
||||
fn try_function_s<'a, 'i>(
|
||||
env: &mut Env<'a, 'i>,
|
||||
x: Symbol,
|
||||
c: &CtorInfo<'a>,
|
||||
stmt: &'a Stmt<'a>,
|
||||
) -> &'a Stmt<'a> {
|
||||
let w = env.unique_symbol();
|
||||
let w = Opportunity {
|
||||
symbol: env.unique_symbol(),
|
||||
update_mode: env.update_mode_ids.next_id(),
|
||||
};
|
||||
|
||||
let new_stmt = function_s(env, w, c, stmt);
|
||||
|
||||
@ -194,7 +209,7 @@ fn try_function_s<'a, 'i>(
|
||||
|
||||
fn insert_reset<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
w: Symbol,
|
||||
w: Opportunity,
|
||||
x: Symbol,
|
||||
union_layout: UnionLayout<'a>,
|
||||
mut stmt: &'a Stmt<'a>,
|
||||
@ -216,16 +231,21 @@ fn insert_reset<'a>(
|
||||
| Array { .. }
|
||||
| EmptyArray
|
||||
| Reuse { .. }
|
||||
| Reset(_)
|
||||
| Reset { .. }
|
||||
| RuntimeErrorFunction(_) => break,
|
||||
}
|
||||
}
|
||||
|
||||
let reset_expr = Expr::Reset(x);
|
||||
let reset_expr = Expr::Reset {
|
||||
symbol: x,
|
||||
update_mode: w.update_mode,
|
||||
};
|
||||
|
||||
let layout = Layout::Union(union_layout);
|
||||
|
||||
stmt = env.arena.alloc(Stmt::Let(w, reset_expr, layout, stmt));
|
||||
stmt = env
|
||||
.arena
|
||||
.alloc(Stmt::Let(w.symbol, reset_expr, layout, stmt));
|
||||
|
||||
for (symbol, expr, expr_layout) in stack.into_iter().rev() {
|
||||
stmt = env
|
||||
@ -584,7 +604,7 @@ fn has_live_var_expr<'a>(expr: &'a Expr<'a>, needle: Symbol) -> bool {
|
||||
Expr::Reuse {
|
||||
symbol, arguments, ..
|
||||
} => needle == *symbol || arguments.iter().any(|s| *s == needle),
|
||||
Expr::Reset(symbol) => needle == *symbol,
|
||||
Expr::Reset { symbol, .. } => needle == *symbol,
|
||||
Expr::RuntimeErrorFunction(_) => false,
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ mod test_reporting {
|
||||
use crate::helpers::{can_expr, infer_expr, CanExprOut, ParseErrOut};
|
||||
use bumpalo::Bump;
|
||||
use roc_module::symbol::{Interns, ModuleId};
|
||||
use roc_mono::ir::{Procs, Stmt};
|
||||
use roc_mono::ir::{Procs, Stmt, UpdateModeIds};
|
||||
use roc_mono::layout::LayoutCache;
|
||||
use roc_reporting::report::{
|
||||
can_problem, mono_problem, parse_problem, type_problem, Report, Severity, BLUE_CODE,
|
||||
@ -91,6 +91,7 @@ mod test_reporting {
|
||||
// Compile and add all the Procs before adding main
|
||||
let mut procs = Procs::new_in(&arena);
|
||||
let mut ident_ids = interns.all_ident_ids.remove(&home).unwrap();
|
||||
let mut update_mode_ids = UpdateModeIds::new();
|
||||
|
||||
// Populate Procs and Subs, and get the low-level Expr from the canonical Expr
|
||||
let ptr_bytes = 8;
|
||||
@ -101,8 +102,8 @@ mod test_reporting {
|
||||
problems: &mut mono_problems,
|
||||
home,
|
||||
ident_ids: &mut ident_ids,
|
||||
update_mode_ids: &mut update_mode_ids,
|
||||
ptr_bytes,
|
||||
update_mode_counter: 0,
|
||||
// call_specialization_counter=0 is reserved
|
||||
call_specialization_counter: 1,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user