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

@ -1180,8 +1180,14 @@ pub(crate) fn build_exp_expr<'a, 'ctx>(
let then_block = ctx.append_basic_block(parent, "then_reset");
let else_block = ctx.append_basic_block(parent, "else_decref");
let refcount_ptr =
PointerToRefcount::from_ptr_to_data(env, tag_pointer_clear_tag_id(env, tag_ptr));
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 {
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 refcount_ptr =
PointerToRefcount::from_ptr_to_data(env, tag_pointer_clear_tag_id(env, tag_ptr));
// reset is only generated for union values
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 {
UpdateMode::InPlace => env.context.bool_type().const_int(1, false),
@ -2930,6 +2948,39 @@ pub(crate) fn build_exp_stmt<'a, 'ctx>(
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")
}
PtrClearTagId => {
arguments!(ptr);
tag_pointer_clear_tag_id(env, ptr.into_pointer_value()).into()
}
Alloca => {
arguments!(initial_value);

View file

@ -14,7 +14,7 @@ use bumpalo::collections::Vec;
use inkwell::basic_block::BasicBlock;
use inkwell::module::Linkage;
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 roc_module::symbol::Interns;
use roc_module::symbol::Symbol;
@ -193,6 +193,14 @@ impl<'ctx> PointerToRefcount<'ctx> {
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>(
@ -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) {
let alignment = env.context.i32_type().const_int(alignment as _, false);
call_void_bitcode_fn(