Merge pull request #5622 from roc-lang/reset-reuse-free

free or reuse unconditionally when value is unique
This commit is contained in:
Richard Feldman 2023-06-28 09:58:10 -04:00 committed by GitHub
commit 0ade2a85d2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
37 changed files with 583 additions and 295 deletions

View file

@ -510,6 +510,12 @@ fn apply_refcount_operation(
builder.add_recursive_touch(block, argument)?; builder.add_recursive_touch(block, argument)?;
} }
ModifyRc::DecRef(symbol) => { ModifyRc::DecRef(symbol) => {
// this is almost certainly suboptimal, but not incorrect
let argument = env.symbols[symbol];
builder.add_recursive_touch(block, argument)?;
}
ModifyRc::Free(symbol) => {
// this is almost certainly suboptimal, but not incorrect
let argument = env.symbols[symbol]; let argument = env.symbols[symbol];
builder.add_recursive_touch(block, argument)?; builder.add_recursive_touch(block, argument)?;
} }

View file

@ -195,8 +195,10 @@ comptime {
exportUtilsFn(utils.test_panic, "test_panic"); exportUtilsFn(utils.test_panic, "test_panic");
exportUtilsFn(utils.increfRcPtrC, "incref_rc_ptr"); exportUtilsFn(utils.increfRcPtrC, "incref_rc_ptr");
exportUtilsFn(utils.decrefRcPtrC, "decref_rc_ptr"); exportUtilsFn(utils.decrefRcPtrC, "decref_rc_ptr");
exportUtilsFn(utils.freeRcPtrC, "free_rc_ptr");
exportUtilsFn(utils.increfDataPtrC, "incref_data_ptr"); exportUtilsFn(utils.increfDataPtrC, "incref_data_ptr");
exportUtilsFn(utils.decrefDataPtrC, "decref_data_ptr"); exportUtilsFn(utils.decrefDataPtrC, "decref_data_ptr");
exportUtilsFn(utils.freeDataPtrC, "free_data_ptr");
exportUtilsFn(utils.isUnique, "is_unique"); exportUtilsFn(utils.isUnique, "is_unique");
exportUtilsFn(utils.decrefCheckNullC, "decref_check_null"); exportUtilsFn(utils.decrefCheckNullC, "decref_check_null");
exportUtilsFn(utils.allocateWithRefcountC, "allocate_with_refcount"); exportUtilsFn(utils.allocateWithRefcountC, "allocate_with_refcount");

View file

@ -220,6 +220,29 @@ pub fn increfDataPtrC(
return increfRcPtrC(isizes, inc_amount); return increfRcPtrC(isizes, inc_amount);
} }
pub fn freeDataPtrC(
bytes_or_null: ?[*]isize,
alignment: u32,
) callconv(.C) void {
var bytes = bytes_or_null orelse return;
const ptr = @ptrToInt(bytes);
const tag_mask: usize = if (@sizeOf(usize) == 8) 0b111 else 0b11;
const masked_ptr = ptr & ~tag_mask;
const isizes: [*]isize = @intToPtr([*]isize, masked_ptr);
return freeRcPtrC(isizes - 1, alignment);
}
pub fn freeRcPtrC(
bytes_or_null: ?[*]isize,
alignment: u32,
) callconv(.C) void {
var bytes = bytes_or_null orelse return;
return free_ptr_to_refcount(bytes, alignment);
}
pub fn decref( pub fn decref(
bytes_or_null: ?[*]u8, bytes_or_null: ?[*]u8,
data_bytes: usize, data_bytes: usize,
@ -236,13 +259,23 @@ pub fn decref(
decref_ptr_to_refcount(isizes - 1, alignment); decref_ptr_to_refcount(isizes - 1, alignment);
} }
inline fn decref_ptr_to_refcount( inline fn free_ptr_to_refcount(
refcount_ptr: [*]isize, refcount_ptr: [*]isize,
alignment: u32, alignment: u32,
) void { ) void {
if (RC_TYPE == Refcount.none) return; if (RC_TYPE == Refcount.none) return;
const extra_bytes = std.math.max(alignment, @sizeOf(usize)); const extra_bytes = std.math.max(alignment, @sizeOf(usize));
// NOTE: we don't even check whether the refcount is "infinity" here!
dealloc(@ptrCast([*]u8, refcount_ptr) - (extra_bytes - @sizeOf(usize)), alignment);
}
inline fn decref_ptr_to_refcount(
refcount_ptr: [*]isize,
alignment: u32,
) void {
if (RC_TYPE == Refcount.none) return;
if (DEBUG_INCDEC and builtin.target.cpu.arch != .wasm32) { if (DEBUG_INCDEC and builtin.target.cpu.arch != .wasm32) {
std.debug.print("| decrement {*}: ", .{refcount_ptr}); std.debug.print("| decrement {*}: ", .{refcount_ptr});
} }
@ -264,13 +297,13 @@ inline fn decref_ptr_to_refcount(
} }
if (refcount == REFCOUNT_ONE_ISIZE) { if (refcount == REFCOUNT_ONE_ISIZE) {
dealloc(@ptrCast([*]u8, refcount_ptr) - (extra_bytes - @sizeOf(usize)), alignment); free_ptr_to_refcount(refcount_ptr, alignment);
} }
}, },
Refcount.atomic => { Refcount.atomic => {
var last = @atomicRmw(isize, &refcount_ptr[0], std.builtin.AtomicRmwOp.Sub, 1, Monotonic); var last = @atomicRmw(isize, &refcount_ptr[0], std.builtin.AtomicRmwOp.Sub, 1, Monotonic);
if (last == REFCOUNT_ONE_ISIZE) { if (last == REFCOUNT_ONE_ISIZE) {
dealloc(@ptrCast([*]u8, refcount_ptr) - (extra_bytes - @sizeOf(usize)), alignment); free_ptr_to_refcount(refcount_ptr, alignment);
} }
}, },
Refcount.none => unreachable, Refcount.none => unreachable,

View file

@ -393,8 +393,10 @@ pub const UTILS_TEST_PANIC: &str = "roc_builtins.utils.test_panic";
pub const UTILS_ALLOCATE_WITH_REFCOUNT: &str = "roc_builtins.utils.allocate_with_refcount"; pub const UTILS_ALLOCATE_WITH_REFCOUNT: &str = "roc_builtins.utils.allocate_with_refcount";
pub const UTILS_INCREF_RC_PTR: &str = "roc_builtins.utils.incref_rc_ptr"; pub const UTILS_INCREF_RC_PTR: &str = "roc_builtins.utils.incref_rc_ptr";
pub const UTILS_DECREF_RC_PTR: &str = "roc_builtins.utils.decref_rc_ptr"; pub const UTILS_DECREF_RC_PTR: &str = "roc_builtins.utils.decref_rc_ptr";
pub const UTILS_FREE_RC_PTR: &str = "roc_builtins.utils.free_rc_ptr";
pub const UTILS_INCREF_DATA_PTR: &str = "roc_builtins.utils.incref_data_ptr"; pub const UTILS_INCREF_DATA_PTR: &str = "roc_builtins.utils.incref_data_ptr";
pub const UTILS_DECREF_DATA_PTR: &str = "roc_builtins.utils.decref_data_ptr"; pub const UTILS_DECREF_DATA_PTR: &str = "roc_builtins.utils.decref_data_ptr";
pub const UTILS_FREE_DATA_PTR: &str = "roc_builtins.utils.free_data_ptr";
pub const UTILS_IS_UNIQUE: &str = "roc_builtins.utils.is_unique"; pub const UTILS_IS_UNIQUE: &str = "roc_builtins.utils.is_unique";
pub const UTILS_DECREF_CHECK_NULL: &str = "roc_builtins.utils.decref_check_null"; pub const UTILS_DECREF_CHECK_NULL: &str = "roc_builtins.utils.decref_check_null";
pub const UTILS_DICT_PSEUDO_SEED: &str = "roc_builtins.utils.dict_pseudo_seed"; pub const UTILS_DICT_PSEUDO_SEED: &str = "roc_builtins.utils.dict_pseudo_seed";

View file

