Merge pull request #5452 from JTeeuwissen/save-construction-children

Add construction (Struct/TagId/List/Box) to known parent/child relations
This commit is contained in:
Folkert de Vries 2023-05-29 22:21:44 +02:00 committed by GitHub
commit ef05ec6906
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 246 additions and 150 deletions

View file

@ -3115,7 +3115,6 @@ fn update<'a>(
&mut layout_interner,
module_id,
ident_ids,
state.target_info,
&mut state.procedures,
);

View file

@ -15,11 +15,10 @@ use bumpalo::collections::CollectIn;
use roc_module::low_level::LowLevel;
use roc_module::symbol::{IdentIds, ModuleId, Symbol};
use roc_target::TargetInfo;
use crate::ir::{
BranchInfo, Call, CallType, Expr, JoinPointId, Literal, ModifyRc, Proc, ProcLayout, Stmt,
UpdateModeId,
BranchInfo, Call, CallType, Expr, JoinPointId, ListLiteralElement, Literal, ModifyRc, Proc,
ProcLayout, Stmt, UpdateModeId,
};
use crate::layout::{
Builtin, InLayout, Layout, LayoutInterner, LayoutRepr, STLayoutInterner, UnionLayout,
@ -27,7 +26,7 @@ use crate::layout::{
use bumpalo::Bump;
use roc_collections::{MutMap, MutSet};
use roc_collections::MutMap;
/**
Try to find increments of symbols followed by decrements of the symbol they were indexed out of (their parent).
@ -38,12 +37,10 @@ pub fn specialize_drops<'a, 'i>(
layout_interner: &'i mut STLayoutInterner<'a>,
home: ModuleId,
ident_ids: &'i mut IdentIds,
target_info: TargetInfo,
procs: &mut MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>,
) {
for ((_symbol, proc_layout), proc) in procs.iter_mut() {
let mut environment =
DropSpecializationEnvironment::new(arena, home, proc_layout.result, target_info);
let mut environment = DropSpecializationEnvironment::new(arena, home, proc_layout.result);
specialize_drops_proc(arena, layout_interner, ident_ids, &mut environment, proc);
}
}
@ -104,7 +101,7 @@ fn specialize_drops_stmt<'a, 'i>(
_ => unreachable!("List get should have two arguments"),
};
environment.add_list_child(*structure, *binding, index);
environment.add_list_child_symbol(*structure, *binding, index);
alloc_let_with_continuation!(environment)
}
@ -114,9 +111,18 @@ fn specialize_drops_stmt<'a, 'i>(
RC::NoRc => alloc_let_with_continuation!(environment),
// We probably should not pass the increments to the continuation.
RC::Rc | RC::Uknown => {
let mut new_environment = environment.clone_without_incremented();
let incremented_symbols = environment.incremented_symbols.drain();
alloc_let_with_continuation!(&mut new_environment)
let new_stmt = alloc_let_with_continuation!(environment);
// The new_environment might have inserted increments that were set to 0 before. We need to add th
for (symbol, increment) in incremented_symbols.map.into_iter() {
environment
.incremented_symbols
.insert_count(symbol, increment);
}
new_stmt
}
},
_ => {
@ -127,16 +133,62 @@ fn specialize_drops_stmt<'a, 'i>(
// the parent might be deallocated before the function can use it.
// Thus forget everything about any increments.
let mut new_environment = environment.clone_without_incremented();
let incremented_symbols = environment.incremented_symbols.drain();
alloc_let_with_continuation!(&mut new_environment)
let new_stmt = alloc_let_with_continuation!(environment);
// The new_environment might have inserted increments that were set to 0 before. We need to add th
for (symbol, increment) in incremented_symbols.map.into_iter() {
environment
.incremented_symbols
.insert_count(symbol, increment);
}
new_stmt
}
}
}
Expr::Tag { tag_id, .. } => {
Expr::Tag {
tag_id,
arguments: children,
..
} => {
environment.symbol_tag.insert(*binding, *tag_id);
for (index, child) in children.iter().enumerate() {
environment.add_union_child(*binding, *child, *tag_id, index as u64);
}
alloc_let_with_continuation!(environment)
}
Expr::Struct(children) => {
for (index, child) in children.iter().enumerate() {
environment.add_struct_child(*binding, *child, index as u64);
}
alloc_let_with_continuation!(environment)
}
Expr::ExprBox { symbol: child } => {
environment.add_box_child(*binding, *child);
alloc_let_with_continuation!(environment)
}
Expr::Array {
elems: children, ..
} => {
for (index, child) in
children
.iter()
.enumerate()
.filter_map(|(index, child)| match child {
ListLiteralElement::Literal(_) => None,
ListLiteralElement::Symbol(s) => Some((index, s)),
})
{
environment.add_list_child(*binding, *child, index as u64);
}
alloc_let_with_continuation!(environment)
}
Expr::StructAtIndex {
@ -188,13 +240,10 @@ fn specialize_drops_stmt<'a, 'i>(
}
alloc_let_with_continuation!(environment)
}
Expr::Struct(_)
| Expr::RuntimeErrorFunction(_)
| Expr::ExprBox { .. }
Expr::RuntimeErrorFunction(_)
| Expr::NullPointer
| Expr::GetTagId { .. }
| Expr::EmptyArray
| Expr::Array { .. } => {
| Expr::EmptyArray => {
// Does nothing relevant to drop specialization. So we can just continue.
alloc_let_with_continuation!(environment)
}
@ -283,10 +332,12 @@ fn specialize_drops_stmt<'a, 'i>(
};
// Find the lowest symbol count for each symbol in each branch, and update the environment to match.
for (symbol, count) in environment.incremented_symbols.iter_mut() {
for (symbol, count) in environment.incremented_symbols.map.iter_mut() {
let consumed = branch_envs
.iter()
.map(|branch_env| branch_env.incremented_symbols.get(symbol).unwrap_or(&0))
.map(|branch_env| {
branch_env.incremented_symbols.map.get(symbol).unwrap_or(&0)
})
.min()
.unwrap();
@ -300,10 +351,14 @@ fn specialize_drops_stmt<'a, 'i>(
let symbol_differences =
environment
.incremented_symbols
.map
.iter()
.filter_map(|(symbol, count)| {
let branch_count =
$branch_env.incremented_symbols.get(symbol).unwrap_or(&0);
let branch_count = $branch_env
.incremented_symbols
.map
.get(symbol)
.unwrap_or(&0);
match branch_count - count {
0 => None,
@ -338,11 +393,6 @@ fn specialize_drops_stmt<'a, 'i>(
(info.clone(), new_branch)
};
// Remove all 0 counts as cleanup.
environment
.incremented_symbols
.retain(|_, count| *count > 0);
arena.alloc(Stmt::Switch {
cond_symbol: *cond_symbol,
cond_layout: *cond_layout,
@ -354,10 +404,12 @@ fn specialize_drops_stmt<'a, 'i>(
Stmt::Ret(symbol) => arena.alloc(Stmt::Ret(*symbol)),
Stmt::Refcounting(rc, continuation) => match rc {
ModifyRc::Inc(symbol, count) => {
let any = environment.any_incremented(symbol);
let inc_before = environment.incremented_symbols.contains(symbol);
// Add a symbol for every increment performed.
environment.add_incremented(*symbol, *count);
environment
.incremented_symbols
.insert_count(*symbol, *count);
let new_continuation = specialize_drops_stmt(
arena,
@ -367,12 +419,17 @@ fn specialize_drops_stmt<'a, 'i>(
continuation,
);
if any {
if inc_before {
// There were increments before this one, best to let the first one do the increments.
// Or there are no increments left, so we can just continue.
new_continuation
} else {
match environment.get_incremented(symbol) {
match environment
.incremented_symbols
.map
.remove(symbol)
.unwrap_or(0)
{
// This is the first increment, but all increments are consumed. So don't insert any.
0 => new_continuation,
// We still need to do some increments.
@ -393,7 +450,7 @@ fn specialize_drops_stmt<'a, 'i>(
// dec a
// dec b
if environment.pop_incremented(symbol) {
if environment.incremented_symbols.pop(symbol) {
// This decremented symbol was incremented before, so we can remove it.
specialize_drops_stmt(
arena,
@ -411,10 +468,10 @@ fn specialize_drops_stmt<'a, 'i>(
// As a might get dropped as a result of the decrement of b.
let mut incremented_children = {
let mut todo_children = bumpalo::vec![in arena; *symbol];
let mut incremented_children = MutSet::default();
let mut incremented_children = CountingMap::new();
while let Some(child) = todo_children.pop() {
if environment.pop_incremented(&child) {
if environment.incremented_symbols.pop(&child) {
incremented_children.insert(child);
} else {
todo_children.extend(environment.get_children(&child));
@ -485,8 +542,10 @@ fn specialize_drops_stmt<'a, 'i>(
};
// Add back the increments for the children to the environment.
for child_symbol in incremented_children.iter() {
environment.add_incremented(*child_symbol, 1)
for (child_symbol, symbol_count) in incremented_children.map.into_iter() {
environment
.incremented_symbols
.insert_count(child_symbol, symbol_count)
}
updated_stmt
@ -565,7 +624,8 @@ fn specialize_drops_stmt<'a, 'i>(
body,
remainder,
} => {
let mut new_environment = environment.clone_without_incremented();
let mut new_environment = environment.clone();
new_environment.incremented_symbols.clear();
for param in parameters.iter() {
new_environment.add_symbol_layout(param.symbol, param.layout);
@ -604,7 +664,7 @@ fn specialize_struct<'a, 'i>(
environment: &mut DropSpecializationEnvironment<'a>,
symbol: &Symbol,
struct_layout: &'a [InLayout],
incremented_children: &mut MutSet<Child>,
incremented_children: &mut CountingMap<Child>,
continuation: &'a Stmt<'a>,
) -> &'a Stmt<'a> {
match environment.struct_children.get(symbol) {
@ -620,7 +680,7 @@ fn specialize_struct<'a, 'i>(
for (index, _layout) in struct_layout.iter().enumerate() {
for (child, _i) in children_clone.iter().filter(|(_, i)| *i == index as u64) {
let removed = incremented_children.remove(child);
let removed = incremented_children.pop(child);
index_symbols.insert(index, (*child, removed));
if removed {
@ -693,7 +753,7 @@ fn specialize_union<'a, 'i>(
environment: &mut DropSpecializationEnvironment<'a>,
symbol: &Symbol,
union_layout: UnionLayout<'a>,
incremented_children: &mut MutSet<Child>,
incremented_children: &mut CountingMap<Child>,
continuation: &'a Stmt<'a>,
) -> &'a Stmt<'a> {
let current_tag = environment.symbol_tag.get(symbol).copied();
@ -736,7 +796,7 @@ fn specialize_union<'a, 'i>(
{
debug_assert_eq!(tag, *t);
let removed = incremented_children.remove(child);
let removed = incremented_children.pop(child);
index_symbols.insert(index, (*child, removed));
if removed {
@ -898,14 +958,14 @@ fn specialize_boxed<'a, 'i>(
layout_interner: &'i mut STLayoutInterner<'a>,
ident_ids: &'i mut IdentIds,
environment: &mut DropSpecializationEnvironment<'a>,
incremented_children: &mut MutSet<Child>,
incremented_children: &mut CountingMap<Child>,
symbol: &Symbol,
continuation: &'a Stmt<'a>,
) -> &'a Stmt<'a> {
let removed = match incremented_children.iter().next() {
Some(s) => {
let removed = match incremented_children.map.iter().next() {
Some((s, _)) => {
let s = *s;
incremented_children.remove(&s);
incremented_children.pop(&s);
Some(s)
}
None => None,
@ -924,23 +984,20 @@ fn specialize_boxed<'a, 'i>(
*symbol,
// If the symbol is unique:
// - free the box
|_, _, _| {
|_, _, continuation| {
arena.alloc(Stmt::Refcounting(
// TODO can be replaced by free if ever added to the IR.
ModifyRc::DecRef(*symbol),
new_continuation,
continuation,
))
},
// If the symbol is not unique:
// - increment the child
// - decref the box
|_, _, _| {
|_, _, continuation| {
arena.alloc(Stmt::Refcounting(
ModifyRc::Inc(s, 1),
arena.alloc(Stmt::Refcounting(
ModifyRc::DecRef(*symbol),
new_continuation,
)),
arena.alloc(Stmt::Refcounting(ModifyRc::DecRef(*symbol), continuation)),
))
},
new_continuation,
@ -958,7 +1015,7 @@ fn specialize_list<'a, 'i>(
layout_interner: &'i mut STLayoutInterner<'a>,
ident_ids: &'i mut IdentIds,
environment: &mut DropSpecializationEnvironment<'a>,
incremented_children: &mut MutSet<Child>,
incremented_children: &mut CountingMap<Child>,
symbol: &Symbol,
item_layout: InLayout,
continuation: &'a Stmt<'a>,
@ -993,7 +1050,7 @@ fn specialize_list<'a, 'i>(
for (child, i) in children_clone.iter().filter(|(_child, i)| *i == index) {
debug_assert!(length > *i);
let removed = incremented_children.remove(child);
let removed = incremented_children.pop(child);
index_symbols.insert(index, (*child, removed));
if removed {
@ -1214,7 +1271,6 @@ struct DropSpecializationEnvironment<'a> {
arena: &'a Bump,
home: ModuleId,
layout: InLayout<'a>,
target_info: TargetInfo,
symbol_layouts: MutMap<Symbol, InLayout<'a>>,
@ -1231,7 +1287,7 @@ struct DropSpecializationEnvironment<'a> {
list_children: MutMap<Parent, Vec<'a, (Child, Index)>>,
// Keeps track of all incremented symbols.
incremented_symbols: MutMap<Symbol, u64>,
incremented_symbols: CountingMap<Symbol>,
// Map containing the current known tag of a layout.
symbol_tag: MutMap<Symbol, Tag>,
@ -1244,42 +1300,23 @@ struct DropSpecializationEnvironment<'a> {
}
impl<'a> DropSpecializationEnvironment<'a> {
fn new(arena: &'a Bump, home: ModuleId, layout: InLayout<'a>, target_info: TargetInfo) -> Self {
fn new(arena: &'a Bump, home: ModuleId, layout: InLayout<'a>) -> Self {
Self {
arena,
home,
layout,
target_info,
symbol_layouts: MutMap::default(),
struct_children: MutMap::default(),
union_children: MutMap::default(),
box_children: MutMap::default(),
list_children: MutMap::default(),
incremented_symbols: MutMap::default(),
incremented_symbols: CountingMap::new(),
symbol_tag: MutMap::default(),
symbol_index: MutMap::default(),
list_length: MutMap::default(),
}
}
fn clone_without_incremented(&self) -> Self {
Self {
arena: self.arena,
home: self.home,
layout: self.layout,
target_info: self.target_info,
symbol_layouts: self.symbol_layouts.clone(),
struct_children: self.struct_children.clone(),
union_children: self.union_children.clone(),
box_children: self.box_children.clone(),
list_children: self.list_children.clone(),
incremented_symbols: MutMap::default(),
symbol_tag: self.symbol_tag.clone(),
symbol_index: self.symbol_index.clone(),
list_length: self.list_length.clone(),
}
}
fn create_symbol<'i>(&self, ident_ids: &'i mut IdentIds, debug_name: &str) -> Symbol {
let ident_id = ident_ids.add_str(debug_name);
Symbol::new(self.home, ident_id)
@ -1316,12 +1353,16 @@ impl<'a> DropSpecializationEnvironment<'a> {
.push(child);
}
fn add_list_child(&mut self, parent: Parent, child: Child, index: &Symbol) {
fn add_list_child(&mut self, parent: Parent, child: Child, index: u64) {
self.list_children
.entry(parent)
.or_insert_with(|| Vec::new_in(self.arena))
.push((child, index));
}
fn add_list_child_symbol(&mut self, parent: Parent, child: Child, index: &Symbol) {
if let Some(index) = self.symbol_index.get(index) {
self.list_children
.entry(parent)
.or_insert_with(|| Vec::new_in(self.arena))
.push((child, *index));
self.add_list_child(parent, child, *index)
}
}
@ -1346,39 +1387,6 @@ impl<'a> DropSpecializationEnvironment<'a> {
res
}
/**
Add a symbol for every increment performed.
*/
fn add_incremented(&mut self, symbol: Symbol, count: u64) {
self.incremented_symbols
.entry(symbol)
.and_modify(|c| *c += count)
.or_insert(count);
}
fn any_incremented(&self, symbol: &Symbol) -> bool {
self.incremented_symbols.contains_key(symbol)
}
/**
Return the amount of times a symbol still has to be incremented.
Accounting for later consumtion and removal of the increment.
*/
fn get_incremented(&mut self, symbol: &Symbol) -> u64 {
self.incremented_symbols.remove(symbol).unwrap_or(0)
}
fn pop_incremented(&mut self, symbol: &Symbol) -> bool {
match self.incremented_symbols.get_mut(symbol) {
Some(0) => false,
Some(c) => {
*c -= 1;
true
}
None => false,
}
}
}
/**
@ -1490,3 +1498,59 @@ fn low_level_no_rc(lowlevel: &LowLevel) -> RC {
}
}
}
/// Map that contains a count for each key.
/// Keys with a count of 0 are kept around, so that it can be seen that they were once present.
#[derive(Clone)]
struct CountingMap<K> {
map: MutMap<K, u64>,
}
impl<K> CountingMap<K>
where
K: Eq + std::hash::Hash + Clone,
{
fn new() -> Self {
Self {
map: MutMap::default(),
}
}
fn insert(&mut self, key: K) {
self.insert_count(key, 1);
}
fn insert_count(&mut self, key: K, count: u64) {
self.map
.entry(key)
.and_modify(|c| *c += count)
.or_insert(count);
}
fn pop(&mut self, key: &K) -> bool {
match self.map.get_mut(key) {
Some(0) => false,
Some(c) => {
*c -= 1;
true
}
None => false,
}
}
fn contains(&self, symbol: &K) -> bool {
self.map.contains_key(symbol)
}
fn drain(&mut self) -> Self {
let res = self.clone();
for (_, v) in self.map.iter_mut() {
*v = 0;
}
res
}
fn clear(&mut self) {
self.map.clear();
}
}

View file

@ -0,0 +1,6 @@
procedure Test.0 ():
let Test.2 : Str = "value";
let Test.3 : {Str, Str} = Struct {Test.2, Test.2};
dec Test.2;
let Test.4 : Str = "result";
ret Test.4;

View file

@ -697,8 +697,8 @@ procedure Json.25 (Json.183):
let Json.1906 : List U8 = CallByName List.8 Json.1907 Json.1908;
ret Json.1906;
else
let Json.1948 : U64 = StructAtIndex 0 Json.186;
inc Json.184;
let Json.1948 : U64 = StructAtIndex 0 Json.186;
let Json.1947 : {List U8, List U8} = CallByName List.52 Json.184 Json.1948;
let Json.210 : List U8 = StructAtIndex 0 Json.1947;
let Json.212 : List U8 = StructAtIndex 1 Json.1947;

View file

@ -623,8 +623,8 @@ procedure Json.25 (Json.183):
let Json.1532 : List U8 = CallByName List.8 Json.1533 Json.1534;
ret Json.1532;
else
let Json.1574 : U64 = StructAtIndex 0 Json.186;
inc Json.184;
let Json.1574 : U64 = StructAtIndex 0 Json.186;
let Json.1573 : {List U8, List U8} = CallByName List.52 Json.184 Json.1574;
let Json.210 : List U8 = StructAtIndex 0 Json.1573;
let Json.212 : List U8 = StructAtIndex 1 Json.1573;

View file

@ -630,8 +630,8 @@ procedure Json.25 (Json.183):
let Json.1532 : List U8 = CallByName List.8 Json.1533 Json.1534;
ret Json.1532;
else
let Json.1574 : U64 = StructAtIndex 0 Json.186;
inc Json.184;
let Json.1574 : U64 = StructAtIndex 0 Json.186;
let Json.1573 : {List U8, List U8} = CallByName List.52 Json.184 Json.1574;
let Json.210 : List U8 = StructAtIndex 0 Json.1573;
let Json.212 : List U8 = StructAtIndex 1 Json.1573;

View file

@ -118,8 +118,8 @@ procedure Json.25 (Json.183):
let Json.1179 : List U8 = CallByName List.8 Json.1180 Json.1181;
ret Json.1179;
else
let Json.1221 : U64 = StructAtIndex 0 Json.186;
inc Json.184;
let Json.1221 : U64 = StructAtIndex 0 Json.186;
let Json.1220 : {List U8, List U8} = CallByName List.52 Json.184 Json.1221;
let Json.210 : List U8 = StructAtIndex 0 Json.1220;
let Json.212 : List U8 = StructAtIndex 1 Json.1220;

View file

@ -147,8 +147,8 @@ procedure Json.25 (Json.183):
let Json.1220 : List U8 = CallByName List.8 Json.1221 Json.1222;
ret Json.1220;
else
let Json.1262 : U64 = StructAtIndex 0 Json.186;
inc Json.184;
let Json.1262 : U64 = StructAtIndex 0 Json.186;
let Json.1261 : {List U8, List U8} = CallByName List.52 Json.184 Json.1262;
let Json.210 : List U8 = StructAtIndex 0 Json.1261;
let Json.212 : List U8 = StructAtIndex 1 Json.1261;

View file

@ -150,8 +150,8 @@ procedure Json.25 (Json.183):
let Json.1220 : List U8 = CallByName List.8 Json.1221 Json.1222;
ret Json.1220;
else
let Json.1262 : U64 = StructAtIndex 0 Json.186;
inc Json.184;
let Json.1262 : U64 = StructAtIndex 0 Json.186;
let Json.1261 : {List U8, List U8} = CallByName List.52 Json.184 Json.1262;
let Json.210 : List U8 = StructAtIndex 0 Json.1261;
let Json.212 : List U8 = StructAtIndex 1 Json.1261;

View file

@ -179,8 +179,8 @@ procedure Json.60 (Json.540):
let Json.1336 : U8 = GetTagId Json.1327;
let Json.1337 : Int1 = lowlevel Eq Json.1335 Json.1336;
if Json.1337 then
let Json.542 : U64 = UnionAtIndex (Id 2) (Index 0) Json.1327;
inc Json.540;
let Json.542 : U64 = UnionAtIndex (Id 2) (Index 0) Json.1327;
let Json.1329 : List U8 = CallByName List.29 Json.540 Json.542;
let Json.1332 : U64 = 0i64;
let Json.1331 : {U64, U64} = Struct {Json.542, Json.1332};
@ -532,18 +532,15 @@ procedure Json.68 ():
procedure Json.69 (Json.1467):
joinpoint Json.1197 Json.1165:
let Json.599 : List U8 = StructAtIndex 0 Json.1165;
inc Json.599;
inc 4 Json.599;
let Json.600 : List U8 = StructAtIndex 1 Json.1165;
let Json.1315 : U64 = 0i64;
let Json.601 : [C {}, C U8] = CallByName List.2 Json.599 Json.1315;
let Json.1314 : U64 = 1i64;
inc Json.599;
let Json.602 : [C {}, C U8] = CallByName List.2 Json.599 Json.1314;
let Json.1313 : U64 = 2i64;
inc Json.599;
let Json.603 : List U8 = CallByName List.29 Json.599 Json.1313;
let Json.1312 : U64 = 6i64;
inc Json.599;
let Json.604 : List U8 = CallByName List.29 Json.599 Json.1312;
let Json.1198 : {[C {}, C U8], [C {}, C U8]} = Struct {Json.601, Json.602};
joinpoint Json.1277:
@ -832,7 +829,7 @@ procedure Test.3 ():
let Test.7 : Str = "Roc";
let Test.6 : [C [C List U8, C ], C Str] = TagId(1) Test.7;
let Test.5 : Int1 = CallByName Bool.11 Test.1 Test.6;
dec Test.6;
dec Test.7;
expect Test.5;
dec Test.0;
dec Test.1;

View file

@ -153,8 +153,8 @@ procedure Json.60 (Json.540):
let Json.1336 : U8 = GetTagId Json.1327;
let Json.1337 : Int1 = lowlevel Eq Json.1335 Json.1336;
if Json.1337 then
let Json.542 : U64 = UnionAtIndex (Id 2) (Index 0) Json.1327;
inc Json.540;
let Json.542 : U64 = UnionAtIndex (Id 2) (Index 0) Json.1327;
let Json.1329 : List U8 = CallByName List.29 Json.540 Json.542;
let Json.1332 : U64 = 0i64;
let Json.1331 : {U64, U64} = Struct {Json.542, Json.1332};
@ -506,18 +506,15 @@ procedure Json.68 ():
procedure Json.69 (Json.1467):
joinpoint Json.1197 Json.1165:
let Json.599 : List U8 = StructAtIndex 0 Json.1165;
inc Json.599;
inc 4 Json.599;
let Json.600 : List U8 = StructAtIndex 1 Json.1165;
let Json.1315 : U64 = 0i64;
let Json.601 : [C {}, C U8] = CallByName List.2 Json.599 Json.1315;
let Json.1314 : U64 = 1i64;
inc Json.599;
let Json.602 : [C {}, C U8] = CallByName List.2 Json.599 Json.1314;
let Json.1313 : U64 = 2i64;
inc Json.599;
let Json.603 : List U8 = CallByName List.29 Json.599 Json.1313;
let Json.1312 : U64 = 6i64;
inc Json.599;
let Json.604 : List U8 = CallByName List.29 Json.599 Json.1312;
let Json.1198 : {[C {}, C U8], [C {}, C U8]} = Struct {Json.601, Json.602};
joinpoint Json.1277:
@ -865,7 +862,7 @@ procedure Test.12 ():
let Test.16 : {List U8, I64} = Struct {Test.17, Test.18};
let Test.15 : [C Str, C {List U8, I64}] = TagId(1) Test.16;
let Test.14 : Int1 = CallByName Bool.11 Test.10 Test.15;
dec Test.15;
dec Test.16;
expect Test.14;
dec Test.10;
let Test.13 : {} = Struct {};

View file

@ -5,7 +5,8 @@ procedure Test.0 ():
let Test.9 : U64 = 1i64;
let Test.10 : Int1 = lowlevel Eq Test.8 Test.9;
if Test.10 then
dec Test.1;
dec Test.11;
decref Test.1;
let Test.3 : Str = "B";
ret Test.3;
else

View file

@ -5,11 +5,20 @@ procedure Test.0 ():
let Test.2 : [<rnu><null>, C *self] = TagId(0) Test.13;
let Test.10 : U8 = 1i64;
let Test.11 : U8 = GetTagId Test.2;
dec Test.2;
let Test.12 : Int1 = lowlevel Eq Test.10 Test.11;
if Test.12 then
let Test.8 : I64 = 0i64;
ret Test.8;
joinpoint #Derived_gen.0:
let Test.12 : Int1 = lowlevel Eq Test.10 Test.11;
if Test.12 then
let Test.8 : I64 = 0i64;
ret Test.8;
else
let Test.9 : I64 = 1i64;
ret Test.9;
in
let #Derived_gen.1 : Int1 = lowlevel RefCountIsUnique Test.2;
if #Derived_gen.1 then
dec Test.13;
decref Test.2;
jump #Derived_gen.0;
else
let Test.9 : I64 = 1i64;
ret Test.9;
decref Test.2;
jump #Derived_gen.0;

View file

@ -30,6 +30,15 @@ procedure Test.0 ():
let Test.16 : Str = "";
let Test.15 : [<r>C List *self, C Str] = TagId(1) Test.16;
let Test.13 : Int1 = CallByName Bool.11 Test.14 Test.15;
dec Test.15;
dec Test.14;
ret Test.13;
joinpoint #Derived_gen.0:
dec Test.14;
ret Test.13;
in
let #Derived_gen.1 : Int1 = lowlevel RefCountIsUnique Test.15;
if #Derived_gen.1 then
dec Test.16;
decref Test.15;
jump #Derived_gen.0;
else
decref Test.15;
jump #Derived_gen.0;

View file

@ -45,10 +45,9 @@ procedure Num.22 (#Attr.2, #Attr.3):
procedure Test.1 (Test.2):
let Test.28 : U64 = 0i64;
inc Test.2;
inc 2 Test.2;
let Test.26 : [C {}, C I64] = CallByName List.2 Test.2 Test.28;
let Test.27 : U64 = 0i64;
inc Test.2;
let Test.25 : [C {}, C I64] = CallByName List.2 Test.2 Test.27;
let Test.8 : {[C {}, C I64], [C {}, C I64]} = Struct {Test.25, Test.26};
joinpoint Test.22:

View file

@ -44,9 +44,8 @@ procedure Num.22 (#Attr.2, #Attr.3):
ret Num.283;
procedure Test.1 (Test.2, Test.3, Test.4):
inc Test.4;
inc 2 Test.4;
let Test.29 : [C {}, C I64] = CallByName List.2 Test.4 Test.3;
inc Test.4;
let Test.28 : [C {}, C I64] = CallByName List.2 Test.4 Test.2;
let Test.13 : {[C {}, C I64], [C {}, C I64]} = Struct {Test.28, Test.29};
joinpoint Test.25:

View file

@ -136,8 +136,8 @@ procedure Json.25 (Json.183):
let Json.1223 : List U8 = CallByName List.8 Json.1224 Json.1225;
ret Json.1223;
else
let Json.1265 : U64 = StructAtIndex 0 Json.186;
inc Json.184;
let Json.1265 : U64 = StructAtIndex 0 Json.186;
let Json.1264 : {List U8, List U8} = CallByName List.52 Json.184 Json.1265;
let Json.210 : List U8 = StructAtIndex 0 Json.1264;
let Json.212 : List U8 = StructAtIndex 1 Json.1264;

View file

@ -3050,3 +3050,19 @@ fn specialize_after_match() {
"#
)
}
#[mono_test]
fn drop_specialize_after_struct() {
indoc!(
r#"
app "test" provides [main] to "./platform"
Tuple a b : { left : a, right : b }
main =
v = "value"
t = { left: v, right: v }
"result"
"#
)
}