@ -87,6 +87,7 @@ macro_rules! map_symbol_to_lowlevel_and_arity {
LowLevel::PtrCast => unimplemented!(), LowLevel::PtrCast => unimplemented!(),
LowLevel::PtrStore => unimplemented!(), LowLevel::PtrStore => unimplemented!(),
LowLevel::PtrLoad => unimplemented!(), LowLevel::PtrLoad => unimplemented!(),
LowLevel::PtrClearTagId => unimplemented!(),
LowLevel::Alloca => unimplemented!(), LowLevel::Alloca => unimplemented!(),
LowLevel::RefCountIncRcPtr => unimplemented!(), LowLevel::RefCountIncRcPtr => unimplemented!(),
LowLevel::RefCountDecRcPtr=> unimplemented!(), LowLevel::RefCountDecRcPtr=> unimplemented!(),

View file

@ -2996,12 +2996,17 @@ impl<
); );
} }
fn build_ptr_to_stack_value( fn build_ptr_clear_tag_id(&mut self, sym: Symbol, ptr: Symbol) {
&mut self, let buf = &mut self.buf;
sym: Symbol,
value: Symbol, let ptr_reg = self.storage_manager.load_to_general_reg(buf, &ptr);
element_layout: InLayout<'a>, let sym_reg = self.storage_manager.claim_general_reg(buf, &sym);
) {
ASM::mov_reg64_imm64(buf, sym_reg, !0b111);
ASM::and_reg64_reg64_reg64(buf, sym_reg, sym_reg, ptr_reg);
}
fn build_alloca(&mut self, sym: Symbol, value: Symbol, element_layout: InLayout<'a>) {
// 1. acquire some stack space // 1. acquire some stack space
let element_width = self.interner().stack_size(element_layout); let element_width = self.interner().stack_size(element_layout);
let allocation = self.debug_symbol("stack_allocation"); let allocation = self.debug_symbol("stack_allocation");

View file

@ -17,7 +17,7 @@ use roc_module::symbol::{Interns, ModuleId, Symbol};
use roc_mono::code_gen_help::{CallerProc, CodeGenHelp}; use roc_mono::code_gen_help::{CallerProc, CodeGenHelp};
use roc_mono::ir::{ use roc_mono::ir::{
BranchInfo, CallType, CrashTag, Expr, HigherOrderLowLevel, JoinPointId, ListLiteralElement, BranchInfo, CallType, CrashTag, Expr, HigherOrderLowLevel, JoinPointId, ListLiteralElement,
Literal, Param, Proc, ProcLayout, SelfRecursive, Stmt, Literal, ModifyRc, Param, Proc, ProcLayout, SelfRecursive, Stmt,
}; };
use roc_mono::layout::{ use roc_mono::layout::{
Builtin, InLayout, LambdaName, Layout, LayoutIds, LayoutInterner, LayoutRepr, STLayoutInterner, Builtin, InLayout, LambdaName, Layout, LayoutIds, LayoutInterner, LayoutRepr, STLayoutInterner,
@ -525,6 +525,29 @@ trait Backend<'a> {
self.return_symbol(sym, ret_layout); self.return_symbol(sym, ret_layout);
self.free_symbols(stmt); self.free_symbols(stmt);
} }
Stmt::Refcounting(ModifyRc::Free(symbol), following) => {
let dst = Symbol::DEV_TMP;
let layout = *self.layout_map().get(symbol).unwrap();
let alignment_bytes = self.interner().allocation_alignment_bytes(layout);
let alignment = self.debug_symbol("alignment");
self.load_literal_i32(&alignment, alignment_bytes as i32);
// NOTE: UTILS_FREE_DATA_PTR clears any tag id bits
self.build_fn_call(
&dst,
bitcode::UTILS_FREE_DATA_PTR.to_string(),
&[*symbol, alignment],
&[Layout::I64, Layout::I32],
&Layout::UNIT,
);
self.free_symbol(&dst);
self.free_symbol(&alignment);
self.build_stmt(layout_ids, following, ret_layout)
}
Stmt::Refcounting(modify, following) => { Stmt::Refcounting(modify, following) => {
let sym = modify.get_symbol(); let sym = modify.get_symbol();
let layout = *self.layout_map().get(&sym).unwrap(); let layout = *self.layout_map().get(&sym).unwrap();
@ -1605,8 +1628,12 @@ trait Backend<'a> {
self.build_ptr_load(*sym, args[0], *ret_layout); self.build_ptr_load(*sym, args[0], *ret_layout);
} }
LowLevel::PtrClearTagId => {
self.build_ptr_clear_tag_id(*sym, args[0]);
}
LowLevel::Alloca => { LowLevel::Alloca => {
self.build_ptr_to_stack_value(*sym, args[0], arg_layouts[0]); self.build_alloca(*sym, args[0], arg_layouts[0]);
} }
LowLevel::RefCountDecRcPtr => self.build_fn_call( LowLevel::RefCountDecRcPtr => self.build_fn_call(
@ -2247,12 +2274,9 @@ trait Backend<'a> {
fn build_ptr_load(&mut self, sym: Symbol, ptr: Symbol, element_layout: InLayout<'a>); fn build_ptr_load(&mut self, sym: Symbol, ptr: Symbol, element_layout: InLayout<'a>);
fn build_ptr_to_stack_value( fn build_ptr_clear_tag_id(&mut self, sym: Symbol, ptr: Symbol);
&mut self,
sym: Symbol, fn build_alloca(&mut self, sym: Symbol, value: Symbol, element_layout: InLayout<'a>);
value: Symbol,
element_layout: InLayout<'a>,
);
/// literal_map gets the map from symbol to literal and layout, used for lazy loading and literal folding. /// literal_map gets the map from symbol to literal and layout, used for lazy loading and literal folding.
fn literal_map(&mut self) -> &mut MutMap<Symbol, (*const Literal<'a>, *const InLayout<'a>)>; fn literal_map(&mut self) -> &mut MutMap<Symbol, (*const Literal<'a>, *const InLayout<'a>)>;

View file

@ -1180,8 +1180,14 @@ pub(crate) fn build_exp_expr<'a, 'ctx>(
let then_block = ctx.append_basic_block(parent, "then_reset"); let then_block = ctx.append_basic_block(parent, "then_reset");
let else_block = ctx.append_basic_block(parent, "else_decref"); let else_block = ctx.append_basic_block(parent, "else_decref");
let refcount_ptr = let refcount_ptr = PointerToRefcount::from_ptr_to_data(
PointerToRefcount::from_ptr_to_data(env, tag_pointer_clear_tag_id(env, tag_ptr)); env,
if union_layout.stores_tag_id_in_pointer(env.target_info) {
tag_pointer_clear_tag_id(env, tag_ptr)
} else {
tag_ptr
},
);
let is_unique = match update_mode { let is_unique = match update_mode {
UpdateMode::InPlace => env.context.bool_type().const_int(1, false), UpdateMode::InPlace => env.context.bool_type().const_int(1, false),
@ -1265,8 +1271,20 @@ pub(crate) fn build_exp_expr<'a, 'ctx>(
let not_unique_block = ctx.append_basic_block(parent, "else_decref"); let not_unique_block = ctx.append_basic_block(parent, "else_decref");
let refcount_ptr = // reset is only generated for union values
PointerToRefcount::from_ptr_to_data(env, tag_pointer_clear_tag_id(env, tag_ptr)); let union_layout = match layout_interner.get_repr(layout) {
LayoutRepr::Union(ul) => ul,
_ => unreachable!(),
};
let refcount_ptr = PointerToRefcount::from_ptr_to_data(
env,
if union_layout.stores_tag_id_in_pointer(env.target_info) {
tag_pointer_clear_tag_id(env, tag_ptr)
} else {
tag_ptr
},
);
let is_unique = match update_mode { let is_unique = match update_mode {
UpdateMode::InPlace => env.context.bool_type().const_int(1, false), UpdateMode::InPlace => env.context.bool_type().const_int(1, false),
@ -2930,6 +2948,39 @@ pub(crate) fn build_exp_stmt<'a, 'ctx>(
cont, cont,
) )
} }
Free(symbol) => {
// unconditionally deallocate the symbol
let (value, layout) = scope.load_symbol_and_layout(symbol);
let alignment = layout_interner.alignment_bytes(layout);
debug_assert!(value.is_pointer_value());
let value = value.into_pointer_value();
let clear_tag_id = match layout_interner.chase_recursive(layout) {
LayoutRepr::Union(union) => union.stores_tag_id_in_pointer(env.target_info),
_ => false,
};
let ptr = if clear_tag_id {
tag_pointer_clear_tag_id(env, value)
} else {
value
};
let rc_ptr = PointerToRefcount::from_ptr_to_data(env, ptr);
rc_ptr.deallocate(env, alignment);
build_exp_stmt(
env,
layout_interner,
layout_ids,
func_spec_solutions,
scope,
parent,
cont,
)
}
} }
} }

View file

@ -1325,6 +1325,12 @@ pub(crate) fn run_low_level<'a, 'ctx>(
.new_build_load(element_type, ptr.into_pointer_value(), "ptr_load") .new_build_load(element_type, ptr.into_pointer_value(), "ptr_load")
} }
PtrClearTagId => {
arguments!(ptr);
tag_pointer_clear_tag_id(env, ptr.into_pointer_value()).into()
}
Alloca => { Alloca => {
arguments!(initial_value); arguments!(initial_value);

View file

@ -14,7 +14,7 @@ use bumpalo::collections::Vec;
use inkwell::basic_block::BasicBlock; use inkwell::basic_block::BasicBlock;
use inkwell::module::Linkage; use inkwell::module::Linkage;
use inkwell::types::{AnyTypeEnum, BasicMetadataTypeEnum, BasicType, BasicTypeEnum}; use inkwell::types::{AnyTypeEnum, BasicMetadataTypeEnum, BasicType, BasicTypeEnum};
use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue}; use inkwell::values::{BasicValueEnum, FunctionValue, InstructionValue, IntValue, PointerValue};
use inkwell::{AddressSpace, IntPredicate}; use inkwell::{AddressSpace, IntPredicate};
use roc_module::symbol::Interns; use roc_module::symbol::Interns;
use roc_module::symbol::Symbol; use roc_module::symbol::Symbol;
@ -193,6 +193,14 @@ impl<'ctx> PointerToRefcount<'ctx> {
builder.build_return(None); builder.build_return(None);
} }
pub fn deallocate<'a, 'env>(
&self,
env: &Env<'a, 'ctx, 'env>,
alignment: u32,
) -> InstructionValue<'ctx> {
free_pointer(env, self.value, alignment)
}
} }
fn incref_pointer<'ctx>( fn incref_pointer<'ctx>(
@ -216,6 +224,28 @@ fn incref_pointer<'ctx>(
); );
} }
fn free_pointer<'ctx>(
env: &Env<'_, 'ctx, '_>,
pointer: PointerValue<'ctx>,
alignment: u32,
) -> InstructionValue<'ctx> {
let alignment = env.context.i32_type().const_int(alignment as _, false);
call_void_bitcode_fn(
env,
&[
env.builder
.build_pointer_cast(
pointer,
env.ptr_int().ptr_type(AddressSpace::default()),
"to_isize_ptr",
)
.into(),
alignment.into(),
],
roc_builtins::bitcode::UTILS_FREE_RC_PTR,
)
}
fn decref_pointer<'ctx>(env: &Env<'_, 'ctx, '_>, pointer: PointerValue<'ctx>, alignment: u32) { fn decref_pointer<'ctx>(env: &Env<'_, 'ctx, '_>, pointer: PointerValue<'ctx>, alignment: u32) {
let alignment = env.context.i32_type().const_int(alignment as _, false); let alignment = env.context.i32_type().const_int(alignment as _, false);
call_void_bitcode_fn( call_void_bitcode_fn(

View file

@ -1,7 +1,7 @@
use bitvec::vec::BitVec; use bitvec::vec::BitVec;
use bumpalo::collections::{String, Vec}; use bumpalo::collections::{String, Vec};
use roc_builtins::bitcode::{FloatWidth, IntWidth}; use roc_builtins::bitcode::{self, FloatWidth, IntWidth};
use roc_collections::all::MutMap; use roc_collections::all::MutMap;
use roc_error_macros::internal_error; use roc_error_macros::internal_error;
use roc_module::low_level::{LowLevel, LowLevelWrapperType}; use roc_module::low_level::{LowLevel, LowLevelWrapperType};
@ -719,7 +719,10 @@ impl<'a, 'r> WasmBackend<'a, 'r> {
Stmt::Jump(id, arguments) => self.stmt_jump(*id, arguments), Stmt::Jump(id, arguments) => self.stmt_jump(*id, arguments),
Stmt::Refcounting(modify, following) => self.stmt_refcounting(modify, following), Stmt::Refcounting(modify, following) => match modify {
ModifyRc::Free(symbol) => self.stmt_refcounting_free(*symbol, following),
_ => self.stmt_refcounting(modify, following),
},
Stmt::Dbg { .. } => todo!("dbg is not implemented in the wasm backend"), Stmt::Dbg { .. } => todo!("dbg is not implemented in the wasm backend"),
Stmt::Expect { .. } => todo!("expect is not implemented in the wasm backend"), Stmt::Expect { .. } => todo!("expect is not implemented in the wasm backend"),
@ -999,6 +1002,43 @@ impl<'a, 'r> WasmBackend<'a, 'r> {
self.stmt(rc_stmt); self.stmt(rc_stmt);
} }
fn stmt_refcounting_free(&mut self, value: Symbol, following: &'a Stmt<'a>) {
let layout = self.storage.symbol_layouts[&value];
let alignment = self.layout_interner.allocation_alignment_bytes(layout);
// Get pointer and offset
let value_storage = self.storage.get(&value).to_owned();
let stored_with_local =
self.storage
.ensure_value_has_local(&mut self.code_builder, value, value_storage);
let (tag_local_id, tag_offset) = match stored_with_local {
StoredValue::StackMemory { location, .. } => {
location.local_and_offset(self.storage.stack_frame_pointer)
}
StoredValue::Local { local_id, .. } => (local_id, 0),
StoredValue::VirtualMachineStack { .. } => {
internal_error!("{:?} should have a local variable", value)
}
};
// load pointer, and add the offset to the pointer
self.code_builder.get_local(tag_local_id);
if tag_offset > 0 {
self.code_builder.i32_const(tag_offset as i32);
self.code_builder.i32_add();
}
// NOTE: UTILS_FREE_DATA_PTR clears any tag id bits
// push the allocation's alignment
self.code_builder.i32_const(alignment as i32);
self.call_host_fn_after_loading_args(bitcode::UTILS_FREE_DATA_PTR, 2, false);
self.stmt(following);
}
pub fn stmt_internal_error(&mut self, msg: &'a str) { pub fn stmt_internal_error(&mut self, msg: &'a str) {
let msg_sym = self.create_symbol("panic_str"); let msg_sym = self.create_symbol("panic_str");
let msg_storage = self.storage.allocate_var( let msg_storage = self.storage.allocate_var(

View file

@ -1979,6 +1979,19 @@ impl<'a> LowLevelCall<'a> {
); );
} }
PtrLoad => backend.expr_unbox(self.ret_symbol, self.arguments[0]), PtrLoad => backend.expr_unbox(self.ret_symbol, self.arguments[0]),
PtrClearTagId => {
let ptr = self.arguments[0];
let ptr_local_id = match backend.storage.get(&ptr) {
StoredValue::Local { local_id, .. } => *local_id,
_ => internal_error!("A pointer will always be an i32"),
};
backend.code_builder.get_local(ptr_local_id);
backend.code_builder.i32_const(-4); // 11111111...1100
backend.code_builder.i32_and();
}
Alloca => { Alloca => {
// Alloca : a -> Ptr a // Alloca : a -> Ptr a
let arg = self.arguments[0]; let arg = self.arguments[0];

View file

@ -3141,6 +3141,7 @@ fn update<'a>(
arena, arena,
&layout_interner, &layout_interner,
module_id, module_id,
state.target_info,
ident_ids, ident_ids,
&mut update_mode_ids, &mut update_mode_ids,
&mut state.procedures, &mut state.procedures,

View file

@ -120,6 +120,7 @@ pub enum LowLevel {
PtrCast, PtrCast,
PtrStore, PtrStore,
PtrLoad, PtrLoad,
PtrClearTagId,
Alloca, Alloca,
RefCountIncRcPtr, RefCountIncRcPtr,
RefCountDecRcPtr, RefCountDecRcPtr,
@ -232,6 +233,7 @@ macro_rules! map_symbol_to_lowlevel {
LowLevel::PtrCast => unimplemented!(), LowLevel::PtrCast => unimplemented!(),
LowLevel::PtrStore => unimplemented!(), LowLevel::PtrStore => unimplemented!(),
LowLevel::PtrLoad => unimplemented!(), LowLevel::PtrLoad => unimplemented!(),
LowLevel::PtrClearTagId => unimplemented!(),
LowLevel::Alloca => unimplemented!(), LowLevel::Alloca => unimplemented!(),
LowLevel::RefCountIncRcPtr => unimplemented!(), LowLevel::RefCountIncRcPtr => unimplemented!(),
LowLevel::RefCountDecRcPtr=> unimplemented!(), LowLevel::RefCountDecRcPtr=> unimplemented!(),

View file

@ -1047,8 +1047,8 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[Ownership] {
PtrLoad => arena.alloc_slice_copy(&[owned]), PtrLoad => arena.alloc_slice_copy(&[owned]),
Alloca => arena.alloc_slice_copy(&[owned]), Alloca => arena.alloc_slice_copy(&[owned]),
PtrCast | RefCountIncRcPtr | RefCountDecRcPtr | RefCountIncDataPtr | RefCountDecDataPtr PtrClearTagId | PtrCast | RefCountIncRcPtr | RefCountDecRcPtr | RefCountIncDataPtr
| RefCountIsUnique => { | RefCountDecDataPtr | RefCountIsUnique => {
unreachable!("Only inserted *after* borrow checking: {:?}", op); unreachable!("Only inserted *after* borrow checking: {:?}", op);
} }
} }

View file

@ -141,6 +141,7 @@ impl<'a> CodeGenHelp<'a> {
let jp_decref = JoinPointId(self.create_symbol(ident_ids, "jp_decref")); let jp_decref = JoinPointId(self.create_symbol(ident_ids, "jp_decref"));
HelperOp::DecRef(jp_decref) HelperOp::DecRef(jp_decref)
} }
ModifyRc::Free(_) => unreachable!("free should be handled by the backend directly"),
}; };
let mut ctx = Context { let mut ctx = Context {

View file

@ -118,6 +118,9 @@ pub fn refcount_stmt<'a>(
}, },
} }
} }
ModifyRc::Free(_) => {
unreachable!("free should be handled by the backend directly")
}
} }
} }
@ -453,8 +456,10 @@ pub fn refcount_reset_proc_body<'a>(
root.arena.alloc(refcount_1_stmt), root.arena.alloc(refcount_1_stmt),
); );
// a Box never masks bits let mask_lower_bits = match layout_interner.get_repr(layout) {
let mask_lower_bits = false; LayoutRepr::Union(ul) => ul.stores_tag_id_in_pointer(root.target_info),
_ => false,
};
// Refcount pointer // Refcount pointer
let rc_ptr_stmt = { let rc_ptr_stmt = {
@ -576,8 +581,10 @@ pub fn refcount_resetref_proc_body<'a>(
root.arena.alloc(refcount_1_stmt), root.arena.alloc(refcount_1_stmt),
); );
// a Box never masks bits let mask_lower_bits = match layout_interner.get_repr(layout) {
let mask_lower_bits = false; LayoutRepr::Union(ul) => ul.stores_tag_id_in_pointer(root.target_info),
_ => false,
};
// Refcount pointer // Refcount pointer
let rc_ptr_stmt = { let rc_ptr_stmt = {
@ -629,39 +636,33 @@ fn rc_ptr_from_data_ptr_help<'a>(
addr_sym: Symbol, addr_sym: Symbol,
recursion_ptr: InLayout<'a>, recursion_ptr: InLayout<'a>,
) -> Stmt<'a> { ) -> Stmt<'a> {
use std::ops::Neg; // symbol of a pointer with any tag id bits cleared
let cleared_sym = if mask_lower_bits {
root.create_symbol(ident_ids, "cleared")
} else {
structure
};
let clear_tag_id_expr = Expr::Call(Call {
call_type: CallType::LowLevel {
op: LowLevel::PtrClearTagId,
update_mode: UpdateModeId::BACKEND_DUMMY,
},
arguments: root.arena.alloc([structure]),
});
let clear_tag_id_stmt =
|next| Stmt::Let(cleared_sym, clear_tag_id_expr, root.layout_isize, next);
// Typecast the structure pointer to an integer // Typecast the structure pointer to an integer
// Backends expect a number Layout to choose the right "subtract" instruction // Backends expect a number Layout to choose the right "subtract" instruction
let as_int_sym = if mask_lower_bits {
root.create_symbol(ident_ids, "as_int")
} else {
addr_sym
};
let as_int_expr = Expr::Call(Call { let as_int_expr = Expr::Call(Call {
call_type: CallType::LowLevel { call_type: CallType::LowLevel {
op: LowLevel::PtrCast, op: LowLevel::PtrCast,
update_mode: UpdateModeId::BACKEND_DUMMY, update_mode: UpdateModeId::BACKEND_DUMMY,
}, },
arguments: root.arena.alloc([structure]), arguments: root.arena.alloc([cleared_sym]),
}); });
let as_int_stmt = |next| Stmt::Let(as_int_sym, as_int_expr, root.layout_isize, next); let as_int_stmt = |next| Stmt::Let(addr_sym, as_int_expr, root.layout_isize, next);
// Mask for lower bits (for tag union id)
let mask_sym = root.create_symbol(ident_ids, "mask");
let mask_expr = Expr::Literal(Literal::Int(
(root.target_info.ptr_width() as i128).neg().to_ne_bytes(),
));
let mask_stmt = |next| Stmt::Let(mask_sym, mask_expr, root.layout_isize, next);
let and_expr = Expr::Call(Call {
call_type: CallType::LowLevel {
op: LowLevel::And,
update_mode: UpdateModeId::BACKEND_DUMMY,
},
arguments: root.arena.alloc([as_int_sym, mask_sym]),
});
let and_stmt = |next| Stmt::Let(addr_sym, and_expr, root.layout_isize, next);
// Pointer size constant // Pointer size constant
let ptr_size_sym = root.create_symbol(ident_ids, "ptr_size"); let ptr_size_sym = root.create_symbol(ident_ids, "ptr_size");
@ -691,40 +692,24 @@ fn rc_ptr_from_data_ptr_help<'a>(
}); });
let cast_stmt = |next| Stmt::Let(rc_ptr_sym, cast_expr, recursion_ptr, next); let cast_stmt = |next| Stmt::Let(rc_ptr_sym, cast_expr, recursion_ptr, next);
let body = as_int_stmt(root.arena.alloc(
//
ptr_size_stmt(root.arena.alloc(
//
sub_stmt(root.arena.alloc(
//
cast_stmt(root.arena.alloc(
//
following,
)),
)),
)),
));
if mask_lower_bits { if mask_lower_bits {
as_int_stmt(root.arena.alloc( clear_tag_id_stmt(root.arena.alloc(body))
//
mask_stmt(root.arena.alloc(
//
and_stmt(root.arena.alloc(
//
ptr_size_stmt(root.arena.alloc(
//
sub_stmt(root.arena.alloc(
//
cast_stmt(root.arena.alloc(
//
following,
)),
)),
)),
)),
)),
))
} else { } else {
as_int_stmt(root.arena.alloc( body
//
ptr_size_stmt(root.arena.alloc(
//
sub_stmt(root.arena.alloc(
//
cast_stmt(root.arena.alloc(
//
following,
)),
)),
)),
))
} }
} }

View file

@ -716,8 +716,10 @@ impl<'a, 'r> Ctx<'a, 'r> {
} }
fn check_modify_rc(&mut self, rc: ModifyRc) { fn check_modify_rc(&mut self, rc: ModifyRc) {
use ModifyRc::*;
match rc { match rc {
ModifyRc::Inc(sym, _) | ModifyRc::Dec(sym) | ModifyRc::DecRef(sym) => { Inc(sym, _) | Dec(sym) | DecRef(sym) | Free(sym) => {
// TODO: also check that sym layout needs refcounting // TODO: also check that sym layout needs refcounting
self.check_sym_exists(sym); self.check_sym_exists(sym);
} }

View file

@ -582,8 +582,9 @@ fn specialize_drops_stmt<'a, 'i>(
updated_stmt updated_stmt
} }
} }
ModifyRc::DecRef(_) => { ModifyRc::DecRef(_) | ModifyRc::Free(_) => {
// Inlining has no point, since it doesn't decrement it's children // These operations are not recursive (the children are not touched)
// so inlining is not useful
arena.alloc(Stmt::Refcounting( arena.alloc(Stmt::Refcounting(
*rc, *rc,
specialize_drops_stmt( specialize_drops_stmt(
@ -1031,8 +1032,10 @@ fn specialize_union<'a, 'i>(
)) ))
}), }),
arena.alloc(Stmt::Refcounting( arena.alloc(Stmt::Refcounting(
// TODO this could be replaced by a free if ever added to the IR. // we know for sure that the allocation is unique at
ModifyRc::DecRef(*symbol), // this point. Therefore we can free (or maybe reuse)
// without checking the refcount again.
ModifyRc::Free(*symbol),
continuation, continuation,
)), )),
) )
@ -1101,8 +1104,10 @@ fn specialize_boxed<'a, 'i>(
// - free the box // - free the box
|_, _, continuation| { |_, _, continuation| {
arena.alloc(Stmt::Refcounting( arena.alloc(Stmt::Refcounting(
// TODO can be replaced by free if ever added to the IR. // we know for sure that the allocation is unique at
ModifyRc::DecRef(*symbol), // this point. Therefore we can free (or maybe reuse)
// without checking the refcount again.
ModifyRc::Free(*symbol),
continuation, continuation,
)) ))
}, },
@ -1682,8 +1687,8 @@ fn low_level_no_rc(lowlevel: &LowLevel) -> RC {
PtrLoad => RC::NoRc, PtrLoad => RC::NoRc,
Alloca => RC::NoRc, Alloca => RC::NoRc,
PtrCast | RefCountIncRcPtr | RefCountDecRcPtr | RefCountIncDataPtr | RefCountDecDataPtr PtrClearTagId | PtrCast | RefCountIncRcPtr | RefCountDecRcPtr | RefCountIncDataPtr
| RefCountIsUnique => { | RefCountDecDataPtr | RefCountIsUnique => {
unreachable!("Only inserted *after* borrow checking: {:?}", lowlevel); unreachable!("Only inserted *after* borrow checking: {:?}", lowlevel);
} }
} }

View file

@ -1612,6 +1612,9 @@ pub enum ModifyRc {
/// sometimes we know we already dealt with the elements (e.g. by copying them all over /// sometimes we know we already dealt with the elements (e.g. by copying them all over
/// to a new list) and so we can just do a DecRef, which is much cheaper in such a case. /// to a new list) and so we can just do a DecRef, which is much cheaper in such a case.
DecRef(Symbol), DecRef(Symbol),
/// Unconditionally deallocate the memory. For tag union that do pointer tagging (store the tag
/// id in the pointer) the backend has to clear the tag id!
Free(Symbol),
} }
impl ModifyRc { impl ModifyRc {
@ -1641,6 +1644,10 @@ impl ModifyRc {
.text("decref ") .text("decref ")
.append(symbol_to_doc(alloc, symbol, pretty)) .append(symbol_to_doc(alloc, symbol, pretty))
.append(";"), .append(";"),
Free(symbol) => alloc
.text("free ")
.append(symbol_to_doc(alloc, symbol, pretty))
.append(";"),
} }
} }
@ -1651,6 +1658,7 @@ impl ModifyRc {
Inc(symbol, _) => *symbol, Inc(symbol, _) => *symbol,
Dec(symbol) => *symbol, Dec(symbol) => *symbol,
DecRef(symbol) => *symbol, DecRef(symbol) => *symbol,
Free(symbol) => *symbol,
} }
} }
} }

View file

@ -19,7 +19,9 @@ use bumpalo::Bump;
use bumpalo::collections::vec::Vec; use bumpalo::collections::vec::Vec;
use bumpalo::collections::CollectIn; use bumpalo::collections::CollectIn;
use roc_collections::{MutMap, MutSet}; use roc_collections::{MutMap, MutSet};
use roc_module::low_level::LowLevel;
use roc_module::symbol::{IdentIds, ModuleId, Symbol}; use roc_module::symbol::{IdentIds, ModuleId, Symbol};
use roc_target::TargetInfo;
/** /**
Insert reset and reuse operations into the IR. Insert reset and reuse operations into the IR.
@ -29,6 +31,7 @@ pub fn insert_reset_reuse_operations<'a, 'i>(
arena: &'a Bump, arena: &'a Bump,
layout_interner: &'i STLayoutInterner<'a>, layout_interner: &'i STLayoutInterner<'a>,
home: ModuleId, home: ModuleId,
target_info: TargetInfo,
ident_ids: &'i mut IdentIds, ident_ids: &'i mut IdentIds,
update_mode_ids: &'i mut UpdateModeIds, update_mode_ids: &'i mut UpdateModeIds,
procs: &mut MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>, procs: &mut MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>,
@ -42,6 +45,7 @@ pub fn insert_reset_reuse_operations<'a, 'i>(
let new_proc = insert_reset_reuse_operations_proc( let new_proc = insert_reset_reuse_operations_proc(
arena, arena,
layout_interner, layout_interner,
target_info,
home, home,
ident_ids, ident_ids,
update_mode_ids, update_mode_ids,
@ -55,6 +59,7 @@ pub fn insert_reset_reuse_operations<'a, 'i>(
fn insert_reset_reuse_operations_proc<'a, 'i>( fn insert_reset_reuse_operations_proc<'a, 'i>(
arena: &'a Bump, arena: &'a Bump,
layout_interner: &'i STLayoutInterner<'a>, layout_interner: &'i STLayoutInterner<'a>,
target_info: TargetInfo,
home: ModuleId, home: ModuleId,
ident_ids: &'i mut IdentIds, ident_ids: &'i mut IdentIds,
update_mode_ids: &'i mut UpdateModeIds, update_mode_ids: &'i mut UpdateModeIds,
@ -66,6 +71,7 @@ fn insert_reset_reuse_operations_proc<'a, 'i>(
} }
let mut env = ReuseEnvironment { let mut env = ReuseEnvironment {
target_info,
symbol_tags: MutMap::default(), symbol_tags: MutMap::default(),
non_unique_symbols: MutSet::default(), non_unique_symbols: MutSet::default(),
reuse_tokens: MutMap::default(), reuse_tokens: MutMap::default(),
@ -398,33 +404,83 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>(
}) })
} }
Stmt::Refcounting(rc, continuation) => { Stmt::Refcounting(rc, continuation) => {
let reuse_pair = match rc { enum SymbolIsUnique {
ModifyRc::Dec(symbol) | ModifyRc::DecRef(symbol) Never,
if !environment.non_unique_symbols.contains(symbol) => Always(Symbol),
{ MustCheck(Symbol),
}
let can_reuse = match rc {
ModifyRc::Dec(symbol) | ModifyRc::DecRef(symbol) => {
// can only reuse if the symbol is (potentially) unique
if environment.non_unique_symbols.contains(symbol) {
SymbolIsUnique::Never
} else {
SymbolIsUnique::MustCheck(*symbol)
}
}
ModifyRc::Free(symbol) => {
// a free'd symbol is guaranteed to be unique
SymbolIsUnique::Always(*symbol)
}
ModifyRc::Inc(_, _) => {
// an incremented symbol is never unique
SymbolIsUnique::Never
}
};
enum ResetOperation {
Reset,
ResetRef,
ClearTagId,
Nothing,
}
let reuse_pair = match can_reuse {
SymbolIsUnique::MustCheck(symbol) | SymbolIsUnique::Always(symbol) => {
// Get the layout of the symbol from where it is defined. // Get the layout of the symbol from where it is defined.
let layout_option = environment.get_symbol_layout(*symbol); let layout_option = environment.get_symbol_layout(symbol);
// If the symbol is defined in the current proc, we can use the layout from the environment. // If the symbol is defined in the current proc, we can use the layout from the environment.
match layout_option.clone() { match layout_option {
LayoutOption::Layout(layout) => { LayoutOption::Layout(layout) => {
match symbol_layout_reusability( match symbol_layout_reusability(
layout_interner, layout_interner,
environment, environment,
symbol, &symbol,
layout, layout,
) { ) {
Reuse::Reusable(union_layout) => { Reuse::Reusable(union_layout) => {
let (reuse_symbol, reset_op) = match rc {
ModifyRc::Dec(_) => (
Symbol::new(home, ident_ids.gen_unique()),
ResetOperation::Reset,
),
ModifyRc::DecRef(_) => (
Symbol::new(home, ident_ids.gen_unique()),
ResetOperation::ResetRef,
),
ModifyRc::Free(_) => {
if union_layout
.stores_tag_id_in_pointer(environment.target_info)
{
(
Symbol::new(home, ident_ids.gen_unique()),
ResetOperation::ClearTagId,
)
} else {
(symbol, ResetOperation::Nothing)
}
}
_ => unreachable!(),
};
let reuse_token = ReuseToken { let reuse_token = ReuseToken {
symbol: Symbol::new(home, ident_ids.gen_unique()), symbol: reuse_symbol,
update_mode_id: update_mode_ids.next_id(), update_mode_id: update_mode_ids.next_id(),
}; };
let dec_ref = match rc { let owned_layout = **layout;
ModifyRc::Dec(_) => false,
ModifyRc::DecRef(_) => true,
_ => unreachable!(),
};
environment.push_reuse_token( environment.push_reuse_token(
arena, arena,
@ -432,7 +488,14 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>(
reuse_token, reuse_token,
layout, layout,
); );
Some((layout, union_layout, *symbol, reuse_token, dec_ref))
Some((
owned_layout,
union_layout,
symbol,
reuse_token,
reset_op,
))
} }
Reuse::Nonreusable => None, Reuse::Nonreusable => None,
} }
@ -440,7 +503,7 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>(
_ => None, _ => None,
} }
} }
_ => { SymbolIsUnique::Never => {
// We don't need to do anything for an inc or symbols known to be non-unique. // We don't need to do anything for an inc or symbols known to be non-unique.
None None
} }
@ -457,7 +520,7 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>(
); );
// If we inserted a reuse token, we need to insert a reset reuse operation if the reuse token is consumed. // If we inserted a reuse token, we need to insert a reset reuse operation if the reuse token is consumed.
if let Some((layout, union_layout, symbol, reuse_token, dec_ref)) = reuse_pair { if let Some((layout, union_layout, symbol, reuse_token, reset_op)) = reuse_pair {
let stack_reuse_token = environment let stack_reuse_token = environment
.peek_reuse_token(&get_reuse_layout_info(layout_interner, union_layout)); .peek_reuse_token(&get_reuse_layout_info(layout_interner, union_layout));
@ -471,29 +534,56 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>(
_ => { _ => {
// The token we inserted is no longer on the stack, it must have been consumed. // The token we inserted is no longer on the stack, it must have been consumed.
// So we need to insert a reset operation. // So we need to insert a reset operation.
let reset_expr = match dec_ref { match reset_op {
// A decref will be replaced by a resetref. ResetOperation::Reset => {
true => Expr::ResetRef { // a dec will be replaced by a reset.
symbol, let reset_expr = Expr::Reset {
update_mode: reuse_token.update_mode_id, symbol,
}, update_mode: reuse_token.update_mode_id,
// And a dec will be replaced by a reset. };
false => Expr::Reset {
symbol,
update_mode: reuse_token.update_mode_id,
},
};
// If we generate a reuse token, we no longer want to use the drop statement anymore. So we just return the reset expression. return arena.alloc(Stmt::Let(
// TODO verify if this works for both dec and decref. reuse_token.symbol,
// TODO reset probably decrements it's children. So we probably need to create a resetref that only does the token. reset_expr,
return arena.alloc(Stmt::Let( layout,
reuse_token.symbol, new_continuation,
reset_expr, ));
// TODO not sure what the layout should be for a reset token. Currently it is the layout of the symbol. }
*layout, ResetOperation::ResetRef => {
new_continuation, // a decref will be replaced by a resetref.
)); let reset_expr = Expr::ResetRef {
symbol,
update_mode: reuse_token.update_mode_id,
};
return arena.alloc(Stmt::Let(
reuse_token.symbol,
reset_expr,
layout,
new_continuation,
));
}
ResetOperation::ClearTagId => {
let reset_expr = Expr::Call(crate::ir::Call {
call_type: crate::ir::CallType::LowLevel {
op: LowLevel::PtrClearTagId,
update_mode: update_mode_ids.next_id(),
},
arguments: arena.alloc([symbol]),
});
return arena.alloc(Stmt::Let(
reuse_token.symbol,
reset_expr,
layout,
new_continuation,
));
}
ResetOperation::Nothing => {
// the reuse token is already in a valid state
return new_continuation;
}
}
} }
} }
} }
@ -661,6 +751,7 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>(
// Create a new environment for the body. With everything but the jump reuse tokens. As those should be given by the jump. // Create a new environment for the body. With everything but the jump reuse tokens. As those should be given by the jump.
let mut first_pass_body_environment = ReuseEnvironment { let mut first_pass_body_environment = ReuseEnvironment {
target_info: environment.target_info,
symbol_tags: environment.symbol_tags.clone(), symbol_tags: environment.symbol_tags.clone(),
non_unique_symbols: environment.non_unique_symbols.clone(), non_unique_symbols: environment.non_unique_symbols.clone(),
reuse_tokens: max_reuse_token_symbols.clone(), reuse_tokens: max_reuse_token_symbols.clone(),
@ -824,6 +915,7 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>(
let (second_pass_body_environment, second_pass_body) = { let (second_pass_body_environment, second_pass_body) = {
// Create a new environment for the body. With everything but the jump reuse tokens. As those should be given by the jump. // Create a new environment for the body. With everything but the jump reuse tokens. As those should be given by the jump.
let mut body_environment = ReuseEnvironment { let mut body_environment = ReuseEnvironment {
target_info: environment.target_info,
symbol_tags: environment.symbol_tags.clone(), symbol_tags: environment.symbol_tags.clone(),
non_unique_symbols: environment.non_unique_symbols.clone(), non_unique_symbols: environment.non_unique_symbols.clone(),
reuse_tokens: used_reuse_tokens.clone(), reuse_tokens: used_reuse_tokens.clone(),
@ -889,7 +981,8 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>(
let mut void_pointer_layout_symbols = Vec::new_in(arena); let mut void_pointer_layout_symbols = Vec::new_in(arena);
// See what tokens we can get from the env, if none are available, use a void pointer. // See what tokens we can get from the env, if none are available, use a void pointer.
// We process the tokens in reverse order, so that when we consume the tokens we last added, we consume the tokens that are most likely not to be null. // We process the tokens in reverse order, so that when we consume the tokens we last added,
// we consume the tokens that are most likely not to be null.
let tokens = token_layouts_clone let tokens = token_layouts_clone
.iter() .iter()
.rev() .rev()
@ -1002,7 +1095,7 @@ fn insert_reset_reuse_operations_stmt<'a, 'i>(
fn create_ptr_cast(arena: &Bump, symbol: Symbol) -> Expr { fn create_ptr_cast(arena: &Bump, symbol: Symbol) -> Expr {
Expr::Call(crate::ir::Call { Expr::Call(crate::ir::Call {
call_type: crate::ir::CallType::LowLevel { call_type: crate::ir::CallType::LowLevel {
op: roc_module::low_level::LowLevel::PtrCast, op: LowLevel::PtrCast,
update_mode: UpdateModeId::BACKEND_DUMMY, update_mode: UpdateModeId::BACKEND_DUMMY,
}, },
arguments: Vec::from_iter_in([symbol], arena).into_bump_slice(), arguments: Vec::from_iter_in([symbol], arena).into_bump_slice(),
@ -1029,7 +1122,6 @@ Struct to to check whether two reuse layouts are interchangeable.
*/ */
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
struct TokenLayout { struct TokenLayout {
has_tag: bool,
size: u32, size: u32,
alignment: u32, alignment: u32,
} }
@ -1092,8 +1184,9 @@ enum JoinPointReuseTokens<'a> {
RemainderSecond(Vec<'a, (&'a InLayout<'a>, TokenLayout)>), RemainderSecond(Vec<'a, (&'a InLayout<'a>, TokenLayout)>),
} }
#[derive(Default, Clone)] #[derive(Clone)]
struct ReuseEnvironment<'a> { struct ReuseEnvironment<'a> {
target_info: TargetInfo,
symbol_tags: MutMap<Symbol, Tag>, symbol_tags: MutMap<Symbol, Tag>,
non_unique_symbols: MutSet<Symbol>, non_unique_symbols: MutSet<Symbol>,
reuse_tokens: ReuseTokens<'a>, reuse_tokens: ReuseTokens<'a>,
@ -1322,16 +1415,6 @@ fn get_reuse_layout_info<'a, 'i>(
union_layout: UnionLayout<'a>, union_layout: UnionLayout<'a>,
) -> TokenLayout { ) -> TokenLayout {
let (size, alignment) = union_layout.data_size_and_alignment(layout_interner); let (size, alignment) = union_layout.data_size_and_alignment(layout_interner);
let has_tag = match union_layout {
UnionLayout::NonRecursive(_) => unreachable!("Non recursive unions should not be reused."), TokenLayout { size, alignment }
// The memory for union layouts that has a tag_id can be reused for new allocations with tag_id.
UnionLayout::Recursive(_) | UnionLayout::NullableWrapped { .. } => true,
// The memory for union layouts that have no tag_id can be reused for new allocations without tag_id
UnionLayout::NonNullableUnwrapped(_) | UnionLayout::NullableUnwrapped { .. } => false,
};
TokenLayout {
has_tag,
size,
alignment,
}
} }

View file

@ -16,23 +16,22 @@ procedure Test.5 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2):
if Test.53 then if Test.53 then
let Test.32 : [<rnu><null>, C *self *self] = UnionAtIndex (Id 0) (Index 0) Test.29; let Test.32 : [<rnu><null>, C *self *self] = UnionAtIndex (Id 0) (Index 0) Test.29;
let Test.33 : [<rnu><null>, C *self *self] = UnionAtIndex (Id 0) (Index 1) Test.29; let Test.33 : [<rnu><null>, C *self *self] = UnionAtIndex (Id 0) (Index 1) Test.29;
joinpoint #Derived_gen.3 #Derived_gen.7: joinpoint #Derived_gen.3 #Derived_gen.6:
let #Derived_gen.8 : [<rnu>C [<rnu><null>, C *self *self] *self, <null>] = lowlevel PtrCast #Derived_gen.7; let #Derived_gen.7 : [<rnu>C [<rnu><null>, C *self *self] *self, <null>] = lowlevel PtrCast #Derived_gen.6;
let Test.43 : [<rnu>C [<rnu><null>, C *self *self] *self, <null>] = Reuse #Derived_gen.8 UpdateModeId { id: 1 } TagId(1) Test.33 Test.30; let Test.43 : [<rnu>C [<rnu><null>, C *self *self] *self, <null>] = Reuse #Derived_gen.7 UpdateModeId { id: 1 } TagId(1) Test.33 Test.30;
let Test.45 : I64 = 1i64; let Test.45 : I64 = 1i64;
let Test.44 : I64 = CallByName Num.19 Test.31 Test.45; let Test.44 : I64 = CallByName Num.19 Test.31 Test.45;
jump Test.41 Test.32 Test.43 Test.44; jump Test.41 Test.32 Test.43 Test.44;
in in
let #Derived_gen.4 : Int1 = lowlevel RefCountIsUnique Test.29; let #Derived_gen.4 : Int1 = lowlevel RefCountIsUnique Test.29;
if #Derived_gen.4 then if #Derived_gen.4 then
let #Derived_gen.9 : [<rnu><null>, C *self *self] = ResetRef { symbol: Test.29, id: UpdateModeId { id: 2 } }; jump #Derived_gen.3 Test.29;
jump #Derived_gen.3 #Derived_gen.9;
else else
inc Test.32; inc Test.32;
inc Test.33; inc Test.33;
decref Test.29; decref Test.29;
let #Derived_gen.10 : [<rnu><null>, C *self *self] = NullPointer; let #Derived_gen.8 : [<rnu><null>, C *self *self] = NullPointer;
jump #Derived_gen.3 #Derived_gen.10; jump #Derived_gen.3 #Derived_gen.8;
else else
let Test.48 : U8 = 1i64; let Test.48 : U8 = 1i64;
let Test.49 : U8 = GetTagId Test.30; let Test.49 : U8 = GetTagId Test.30;
@ -42,7 +41,7 @@ procedure Test.5 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2):
let Test.36 : [<rnu>C [<rnu><null>, C *self *self] *self, <null>] = UnionAtIndex (Id 1) (Index 1) Test.30; let Test.36 : [<rnu>C [<rnu><null>, C *self *self] *self, <null>] = UnionAtIndex (Id 1) (Index 1) Test.30;
let #Derived_gen.5 : Int1 = lowlevel RefCountIsUnique Test.30; let #Derived_gen.5 : Int1 = lowlevel RefCountIsUnique Test.30;
if #Derived_gen.5 then if #Derived_gen.5 then
decref Test.30; free Test.30;
jump Test.41 Test.35 Test.36 Test.31; jump Test.41 Test.35 Test.36 Test.31;
else else
inc Test.35; inc Test.35;

View file

@ -90,7 +90,7 @@ procedure Test.2 (Test.6):
in in
let #Derived_gen.2 : Int1 = lowlevel RefCountIsUnique Test.6; let #Derived_gen.2 : Int1 = lowlevel RefCountIsUnique Test.6;
if #Derived_gen.2 then if #Derived_gen.2 then
decref Test.6; free Test.6;
jump #Derived_gen.1; jump #Derived_gen.1;
else else
inc Test.7; inc Test.7;
@ -108,7 +108,7 @@ procedure Test.2 (Test.6):
in in
let #Derived_gen.4 : Int1 = lowlevel RefCountIsUnique Test.6; let #Derived_gen.4 : Int1 = lowlevel RefCountIsUnique Test.6;
if #Derived_gen.4 then if #Derived_gen.4 then
decref Test.6; free Test.6;
jump #Derived_gen.3; jump #Derived_gen.3;
else else
inc Test.9; inc Test.9;

View file

@ -87,7 +87,7 @@ procedure Test.11 (#Derived_gen.7, #Derived_gen.8):
in in
let #Derived_gen.15 : Int1 = lowlevel RefCountIsUnique #Attr.12; let #Derived_gen.15 : Int1 = lowlevel RefCountIsUnique #Attr.12;
if #Derived_gen.15 then if #Derived_gen.15 then
decref #Attr.12; free #Attr.12;
jump #Derived_gen.14; jump #Derived_gen.14;
else else
inc Test.7; inc Test.7;
@ -155,7 +155,7 @@ procedure Test.9 (Test.10, #Attr.12):
in in
let #Derived_gen.13 : Int1 = lowlevel RefCountIsUnique #Attr.12; let #Derived_gen.13 : Int1 = lowlevel RefCountIsUnique #Attr.12;
if #Derived_gen.13 then if #Derived_gen.13 then
decref #Attr.12; free #Attr.12;
jump #Derived_gen.12; jump #Derived_gen.12;
else else
inc Test.7; inc Test.7;

View file

@ -15,7 +15,7 @@ procedure Test.2 (#Derived_gen.0):
let Test.5 : [<rnu><null>, C *self] = UnionAtIndex (Id 0) (Index 0) Test.7; let Test.5 : [<rnu><null>, C *self] = UnionAtIndex (Id 0) (Index 0) Test.7;
let #Derived_gen.1 : Int1 = lowlevel RefCountIsUnique Test.7; let #Derived_gen.1 : Int1 = lowlevel RefCountIsUnique Test.7;
if #Derived_gen.1 then if #Derived_gen.1 then
decref Test.7; free Test.7;
jump Test.13 Test.5; jump Test.13 Test.5;
else else
inc Test.5; inc Test.5;

View file

@ -116,7 +116,7 @@ procedure Test.1 (#Derived_gen.0):
in in
let #Derived_gen.7 : Int1 = lowlevel RefCountIsUnique Test.49; let #Derived_gen.7 : Int1 = lowlevel RefCountIsUnique Test.49;
if #Derived_gen.7 then if #Derived_gen.7 then
decref Test.49; free Test.49;
jump #Derived_gen.6; jump #Derived_gen.6;
else else
decref Test.49; decref Test.49;
@ -161,7 +161,7 @@ procedure Test.1 (#Derived_gen.0):
in in
let #Derived_gen.9 : Int1 = lowlevel RefCountIsUnique Test.51; let #Derived_gen.9 : Int1 = lowlevel RefCountIsUnique Test.51;
if #Derived_gen.9 then if #Derived_gen.9 then
decref Test.51; free Test.51;
jump #Derived_gen.8; jump #Derived_gen.8;
else else
inc Test.14; inc Test.14;

View file

@ -22,27 +22,26 @@ procedure Test.2 (#Derived_gen.0, #Derived_gen.1):
else else
let Test.7 : I64 = UnionAtIndex (Id 0) (Index 0) Test.4; let Test.7 : I64 = UnionAtIndex (Id 0) (Index 0) Test.4;
let Test.8 : [<rnu><null>, C I64 *self] = UnionAtIndex (Id 0) (Index 1) Test.4; let Test.8 : [<rnu><null>, C I64 *self] = UnionAtIndex (Id 0) (Index 1) Test.4;
joinpoint #Derived_gen.12 #Derived_gen.15: joinpoint #Derived_gen.12 #Derived_gen.14:
let Test.19 : Int1 = CallByName Num.31 Test.7; let Test.19 : Int1 = CallByName Num.31 Test.7;
if Test.19 then if Test.19 then
let #Derived_gen.9 : [<rnu><null>, C I64 *self] = NullPointer; let #Derived_gen.9 : [<rnu><null>, C I64 *self] = NullPointer;
let Test.20 : [<rnu><null>, C I64 *self] = Reuse #Derived_gen.15 UpdateModeId { id: 1 } TagId(0) Test.7 #Derived_gen.9; let Test.20 : [<rnu><null>, C I64 *self] = Reuse #Derived_gen.14 UpdateModeId { id: 1 } TagId(0) Test.7 #Derived_gen.9;
let #Derived_gen.10 : Ptr([<rnu><null>, C I64 *self]) = UnionFieldPtrAtIndex (Id 0) (Index 1) Test.20; let #Derived_gen.10 : Ptr([<rnu><null>, C I64 *self]) = UnionFieldPtrAtIndex (Id 0) (Index 1) Test.20;
let #Derived_gen.11 : {} = lowlevel PtrStore #Derived_gen.5 Test.20; let #Derived_gen.11 : {} = lowlevel PtrStore #Derived_gen.5 Test.20;
jump #Derived_gen.4 Test.8 Test.5 #Derived_gen.10 #Derived_gen.6; jump #Derived_gen.4 Test.8 Test.5 #Derived_gen.10 #Derived_gen.6;
else else
decref #Derived_gen.15; decref #Derived_gen.14;
jump #Derived_gen.4 Test.8 Test.5 #Derived_gen.5 #Derived_gen.6; jump #Derived_gen.4 Test.8 Test.5 #Derived_gen.5 #Derived_gen.6;
in in
let #Derived_gen.13 : Int1 = lowlevel RefCountIsUnique Test.4; let #Derived_gen.13 : Int1 = lowlevel RefCountIsUnique Test.4;
if #Derived_gen.13 then if #Derived_gen.13 then
let #Derived_gen.16 : [<rnu><null>, C I64 *self] = ResetRef { symbol: Test.4, id: UpdateModeId { id: 2 } }; jump #Derived_gen.12 Test.4;
jump #Derived_gen.12 #Derived_gen.16;
else else
inc Test.8; inc Test.8;
decref Test.4; decref Test.4;
let #Derived_gen.17 : [<rnu><null>, C I64 *self] = NullPointer; let #Derived_gen.15 : [<rnu><null>, C I64 *self] = NullPointer;
jump #Derived_gen.12 #Derived_gen.17; jump #Derived_gen.12 #Derived_gen.15;
in in
jump #Derived_gen.4 #Derived_gen.0 #Derived_gen.1 #Derived_gen.2 #Derived_gen.2; jump #Derived_gen.4 #Derived_gen.0 #Derived_gen.1 #Derived_gen.2 #Derived_gen.2;

View file

@ -22,23 +22,22 @@ procedure Test.2 (#Derived_gen.0, #Derived_gen.1):
else else
let Test.7 : I64 = UnionAtIndex (Id 0) (Index 0) Test.5; let Test.7 : I64 = UnionAtIndex (Id 0) (Index 0) Test.5;
let Test.8 : [<rnu><null>, C I64 *self] = UnionAtIndex (Id 0) (Index 1) Test.5; let Test.8 : [<rnu><null>, C I64 *self] = UnionAtIndex (Id 0) (Index 1) Test.5;
joinpoint #Derived_gen.12 #Derived_gen.15: joinpoint #Derived_gen.12 #Derived_gen.14:
let Test.20 : I64 = CallByName Test.10 Test.7; let Test.20 : I64 = CallByName Test.10 Test.7;
let #Derived_gen.9 : [<rnu><null>, C I64 *self] = NullPointer; let #Derived_gen.9 : [<rnu><null>, C I64 *self] = NullPointer;
let Test.19 : [<rnu><null>, C I64 *self] = Reuse #Derived_gen.15 UpdateModeId { id: 1 } TagId(0) Test.20 #Derived_gen.9; let Test.19 : [<rnu><null>, C I64 *self] = Reuse #Derived_gen.14 UpdateModeId { id: 1 } TagId(0) Test.20 #Derived_gen.9;
let #Derived_gen.10 : Ptr([<rnu><null>, C I64 *self]) = UnionFieldPtrAtIndex (Id 0) (Index 1) Test.19; let #Derived_gen.10 : Ptr([<rnu><null>, C I64 *self]) = UnionFieldPtrAtIndex (Id 0) (Index 1) Test.19;
let #Derived_gen.11 : {} = lowlevel PtrStore #Derived_gen.5 Test.19; let #Derived_gen.11 : {} = lowlevel PtrStore #Derived_gen.5 Test.19;
jump #Derived_gen.4 Test.4 Test.8 #Derived_gen.10 #Derived_gen.6; jump #Derived_gen.4 Test.4 Test.8 #Derived_gen.10 #Derived_gen.6;
in in
let #Derived_gen.13 : Int1 = lowlevel RefCountIsUnique Test.5; let #Derived_gen.13 : Int1 = lowlevel RefCountIsUnique Test.5;
if #Derived_gen.13 then if #Derived_gen.13 then
let #Derived_gen.16 : [<rnu><null>, C I64 *self] = ResetRef { symbol: Test.5, id: UpdateModeId { id: 2 } }; jump #Derived_gen.12 Test.5;
jump #Derived_gen.12 #Derived_gen.16;
else else
inc Test.8; inc Test.8;
decref Test.5; decref Test.5;
let #Derived_gen.17 : [<rnu><null>, C I64 *self] = NullPointer; let #Derived_gen.15 : [<rnu><null>, C I64 *self] = NullPointer;
jump #Derived_gen.12 #Derived_gen.17; jump #Derived_gen.12 #Derived_gen.15;
in in
jump #Derived_gen.4 #Derived_gen.0 #Derived_gen.1 #Derived_gen.2 #Derived_gen.2; jump #Derived_gen.4 #Derived_gen.0 #Derived_gen.1 #Derived_gen.2 #Derived_gen.2;

View file

@ -13,19 +13,18 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1):
else else
let Test.9 : I64 = UnionAtIndex (Id 0) (Index 0) Test.8; let Test.9 : I64 = UnionAtIndex (Id 0) (Index 0) Test.8;
let Test.10 : [<rnu><null>, C I64 *self] = UnionAtIndex (Id 0) (Index 1) Test.8; let Test.10 : [<rnu><null>, C I64 *self] = UnionAtIndex (Id 0) (Index 1) Test.8;
joinpoint #Derived_gen.2 #Derived_gen.5: joinpoint #Derived_gen.2 #Derived_gen.4:
let Test.21 : [<rnu><null>, C I64 *self] = Reuse #Derived_gen.5 UpdateModeId { id: 1 } TagId(0) Test.9 Test.7; let Test.21 : [<rnu><null>, C I64 *self] = Reuse #Derived_gen.4 UpdateModeId { id: 1 } TagId(0) Test.9 Test.7;
jump Test.18 Test.21 Test.10; jump Test.18 Test.21 Test.10;
in in
let #Derived_gen.3 : Int1 = lowlevel RefCountIsUnique Test.8; let #Derived_gen.3 : Int1 = lowlevel RefCountIsUnique Test.8;
if #Derived_gen.3 then if #Derived_gen.3 then
let #Derived_gen.6 : [<rnu><null>, C I64 *self] = ResetRef { symbol: Test.8, id: UpdateModeId { id: 2 } }; jump #Derived_gen.2 Test.8;
jump #Derived_gen.2 #Derived_gen.6;
else else
inc Test.10; inc Test.10;
decref Test.8; decref Test.8;
let #Derived_gen.7 : [<rnu><null>, C I64 *self] = NullPointer; let #Derived_gen.5 : [<rnu><null>, C I64 *self] = NullPointer;
jump #Derived_gen.2 #Derived_gen.7; jump #Derived_gen.2 #Derived_gen.5;
in in
jump Test.18 #Derived_gen.0 #Derived_gen.1; jump Test.18 #Derived_gen.0 #Derived_gen.1;

View file

@ -17,7 +17,7 @@ procedure Test.0 ():
let #Derived_gen.1 : Int1 = lowlevel RefCountIsUnique Test.2; let #Derived_gen.1 : Int1 = lowlevel RefCountIsUnique Test.2;
if #Derived_gen.1 then if #Derived_gen.1 then
dec Test.13; dec Test.13;
decref Test.2; free Test.2;
jump #Derived_gen.0; jump #Derived_gen.0;
else else
decref Test.2; decref Test.2;

View file

@ -22,7 +22,7 @@ procedure Test.0 ():
in in
let #Derived_gen.1 : Int1 = lowlevel RefCountIsUnique Test.2; let #Derived_gen.1 : Int1 = lowlevel RefCountIsUnique Test.2;
if #Derived_gen.1 then if #Derived_gen.1 then
decref Test.2; free Test.2;
jump #Derived_gen.0; jump #Derived_gen.0;
else else
inc Test.12; inc Test.12;

View file

@ -37,7 +37,7 @@ procedure Test.0 ():
let #Derived_gen.1 : Int1 = lowlevel RefCountIsUnique Test.15; let #Derived_gen.1 : Int1 = lowlevel RefCountIsUnique Test.15;
if #Derived_gen.1 then if #Derived_gen.1 then
dec Test.16; dec Test.16;
decref Test.15; free Test.15;
jump #Derived_gen.0; jump #Derived_gen.0;
else else
decref Test.15; decref Test.15;

View file

@ -30,13 +30,13 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2):
let Test.18 : I64 = UnionAtIndex (Id 1) (Index 1) Test.9; let Test.18 : I64 = UnionAtIndex (Id 1) (Index 1) Test.9;
let Test.19 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 2) Test.9; let Test.19 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 2) Test.9;
let Test.17 : I32 = UnionAtIndex (Id 1) (Index 3) Test.9; let Test.17 : I32 = UnionAtIndex (Id 1) (Index 3) Test.9;
joinpoint #Derived_gen.114 #Derived_gen.119: joinpoint #Derived_gen.114 #Derived_gen.118:
let Test.179 : Int1 = CallByName Num.22 Test.10 Test.17; let Test.179 : Int1 = CallByName Num.22 Test.10 Test.17;
if Test.179 then if Test.179 then
joinpoint Test.238 #Derived_gen.181: joinpoint Test.238 #Derived_gen.166:
let Test.232 : Int1 = false; let Test.232 : Int1 = false;
let #Derived_gen.10 : [<rnu>C *self I64 *self I32 Int1, <null>] = NullPointer; let #Derived_gen.10 : [<rnu>C *self I64 *self I32 Int1, <null>] = NullPointer;
let Test.231 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.181 UpdateModeId { id: 56 } TagId(1) #Derived_gen.10 Test.18 Test.19 Test.17 Test.232; let Test.231 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.166 UpdateModeId { id: 56 } TagId(1) #Derived_gen.10 Test.18 Test.19 Test.17 Test.232;
let #Derived_gen.11 : Ptr([<rnu>C *self I64 *self I32 Int1, <null>]) = UnionFieldPtrAtIndex (Id 1) (Index 0) Test.231; let #Derived_gen.11 : Ptr([<rnu>C *self I64 *self I32 Int1, <null>]) = UnionFieldPtrAtIndex (Id 1) (Index 0) Test.231;
let #Derived_gen.12 : {} = lowlevel PtrStore #Derived_gen.6 Test.231; let #Derived_gen.12 : {} = lowlevel PtrStore #Derived_gen.6 Test.231;
jump #Derived_gen.5 Test.16 Test.10 Test.11 #Derived_gen.11 #Derived_gen.7; jump #Derived_gen.5 Test.16 Test.10 Test.11 #Derived_gen.11 #Derived_gen.7;
@ -50,7 +50,7 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2):
let Test.239 : Int1 = lowlevel Eq Test.235 Test.234; let Test.239 : Int1 = lowlevel Eq Test.235 Test.234;
if Test.239 then if Test.239 then
let Test.180 : [<rnu>C *self I64 *self I32 Int1, <null>] = CallByName Test.3 Test.16 Test.10 Test.11; let Test.180 : [<rnu>C *self I64 *self I32 Int1, <null>] = CallByName Test.3 Test.16 Test.10 Test.11;
joinpoint Test.199 #Derived_gen.208: joinpoint Test.199 #Derived_gen.187:
let Test.198 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 0) Test.180; let Test.198 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 0) Test.180;
let Test.20 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 0) Test.198; let Test.20 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 0) Test.198;
inc Test.20; inc Test.20;
@ -61,57 +61,55 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2):
let Test.25 : I64 = UnionAtIndex (Id 1) (Index 1) Test.180; let Test.25 : I64 = UnionAtIndex (Id 1) (Index 1) Test.180;
let Test.26 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 2) Test.180; let Test.26 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 2) Test.180;
let Test.24 : I32 = UnionAtIndex (Id 1) (Index 3) Test.180; let Test.24 : I32 = UnionAtIndex (Id 1) (Index 3) Test.180;
joinpoint #Derived_gen.72 #Derived_gen.211 #Derived_gen.212 #Derived_gen.213: joinpoint #Derived_gen.72 #Derived_gen.189 #Derived_gen.190 #Derived_gen.191:
let Test.186 : Int1 = false; let Test.186 : Int1 = false;
let Test.183 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.213 UpdateModeId { id: 85 } TagId(1) Test.20 Test.22 Test.23 Test.21 Test.186; let Test.183 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.191 UpdateModeId { id: 85 } TagId(1) Test.20 Test.22 Test.23 Test.21 Test.186;
let Test.185 : Int1 = false; let Test.185 : Int1 = false;
let Test.184 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.212 UpdateModeId { id: 84 } TagId(1) Test.26 Test.18 Test.19 Test.17 Test.185; let Test.184 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.190 UpdateModeId { id: 84 } TagId(1) Test.26 Test.18 Test.19 Test.17 Test.185;
let Test.182 : Int1 = true; let Test.182 : Int1 = true;
let Test.181 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.211 UpdateModeId { id: 83 } TagId(1) Test.183 Test.25 Test.184 Test.24 Test.182; let Test.181 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.189 UpdateModeId { id: 83 } TagId(1) Test.183 Test.25 Test.184 Test.24 Test.182;
let #Derived_gen.14 : {} = lowlevel PtrStore #Derived_gen.6 Test.181; let #Derived_gen.14 : {} = lowlevel PtrStore #Derived_gen.6 Test.181;
let #Derived_gen.13 : [<rnu>C *self I64 *self I32 Int1, <null>] = lowlevel PtrLoad #Derived_gen.7; let #Derived_gen.13 : [<rnu>C *self I64 *self I32 Int1, <null>] = lowlevel PtrLoad #Derived_gen.7;
ret #Derived_gen.13; ret #Derived_gen.13;
in in
let #Derived_gen.73 : Int1 = lowlevel RefCountIsUnique Test.180; let #Derived_gen.73 : Int1 = lowlevel RefCountIsUnique Test.180;
if #Derived_gen.73 then if #Derived_gen.73 then
let #Derived_gen.214 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reset { symbol: Test.198, id: UpdateModeId { id: 86 } }; let #Derived_gen.192 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reset { symbol: Test.198, id: UpdateModeId { id: 86 } };
let #Derived_gen.215 : [<rnu>C *self I64 *self I32 Int1, <null>] = ResetRef { symbol: Test.180, id: UpdateModeId { id: 87 } }; jump #Derived_gen.72 #Derived_gen.187 #Derived_gen.192 Test.180;
jump #Derived_gen.72 #Derived_gen.208 #Derived_gen.214 #Derived_gen.215;
else else
inc Test.26; inc Test.26;
decref Test.180; decref Test.180;
let #Derived_gen.216 : [<rnu>C *self I64 *self I32 Int1, <null>] = NullPointer; let #Derived_gen.193 : [<rnu>C *self I64 *self I32 Int1, <null>] = NullPointer;
jump #Derived_gen.72 #Derived_gen.216 #Derived_gen.216 #Derived_gen.208; jump #Derived_gen.72 #Derived_gen.193 #Derived_gen.193 #Derived_gen.187;
in in
let Test.228 : U8 = 1i64; let Test.228 : U8 = 1i64;
let Test.229 : U8 = GetTagId Test.180; let Test.229 : U8 = GetTagId Test.180;
let Test.230 : Int1 = lowlevel Eq Test.228 Test.229; let Test.230 : Int1 = lowlevel Eq Test.228 Test.229;
if Test.230 then if Test.230 then
joinpoint Test.225 #Derived_gen.226: joinpoint Test.225 #Derived_gen.201:
joinpoint Test.216 #Derived_gen.227: joinpoint Test.216 #Derived_gen.202:
let Test.46 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 0) Test.180; let Test.46 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 0) Test.180;
let Test.48 : I64 = UnionAtIndex (Id 1) (Index 1) Test.180; let Test.48 : I64 = UnionAtIndex (Id 1) (Index 1) Test.180;
let Test.49 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 2) Test.180; let Test.49 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 2) Test.180;
let Test.47 : I32 = UnionAtIndex (Id 1) (Index 3) Test.180; let Test.47 : I32 = UnionAtIndex (Id 1) (Index 3) Test.180;
joinpoint #Derived_gen.66 #Derived_gen.229 #Derived_gen.230: joinpoint #Derived_gen.66 #Derived_gen.203 #Derived_gen.204:
let Test.196 : Int1 = true; let Test.196 : Int1 = true;
let Test.195 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.230 UpdateModeId { id: 100 } TagId(1) Test.46 Test.48 Test.49 Test.47 Test.196; let Test.195 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.204 UpdateModeId { id: 100 } TagId(1) Test.46 Test.48 Test.49 Test.47 Test.196;
let Test.194 : Int1 = false; let Test.194 : Int1 = false;
let Test.193 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.229 UpdateModeId { id: 99 } TagId(1) Test.195 Test.18 Test.19 Test.17 Test.194; let Test.193 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.203 UpdateModeId { id: 99 } TagId(1) Test.195 Test.18 Test.19 Test.17 Test.194;
let #Derived_gen.16 : {} = lowlevel PtrStore #Derived_gen.6 Test.193; let #Derived_gen.16 : {} = lowlevel PtrStore #Derived_gen.6 Test.193;
let #Derived_gen.15 : [<rnu>C *self I64 *self I32 Int1, <null>] = lowlevel PtrLoad #Derived_gen.7; let #Derived_gen.15 : [<rnu>C *self I64 *self I32 Int1, <null>] = lowlevel PtrLoad #Derived_gen.7;
ret #Derived_gen.15; ret #Derived_gen.15;
in in
let #Derived_gen.67 : Int1 = lowlevel RefCountIsUnique Test.180; let #Derived_gen.67 : Int1 = lowlevel RefCountIsUnique Test.180;
if #Derived_gen.67 then if #Derived_gen.67 then
let #Derived_gen.231 : [<rnu>C *self I64 *self I32 Int1, <null>] = ResetRef { symbol: Test.180, id: UpdateModeId { id: 101 } }; jump #Derived_gen.66 #Derived_gen.202 Test.180;
jump #Derived_gen.66 #Derived_gen.227 #Derived_gen.231;
else else
inc Test.46; inc Test.46;
inc Test.49; inc Test.49;
decref Test.180; decref Test.180;
let #Derived_gen.232 : [<rnu>C *self I64 *self I32 Int1, <null>] = NullPointer; let #Derived_gen.205 : [<rnu>C *self I64 *self I32 Int1, <null>] = NullPointer;
jump #Derived_gen.66 #Derived_gen.232 #Derived_gen.227; jump #Derived_gen.66 #Derived_gen.205 #Derived_gen.202;
in in
let Test.213 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 0) Test.180; let Test.213 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 0) Test.180;
let Test.214 : U8 = 1i64; let Test.214 : U8 = 1i64;
@ -123,11 +121,11 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2):
let Test.212 : Int1 = true; let Test.212 : Int1 = true;
let Test.217 : Int1 = lowlevel Eq Test.212 Test.211; let Test.217 : Int1 = lowlevel Eq Test.212 Test.211;
if Test.217 then if Test.217 then
jump Test.199 #Derived_gen.226; jump Test.199 #Derived_gen.201;
else else
jump Test.216 #Derived_gen.226; jump Test.216 #Derived_gen.201;
else else
jump Test.216 #Derived_gen.226; jump Test.216 #Derived_gen.201;
in in
let Test.222 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 2) Test.180; let Test.222 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 2) Test.180;
let Test.223 : U8 = 1i64; let Test.223 : U8 = 1i64;
@ -139,7 +137,7 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2):
let Test.221 : Int1 = true; let Test.221 : Int1 = true;
let Test.226 : Int1 = lowlevel Eq Test.221 Test.220; let Test.226 : Int1 = lowlevel Eq Test.221 Test.220;
if Test.226 then if Test.226 then
joinpoint Test.207 #Derived_gen.233: joinpoint Test.207 #Derived_gen.206:
let Test.33 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 0) Test.180; let Test.33 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 0) Test.180;
let Test.35 : I64 = UnionAtIndex (Id 1) (Index 1) Test.180; let Test.35 : I64 = UnionAtIndex (Id 1) (Index 1) Test.180;
let Test.200 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 2) Test.180; let Test.200 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 2) Test.180;
@ -150,27 +148,26 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2):
inc Test.39; inc Test.39;
let Test.37 : I32 = UnionAtIndex (Id 1) (Index 3) Test.200; let Test.37 : I32 = UnionAtIndex (Id 1) (Index 3) Test.200;
let Test.34 : I32 = UnionAtIndex (Id 1) (Index 3) Test.180; let Test.34 : I32 = UnionAtIndex (Id 1) (Index 3) Test.180;
joinpoint #Derived_gen.70 #Derived_gen.236 #Derived_gen.237 #Derived_gen.238: joinpoint #Derived_gen.70 #Derived_gen.208 #Derived_gen.209 #Derived_gen.210:
let Test.192 : Int1 = false; let Test.192 : Int1 = false;
let Test.189 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.238 UpdateModeId { id: 107 } TagId(1) Test.33 Test.35 Test.36 Test.34 Test.192; let Test.189 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.210 UpdateModeId { id: 107 } TagId(1) Test.33 Test.35 Test.36 Test.34 Test.192;
let Test.191 : Int1 = false; let Test.191 : Int1 = false;
let Test.190 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.237 UpdateModeId { id: 106 } TagId(1) Test.39 Test.18 Test.19 Test.17 Test.191; let Test.190 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.209 UpdateModeId { id: 106 } TagId(1) Test.39 Test.18 Test.19 Test.17 Test.191;
let Test.188 : Int1 = true; let Test.188 : Int1 = true;
let Test.187 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.236 UpdateModeId { id: 105 } TagId(1) Test.189 Test.38 Test.190 Test.37 Test.188; let Test.187 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.208 UpdateModeId { id: 105 } TagId(1) Test.189 Test.38 Test.190 Test.37 Test.188;
let #Derived_gen.18 : {} = lowlevel PtrStore #Derived_gen.6 Test.187; let #Derived_gen.18 : {} = lowlevel PtrStore #Derived_gen.6 Test.187;
let #Derived_gen.17 : [<rnu>C *self I64 *self I32 Int1, <null>] = lowlevel PtrLoad #Derived_gen.7; let #Derived_gen.17 : [<rnu>C *self I64 *self I32 Int1, <null>] = lowlevel PtrLoad #Derived_gen.7;
ret #Derived_gen.17; ret #Derived_gen.17;
in in
let #Derived_gen.71 : Int1 = lowlevel RefCountIsUnique Test.180; let #Derived_gen.71 : Int1 = lowlevel RefCountIsUnique Test.180;
if #Derived_gen.71 then if #Derived_gen.71 then
let #Derived_gen.239 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reset { symbol: Test.200, id: UpdateModeId { id: 108 } }; let #Derived_gen.211 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reset { symbol: Test.200, id: UpdateModeId { id: 108 } };
let #Derived_gen.240 : [<rnu>C *self I64 *self I32 Int1, <null>] = ResetRef { symbol: Test.180, id: UpdateModeId { id: 109 } }; jump #Derived_gen.70 #Derived_gen.206 #Derived_gen.211 Test.180;
jump #Derived_gen.70 #Derived_gen.233 #Derived_gen.239 #Derived_gen.240;
else else
inc Test.33; inc Test.33;
decref Test.180; decref Test.180;
let #Derived_gen.241 : [<rnu>C *self I64 *self I32 Int1, <null>] = NullPointer; let #Derived_gen.212 : [<rnu>C *self I64 *self I32 Int1, <null>] = NullPointer;
jump #Derived_gen.70 #Derived_gen.241 #Derived_gen.241 #Derived_gen.233; jump #Derived_gen.70 #Derived_gen.212 #Derived_gen.212 #Derived_gen.206;
in in
let Test.204 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 0) Test.180; let Test.204 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 0) Test.180;
let Test.205 : U8 = 1i64; let Test.205 : U8 = 1i64;
@ -182,33 +179,33 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2):
let Test.203 : Int1 = true; let Test.203 : Int1 = true;
let Test.208 : Int1 = lowlevel Eq Test.203 Test.202; let Test.208 : Int1 = lowlevel Eq Test.203 Test.202;
if Test.208 then if Test.208 then
jump Test.199 #Derived_gen.119; jump Test.199 #Derived_gen.118;
else else
jump Test.207 #Derived_gen.119; jump Test.207 #Derived_gen.118;
else else
jump Test.207 #Derived_gen.119; jump Test.207 #Derived_gen.118;
else else
jump Test.225 #Derived_gen.119; jump Test.225 #Derived_gen.118;
else else
jump Test.225 #Derived_gen.119; jump Test.225 #Derived_gen.118;
else else
decref #Derived_gen.119; decref #Derived_gen.118;
dec Test.19; dec Test.19;
let Test.197 : [<rnu>C *self I64 *self I32 Int1, <null>] = TagId(0) ; let Test.197 : [<rnu>C *self I64 *self I32 Int1, <null>] = TagId(0) ;
let #Derived_gen.20 : {} = lowlevel PtrStore #Derived_gen.6 Test.197; let #Derived_gen.20 : {} = lowlevel PtrStore #Derived_gen.6 Test.197;
let #Derived_gen.19 : [<rnu>C *self I64 *self I32 Int1, <null>] = lowlevel PtrLoad #Derived_gen.7; let #Derived_gen.19 : [<rnu>C *self I64 *self I32 Int1, <null>] = lowlevel PtrLoad #Derived_gen.7;
ret #Derived_gen.19; ret #Derived_gen.19;
else else
jump Test.238 #Derived_gen.119; jump Test.238 #Derived_gen.118;
else else
jump Test.238 #Derived_gen.119; jump Test.238 #Derived_gen.118;
else else
let Test.117 : Int1 = CallByName Num.24 Test.10 Test.17; let Test.117 : Int1 = CallByName Num.24 Test.10 Test.17;
if Test.117 then if Test.117 then
joinpoint Test.176 #Derived_gen.333: joinpoint Test.176 #Derived_gen.288:
let Test.170 : Int1 = false; let Test.170 : Int1 = false;
let #Derived_gen.21 : [<rnu>C *self I64 *self I32 Int1, <null>] = NullPointer; let #Derived_gen.21 : [<rnu>C *self I64 *self I32 Int1, <null>] = NullPointer;
let Test.169 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.333 UpdateModeId { id: 196 } TagId(1) Test.16 Test.18 #Derived_gen.21 Test.17 Test.170; let Test.169 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.288 UpdateModeId { id: 196 } TagId(1) Test.16 Test.18 #Derived_gen.21 Test.17 Test.170;
let #Derived_gen.22 : Ptr([<rnu>C *self I64 *self I32 Int1, <null>]) = UnionFieldPtrAtIndex (Id 1) (Index 2) Test.169; let #Derived_gen.22 : Ptr([<rnu>C *self I64 *self I32 Int1, <null>]) = UnionFieldPtrAtIndex (Id 1) (Index 2) Test.169;
let #Derived_gen.23 : {} = lowlevel PtrStore #Derived_gen.6 Test.169; let #Derived_gen.23 : {} = lowlevel PtrStore #Derived_gen.6 Test.169;
jump #Derived_gen.5 Test.19 Test.10 Test.11 #Derived_gen.22 #Derived_gen.7; jump #Derived_gen.5 Test.19 Test.10 Test.11 #Derived_gen.22 #Derived_gen.7;
@ -222,9 +219,9 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2):
let Test.177 : Int1 = lowlevel Eq Test.173 Test.172; let Test.177 : Int1 = lowlevel Eq Test.173 Test.172;
if Test.177 then if Test.177 then
inc Test.19; inc Test.19;
let #Derived_gen.334 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reset { symbol: Test.16, id: UpdateModeId { id: 197 } }; let #Derived_gen.289 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reset { symbol: Test.16, id: UpdateModeId { id: 197 } };
let Test.118 : [<rnu>C *self I64 *self I32 Int1, <null>] = CallByName Test.3 Test.19 Test.10 Test.11; let Test.118 : [<rnu>C *self I64 *self I32 Int1, <null>] = CallByName Test.3 Test.19 Test.10 Test.11;
joinpoint Test.137 #Derived_gen.374 #Derived_gen.375: joinpoint Test.137 #Derived_gen.322 #Derived_gen.323:
let Test.136 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 0) Test.118; let Test.136 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 0) Test.118;
let Test.57 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 0) Test.136; let Test.57 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 0) Test.136;
inc Test.57; inc Test.57;
@ -235,58 +232,56 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2):
let Test.62 : I64 = UnionAtIndex (Id 1) (Index 1) Test.118; let Test.62 : I64 = UnionAtIndex (Id 1) (Index 1) Test.118;
let Test.63 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 2) Test.118; let Test.63 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 2) Test.118;
let Test.61 : I32 = UnionAtIndex (Id 1) (Index 3) Test.118; let Test.61 : I32 = UnionAtIndex (Id 1) (Index 3) Test.118;
joinpoint #Derived_gen.112 #Derived_gen.379 #Derived_gen.380 #Derived_gen.381: joinpoint #Derived_gen.112 #Derived_gen.326 #Derived_gen.327 #Derived_gen.328:
let Test.124 : Int1 = false; let Test.124 : Int1 = false;
let Test.121 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.381 UpdateModeId { id: 242 } TagId(1) Test.57 Test.59 Test.60 Test.58 Test.124; let Test.121 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.328 UpdateModeId { id: 242 } TagId(1) Test.57 Test.59 Test.60 Test.58 Test.124;
let Test.123 : Int1 = false; let Test.123 : Int1 = false;
let Test.122 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.380 UpdateModeId { id: 241 } TagId(1) Test.63 Test.18 Test.19 Test.17 Test.123; let Test.122 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.327 UpdateModeId { id: 241 } TagId(1) Test.63 Test.18 Test.19 Test.17 Test.123;
let Test.120 : Int1 = true; let Test.120 : Int1 = true;
let Test.119 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.379 UpdateModeId { id: 240 } TagId(1) Test.121 Test.62 Test.122 Test.61 Test.120; let Test.119 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.326 UpdateModeId { id: 240 } TagId(1) Test.121 Test.62 Test.122 Test.61 Test.120;
let #Derived_gen.25 : {} = lowlevel PtrStore #Derived_gen.6 Test.119; let #Derived_gen.25 : {} = lowlevel PtrStore #Derived_gen.6 Test.119;
let #Derived_gen.24 : [<rnu>C *self I64 *self I32 Int1, <null>] = lowlevel PtrLoad #Derived_gen.7; let #Derived_gen.24 : [<rnu>C *self I64 *self I32 Int1, <null>] = lowlevel PtrLoad #Derived_gen.7;
ret #Derived_gen.24; ret #Derived_gen.24;
in in
let #Derived_gen.113 : Int1 = lowlevel RefCountIsUnique Test.118; let #Derived_gen.113 : Int1 = lowlevel RefCountIsUnique Test.118;
if #Derived_gen.113 then if #Derived_gen.113 then
decref #Derived_gen.374; decref #Derived_gen.322;
let #Derived_gen.382 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reset { symbol: Test.136, id: UpdateModeId { id: 243 } }; let #Derived_gen.329 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reset { symbol: Test.136, id: UpdateModeId { id: 243 } };
let #Derived_gen.383 : [<rnu>C *self I64 *self I32 Int1, <null>] = ResetRef { symbol: Test.118, id: UpdateModeId { id: 244 } }; jump #Derived_gen.112 #Derived_gen.323 #Derived_gen.329 Test.118;
jump #Derived_gen.112 #Derived_gen.375 #Derived_gen.382 #Derived_gen.383;
else else
inc Test.63; inc Test.63;
decref Test.118; decref Test.118;
let #Derived_gen.384 : [<rnu>C *self I64 *self I32 Int1, <null>] = NullPointer; let #Derived_gen.330 : [<rnu>C *self I64 *self I32 Int1, <null>] = NullPointer;
jump #Derived_gen.112 #Derived_gen.384 #Derived_gen.374 #Derived_gen.375; jump #Derived_gen.112 #Derived_gen.330 #Derived_gen.322 #Derived_gen.323;
in in
let Test.166 : U8 = 1i64; let Test.166 : U8 = 1i64;
let Test.167 : U8 = GetTagId Test.118; let Test.167 : U8 = GetTagId Test.118;
let Test.168 : Int1 = lowlevel Eq Test.166 Test.167; let Test.168 : Int1 = lowlevel Eq Test.166 Test.167;
if Test.168 then if Test.168 then
joinpoint Test.163 #Derived_gen.396 #Derived_gen.397: joinpoint Test.163 #Derived_gen.340 #Derived_gen.341:
joinpoint Test.154 #Derived_gen.398 #Derived_gen.399: joinpoint Test.154 #Derived_gen.342 #Derived_gen.343:
let Test.83 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 0) Test.118; let Test.83 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 0) Test.118;
let Test.85 : I64 = UnionAtIndex (Id 1) (Index 1) Test.118; let Test.85 : I64 = UnionAtIndex (Id 1) (Index 1) Test.118;
let Test.86 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 2) Test.118; let Test.86 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 2) Test.118;
let Test.84 : I32 = UnionAtIndex (Id 1) (Index 3) Test.118; let Test.84 : I32 = UnionAtIndex (Id 1) (Index 3) Test.118;
joinpoint #Derived_gen.102 #Derived_gen.402 #Derived_gen.403: joinpoint #Derived_gen.102 #Derived_gen.345 #Derived_gen.346:
let Test.134 : Int1 = true; let Test.134 : Int1 = true;
let Test.133 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.403 UpdateModeId { id: 262 } TagId(1) Test.83 Test.85 Test.86 Test.84 Test.134; let Test.133 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.346 UpdateModeId { id: 262 } TagId(1) Test.83 Test.85 Test.86 Test.84 Test.134;
let Test.132 : Int1 = false; let Test.132 : Int1 = false;
let Test.131 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.402 UpdateModeId { id: 261 } TagId(1) Test.133 Test.18 Test.19 Test.17 Test.132; let Test.131 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.345 UpdateModeId { id: 261 } TagId(1) Test.133 Test.18 Test.19 Test.17 Test.132;
let #Derived_gen.27 : {} = lowlevel PtrStore #Derived_gen.6 Test.131; let #Derived_gen.27 : {} = lowlevel PtrStore #Derived_gen.6 Test.131;
let #Derived_gen.26 : [<rnu>C *self I64 *self I32 Int1, <null>] = lowlevel PtrLoad #Derived_gen.7; let #Derived_gen.26 : [<rnu>C *self I64 *self I32 Int1, <null>] = lowlevel PtrLoad #Derived_gen.7;
ret #Derived_gen.26; ret #Derived_gen.26;
in in
let #Derived_gen.103 : Int1 = lowlevel RefCountIsUnique Test.118; let #Derived_gen.103 : Int1 = lowlevel RefCountIsUnique Test.118;
if #Derived_gen.103 then if #Derived_gen.103 then
decref #Derived_gen.398; decref #Derived_gen.342;
let #Derived_gen.404 : [<rnu>C *self I64 *self I32 Int1, <null>] = ResetRef { symbol: Test.118, id: UpdateModeId { id: 263 } }; jump #Derived_gen.102 #Derived_gen.343 Test.118;
jump #Derived_gen.102 #Derived_gen.399 #Derived_gen.404;
else else
inc Test.83; inc Test.83;
inc Test.86; inc Test.86;
decref Test.118; decref Test.118;
jump #Derived_gen.102 #Derived_gen.398 #Derived_gen.399; jump #Derived_gen.102 #Derived_gen.342 #Derived_gen.343;
in in
let Test.151 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 0) Test.118; let Test.151 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 0) Test.118;
let Test.152 : U8 = 1i64; let Test.152 : U8 = 1i64;
@ -298,11 +293,11 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2):
let Test.150 : Int1 = true; let Test.150 : Int1 = true;
let Test.155 : Int1 = lowlevel Eq Test.150 Test.149; let Test.155 : Int1 = lowlevel Eq Test.150 Test.149;
if Test.155 then if Test.155 then
jump Test.137 #Derived_gen.396 #Derived_gen.397; jump Test.137 #Derived_gen.340 #Derived_gen.341;
else else
jump Test.154 #Derived_gen.396 #Derived_gen.397; jump Test.154 #Derived_gen.340 #Derived_gen.341;
else else
jump Test.154 #Derived_gen.396 #Derived_gen.397; jump Test.154 #Derived_gen.340 #Derived_gen.341;
in in
let Test.160 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 2) Test.118; let Test.160 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 2) Test.118;
let Test.161 : U8 = 1i64; let Test.161 : U8 = 1i64;
@ -314,7 +309,7 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2):
let Test.159 : Int1 = true; let Test.159 : Int1 = true;
let Test.164 : Int1 = lowlevel Eq Test.159 Test.158; let Test.164 : Int1 = lowlevel Eq Test.159 Test.158;
if Test.164 then if Test.164 then
joinpoint Test.145 #Derived_gen.405 #Derived_gen.406: joinpoint Test.145 #Derived_gen.347 #Derived_gen.348:
let Test.70 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 0) Test.118; let Test.70 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 0) Test.118;
let Test.72 : I64 = UnionAtIndex (Id 1) (Index 1) Test.118; let Test.72 : I64 = UnionAtIndex (Id 1) (Index 1) Test.118;
let Test.138 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 2) Test.118; let Test.138 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 2) Test.118;
@ -325,28 +320,27 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2):
inc Test.76; inc Test.76;
let Test.74 : I32 = UnionAtIndex (Id 1) (Index 3) Test.138; let Test.74 : I32 = UnionAtIndex (Id 1) (Index 3) Test.138;
let Test.71 : I32 = UnionAtIndex (Id 1) (Index 3) Test.118; let Test.71 : I32 = UnionAtIndex (Id 1) (Index 3) Test.118;
joinpoint #Derived_gen.106 #Derived_gen.410 #Derived_gen.411 #Derived_gen.412: joinpoint #Derived_gen.106 #Derived_gen.351 #Derived_gen.352 #Derived_gen.353:
let Test.130 : Int1 = false; let Test.130 : Int1 = false;
let Test.127 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.412 UpdateModeId { id: 271 } TagId(1) Test.70 Test.72 Test.73 Test.71 Test.130; let Test.127 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.353 UpdateModeId { id: 271 } TagId(1) Test.70 Test.72 Test.73 Test.71 Test.130;
let Test.129 : Int1 = false; let Test.129 : Int1 = false;
let Test.128 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.411 UpdateModeId { id: 270 } TagId(1) Test.76 Test.18 Test.19 Test.17 Test.129; let Test.128 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.352 UpdateModeId { id: 270 } TagId(1) Test.76 Test.18 Test.19 Test.17 Test.129;
let Test.126 : Int1 = true; let Test.126 : Int1 = true;
let Test.125 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.410 UpdateModeId { id: 269 } TagId(1) Test.127 Test.75 Test.128 Test.74 Test.126; let Test.125 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.351 UpdateModeId { id: 269 } TagId(1) Test.127 Test.75 Test.128 Test.74 Test.126;
let #Derived_gen.29 : {} = lowlevel PtrStore #Derived_gen.6 Test.125; let #Derived_gen.29 : {} = lowlevel PtrStore #Derived_gen.6 Test.125;
let #Derived_gen.28 : [<rnu>C *self I64 *self I32 Int1, <null>] = lowlevel PtrLoad #Derived_gen.7; let #Derived_gen.28 : [<rnu>C *self I64 *self I32 Int1, <null>] = lowlevel PtrLoad #Derived_gen.7;
ret #Derived_gen.28; ret #Derived_gen.28;
in in
let #Derived_gen.107 : Int1 = lowlevel RefCountIsUnique Test.118; let #Derived_gen.107 : Int1 = lowlevel RefCountIsUnique Test.118;
if #Derived_gen.107 then if #Derived_gen.107 then
decref #Derived_gen.405; decref #Derived_gen.347;
let #Derived_gen.413 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reset { symbol: Test.138, id: UpdateModeId { id: 272 } }; let #Derived_gen.354 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reset { symbol: Test.138, id: UpdateModeId { id: 272 } };
let #Derived_gen.414 : [<rnu>C *self I64 *self I32 Int1, <null>] = ResetRef { symbol: Test.118, id: UpdateModeId { id: 273 } }; jump #Derived_gen.106 #Derived_gen.348 #Derived_gen.354 Test.118;
jump #Derived_gen.106 #Derived_gen.406 #Derived_gen.413 #Derived_gen.414;
else else
inc Test.70; inc Test.70;
decref Test.118; decref Test.118;
let #Derived_gen.415 : [<rnu>C *self I64 *self I32 Int1, <null>] = NullPointer; let #Derived_gen.355 : [<rnu>C *self I64 *self I32 Int1, <null>] = NullPointer;
jump #Derived_gen.106 #Derived_gen.415 #Derived_gen.405 #Derived_gen.406; jump #Derived_gen.106 #Derived_gen.355 #Derived_gen.347 #Derived_gen.348;
in in
let Test.142 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 0) Test.118; let Test.142 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 0) Test.118;
let Test.143 : U8 = 1i64; let Test.143 : U8 = 1i64;
@ -358,18 +352,18 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2):
let Test.141 : Int1 = true; let Test.141 : Int1 = true;
let Test.146 : Int1 = lowlevel Eq Test.141 Test.140; let Test.146 : Int1 = lowlevel Eq Test.141 Test.140;
if Test.146 then if Test.146 then
jump Test.137 #Derived_gen.119 #Derived_gen.334; jump Test.137 #Derived_gen.118 #Derived_gen.289;
else else
jump Test.145 #Derived_gen.119 #Derived_gen.334; jump Test.145 #Derived_gen.118 #Derived_gen.289;
else else
jump Test.145 #Derived_gen.119 #Derived_gen.334; jump Test.145 #Derived_gen.118 #Derived_gen.289;
else else
jump Test.163 #Derived_gen.119 #Derived_gen.334; jump Test.163 #Derived_gen.118 #Derived_gen.289;
else else
jump Test.163 #Derived_gen.119 #Derived_gen.334; jump Test.163 #Derived_gen.118 #Derived_gen.289;
else else
decref #Derived_gen.334; decref #Derived_gen.289;
decref #Derived_gen.119; decref #Derived_gen.118;
joinpoint #Derived_gen.108: joinpoint #Derived_gen.108:
let Test.135 : [<rnu>C *self I64 *self I32 Int1, <null>] = TagId(0) ; let Test.135 : [<rnu>C *self I64 *self I32 Int1, <null>] = TagId(0) ;
let #Derived_gen.31 : {} = lowlevel PtrStore #Derived_gen.6 Test.135; let #Derived_gen.31 : {} = lowlevel PtrStore #Derived_gen.6 Test.135;
@ -382,43 +376,42 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2):
dec #Derived_gen.110; dec #Derived_gen.110;
let #Derived_gen.109 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 2) Test.19; let #Derived_gen.109 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 2) Test.19;
dec #Derived_gen.109; dec #Derived_gen.109;
decref Test.19; free Test.19;
jump #Derived_gen.108; jump #Derived_gen.108;
else else
decref Test.19; decref Test.19;
jump #Derived_gen.108; jump #Derived_gen.108;
else else
jump Test.176 #Derived_gen.119; jump Test.176 #Derived_gen.118;
else else
jump Test.176 #Derived_gen.119; jump Test.176 #Derived_gen.118;
else else
let Test.116 : Int1 = false; let Test.116 : Int1 = false;
let Test.115 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.119 UpdateModeId { id: 1 } TagId(1) Test.16 Test.11 Test.19 Test.10 Test.116; let Test.115 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.118 UpdateModeId { id: 1 } TagId(1) Test.16 Test.11 Test.19 Test.10 Test.116;
let #Derived_gen.33 : {} = lowlevel PtrStore #Derived_gen.6 Test.115; let #Derived_gen.33 : {} = lowlevel PtrStore #Derived_gen.6 Test.115;
let #Derived_gen.32 : [<rnu>C *self I64 *self I32 Int1, <null>] = lowlevel PtrLoad #Derived_gen.7; let #Derived_gen.32 : [<rnu>C *self I64 *self I32 Int1, <null>] = lowlevel PtrLoad #Derived_gen.7;
ret #Derived_gen.32; ret #Derived_gen.32;
in in
let #Derived_gen.115 : Int1 = lowlevel RefCountIsUnique Test.9; let #Derived_gen.115 : Int1 = lowlevel RefCountIsUnique Test.9;
if #Derived_gen.115 then if #Derived_gen.115 then
let #Derived_gen.424 : [<rnu>C *self I64 *self I32 Int1, <null>] = ResetRef { symbol: Test.9, id: UpdateModeId { id: 282 } }; jump #Derived_gen.114 Test.9;
jump #Derived_gen.114 #Derived_gen.424;
else else
inc Test.16; inc Test.16;
inc Test.19; inc Test.19;
decref Test.9; decref Test.9;
let #Derived_gen.425 : [<rnu>C *self I64 *self I32 Int1, <null>] = NullPointer; let #Derived_gen.363 : [<rnu>C *self I64 *self I32 Int1, <null>] = NullPointer;
jump #Derived_gen.114 #Derived_gen.425; jump #Derived_gen.114 #Derived_gen.363;
else else
let Test.96 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 0) Test.9; let Test.96 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 0) Test.9;
let Test.98 : I64 = UnionAtIndex (Id 1) (Index 1) Test.9; let Test.98 : I64 = UnionAtIndex (Id 1) (Index 1) Test.9;
let Test.99 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 2) Test.9; let Test.99 : [<rnu>C *self I64 *self I32 Int1, <null>] = UnionAtIndex (Id 1) (Index 2) Test.9;
let Test.97 : I32 = UnionAtIndex (Id 1) (Index 3) Test.9; let Test.97 : I32 = UnionAtIndex (Id 1) (Index 3) Test.9;
joinpoint #Derived_gen.116 #Derived_gen.427: joinpoint #Derived_gen.116 #Derived_gen.364:
let Test.247 : Int1 = CallByName Num.22 Test.10 Test.97; let Test.247 : Int1 = CallByName Num.22 Test.10 Test.97;
if Test.247 then if Test.247 then
let Test.249 : Int1 = true; let Test.249 : Int1 = true;
let #Derived_gen.34 : [<rnu>C *self I64 *self I32 Int1, <null>] = NullPointer; let #Derived_gen.34 : [<rnu>C *self I64 *self I32 Int1, <null>] = NullPointer;
let Test.248 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.427 UpdateModeId { id: 284 } TagId(1) #Derived_gen.34 Test.98 Test.99 Test.97 Test.249; let Test.248 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.364 UpdateModeId { id: 284 } TagId(1) #Derived_gen.34 Test.98 Test.99 Test.97 Test.249;
let #Derived_gen.35 : Ptr([<rnu>C *self I64 *self I32 Int1, <null>]) = UnionFieldPtrAtIndex (Id 1) (Index 0) Test.248; let #Derived_gen.35 : Ptr([<rnu>C *self I64 *self I32 Int1, <null>]) = UnionFieldPtrAtIndex (Id 1) (Index 0) Test.248;
let #Derived_gen.36 : {} = lowlevel PtrStore #Derived_gen.6 Test.248; let #Derived_gen.36 : {} = lowlevel PtrStore #Derived_gen.6 Test.248;
jump #Derived_gen.5 Test.96 Test.10 Test.11 #Derived_gen.35 #Derived_gen.7; jump #Derived_gen.5 Test.96 Test.10 Test.11 #Derived_gen.35 #Derived_gen.7;
@ -427,27 +420,26 @@ procedure Test.3 (#Derived_gen.0, #Derived_gen.1, #Derived_gen.2):
if Test.243 then if Test.243 then
let Test.245 : Int1 = true; let Test.245 : Int1 = true;
let #Derived_gen.37 : [<rnu>C *self I64 *self I32 Int1, <null>] = NullPointer; let #Derived_gen.37 : [<rnu>C *self I64 *self I32 Int1, <null>] = NullPointer;
let Test.244 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.427 UpdateModeId { id: 284 } TagId(1) Test.96 Test.98 #Derived_gen.37 Test.97 Test.245; let Test.244 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.364 UpdateModeId { id: 284 } TagId(1) Test.96 Test.98 #Derived_gen.37 Test.97 Test.245;
let #Derived_gen.38 : Ptr([<rnu>C *self I64 *self I32 Int1, <null>]) = UnionFieldPtrAtIndex (Id 1) (Index 2) Test.244; let #Derived_gen.38 : Ptr([<rnu>C *self I64 *self I32 Int1, <null>]) = UnionFieldPtrAtIndex (Id 1) (Index 2) Test.244;
let #Derived_gen.39 : {} = lowlevel PtrStore #Derived_gen.6 Test.244; let #Derived_gen.39 : {} = lowlevel PtrStore #Derived_gen.6 Test.244;
jump #Derived_gen.5 Test.99 Test.10 Test.11 #Derived_gen.38 #Derived_gen.7; jump #Derived_gen.5 Test.99 Test.10 Test.11 #Derived_gen.38 #Derived_gen.7;
else else
let Test.242 : Int1 = true; let Test.242 : Int1 = true;
let Test.241 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.427 UpdateModeId { id: 284 } TagId(1) Test.96 Test.11 Test.99 Test.10 Test.242; let Test.241 : [<rnu>C *self I64 *self I32 Int1, <null>] = Reuse #Derived_gen.364 UpdateModeId { id: 284 } TagId(1) Test.96 Test.11 Test.99 Test.10 Test.242;
let #Derived_gen.41 : {} = lowlevel PtrStore #Derived_gen.6 Test.241; let #Derived_gen.41 : {} = lowlevel PtrStore #Derived_gen.6 Test.241;
let #Derived_gen.40 : [<rnu>C *self I64 *self I32 Int1, <null>] = lowlevel PtrLoad #Derived_gen.7; let #Derived_gen.40 : [<rnu>C *self I64 *self I32 Int1, <null>] = lowlevel PtrLoad #Derived_gen.7;
ret #Derived_gen.40; ret #Derived_gen.40;
in in
let #Derived_gen.117 : Int1 = lowlevel RefCountIsUnique Test.9; let #Derived_gen.117 : Int1 = lowlevel RefCountIsUnique Test.9;
if #Derived_gen.117 then if #Derived_gen.117 then
let #Derived_gen.428 : [<rnu>C *self I64 *self I32 Int1, <null>] = ResetRef { symbol: Test.9, id: UpdateModeId { id: 285 } }; jump #Derived_gen.116 Test.9;
jump #Derived_gen.116 #Derived_gen.428;
else else
inc Test.96; inc Test.96;
inc Test.99; inc Test.99;
decref Test.9; decref Test.9;
let #Derived_gen.429 : [<rnu>C *self I64 *self I32 Int1, <null>] = NullPointer; let #Derived_gen.365 : [<rnu>C *self I64 *self I32 Int1, <null>] = NullPointer;
jump #Derived_gen.116 #Derived_gen.429; jump #Derived_gen.116 #Derived_gen.365;
in in
jump #Derived_gen.5 #Derived_gen.0 #Derived_gen.1 #Derived_gen.2 #Derived_gen.3 #Derived_gen.3; jump #Derived_gen.5 #Derived_gen.0 #Derived_gen.1 #Derived_gen.2 #Derived_gen.3 #Derived_gen.3;

View file

@ -44,7 +44,7 @@ procedure Test.6 (Test.16, #Attr.12):
in in
let #Derived_gen.3 : Int1 = lowlevel RefCountIsUnique #Attr.12; let #Derived_gen.3 : Int1 = lowlevel RefCountIsUnique #Attr.12;
if #Derived_gen.3 then if #Derived_gen.3 then
decref #Attr.12; free #Attr.12;
jump #Derived_gen.2; jump #Derived_gen.2;
else else
decref #Attr.12; decref #Attr.12;

View file

@ -54,7 +54,7 @@ procedure Test.4 (#Derived_gen.2, #Derived_gen.3):
in in
let #Derived_gen.5 : Int1 = lowlevel RefCountIsUnique #Attr.12; let #Derived_gen.5 : Int1 = lowlevel RefCountIsUnique #Attr.12;
if #Derived_gen.5 then if #Derived_gen.5 then
decref #Attr.12; free #Attr.12;
jump #Derived_gen.4; jump #Derived_gen.4;
else else
inc Test.3; inc Test.3;

View file

@ -10,7 +10,7 @@ procedure Test.11 (Test.29, #Attr.12):
let Test.10 : {} = UnionAtIndex (Id 0) (Index 0) #Attr.12; let Test.10 : {} = UnionAtIndex (Id 0) (Index 0) #Attr.12;
let #Derived_gen.9 : Int1 = lowlevel RefCountIsUnique #Attr.12; let #Derived_gen.9 : Int1 = lowlevel RefCountIsUnique #Attr.12;
if #Derived_gen.9 then if #Derived_gen.9 then
decref #Attr.12; free #Attr.12;
ret Test.10; ret Test.10;
else else
decref #Attr.12; decref #Attr.12;
@ -40,7 +40,7 @@ procedure Test.14 (#Derived_gen.2, #Derived_gen.3):
in in
let #Derived_gen.11 : Int1 = lowlevel RefCountIsUnique #Attr.12; let #Derived_gen.11 : Int1 = lowlevel RefCountIsUnique #Attr.12;
if #Derived_gen.11 then if #Derived_gen.11 then
decref #Attr.12; free #Attr.12;
jump #Derived_gen.10; jump #Derived_gen.10;
else else
decref #Attr.12; decref #Attr.12;

View file

@ -39,7 +39,7 @@ procedure Test.2 (Test.9, Test.10):
let #Derived_gen.5 : Int1 = lowlevel RefCountIsUnique Test.9; let #Derived_gen.5 : Int1 = lowlevel RefCountIsUnique Test.9;
if #Derived_gen.5 then if #Derived_gen.5 then
dec Test.11; dec Test.11;
decref Test.9; free Test.9;
jump #Derived_gen.4; jump #Derived_gen.4;
else else
inc Test.12; inc Test.12;
@ -65,7 +65,7 @@ procedure Test.3 (Test.17):
if #Derived_gen.3 then if #Derived_gen.3 then
let #Derived_gen.2 : Str = UnionAtIndex (Id 0) (Index 0) Test.17; let #Derived_gen.2 : Str = UnionAtIndex (Id 0) (Index 0) Test.17;
dec #Derived_gen.2; dec #Derived_gen.2;
decref Test.17; free Test.17;
jump #Derived_gen.1; jump #Derived_gen.1;
else else
inc Test.18; inc Test.18;