have zig allocate all refcounts

This commit is contained in:
Brendan Hansknecht 2022-04-01 14:06:28 -07:00
parent 805e4ef5d3
commit 577282ced3
6 changed files with 32 additions and 88 deletions

View file

@ -155,6 +155,7 @@ comptime {
exportUtilsFn(utils.increfC, "incref"); exportUtilsFn(utils.increfC, "incref");
exportUtilsFn(utils.decrefC, "decref"); exportUtilsFn(utils.decrefC, "decref");
exportUtilsFn(utils.decrefCheckNullC, "decref_check_null"); exportUtilsFn(utils.decrefCheckNullC, "decref_check_null");
exportUtilsFn(utils.allocateWithRefcountC, "allocate_with_refcount");
exportExpectFn(expect.expectFailedC, "expect_failed"); exportExpectFn(expect.expectFailedC, "expect_failed");
exportExpectFn(expect.getExpectFailuresC, "get_expect_failures"); exportExpectFn(expect.getExpectFailuresC, "get_expect_failures");
exportExpectFn(expect.deinitFailuresC, "deinit_failures"); exportExpectFn(expect.deinitFailuresC, "deinit_failures");

View file

@ -208,6 +208,13 @@ inline fn decref_ptr_to_refcount(
} }
} }
pub fn allocateWithRefcountC(
data_bytes: usize,
element_alignment: u32,
) callconv(.C) [*]u8 {
return allocateWithRefcount(data_bytes, element_alignment);
}
pub fn allocateWithRefcount( pub fn allocateWithRefcount(
data_bytes: usize, data_bytes: usize,
element_alignment: u32, element_alignment: u32,

View file

@ -371,6 +371,7 @@ pub const DEC_MUL_WITH_OVERFLOW: &str = "roc_builtins.dec.mul_with_overflow";
pub const DEC_DIV: &str = "roc_builtins.dec.div"; pub const DEC_DIV: &str = "roc_builtins.dec.div";
pub const UTILS_TEST_PANIC: &str = "roc_builtins.utils.test_panic"; 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_INCREF: &str = "roc_builtins.utils.incref"; pub const UTILS_INCREF: &str = "roc_builtins.utils.incref";
pub const UTILS_DECREF: &str = "roc_builtins.utils.decref"; pub const UTILS_DECREF: &str = "roc_builtins.utils.decref";
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";

View file

@ -2127,15 +2127,11 @@ fn reserve_with_refcount_help<'a, 'ctx, 'env>(
stack_size: u32, stack_size: u32,
alignment_bytes: u32, alignment_bytes: u32,
) -> PointerValue<'ctx> { ) -> PointerValue<'ctx> {
let ctx = env.context;
let len_type = env.ptr_int(); let len_type = env.ptr_int();
let value_bytes_intvalue = len_type.const_int(stack_size as u64, false); let value_bytes_intvalue = len_type.const_int(stack_size as u64, false);
let rc1 = crate::llvm::refcounting::refcount_1(ctx, env.target_info); allocate_with_refcount_help(env, basic_type, alignment_bytes, value_bytes_intvalue)
allocate_with_refcount_help(env, basic_type, alignment_bytes, value_bytes_intvalue, rc1)
} }
pub fn allocate_with_refcount<'a, 'ctx, 'env>( pub fn allocate_with_refcount<'a, 'ctx, 'env>(
@ -2156,74 +2152,22 @@ pub fn allocate_with_refcount_help<'a, 'ctx, 'env>(
value_type: impl BasicType<'ctx>, value_type: impl BasicType<'ctx>,
alignment_bytes: u32, alignment_bytes: u32,
number_of_data_bytes: IntValue<'ctx>, number_of_data_bytes: IntValue<'ctx>,
initial_refcount: IntValue<'ctx>,
) -> PointerValue<'ctx> { ) -> PointerValue<'ctx> {
let builder = env.builder; let ptr = call_bitcode_fn(
env,
&[
number_of_data_bytes.into(),
env.alignment_const(alignment_bytes).into(),
],
roc_builtins::bitcode::UTILS_ALLOCATE_WITH_REFCOUNT,
)
.into_pointer_value();
let len_type = env.ptr_int(); let ptr_type = value_type.ptr_type(AddressSpace::Generic);
let ptr_width_u32 = env.target_info.ptr_width() as u32;
let extra_bytes = alignment_bytes.max(ptr_width_u32); env.builder
.build_bitcast(ptr, ptr_type, "alloc_cast_to_desired")
let ptr = { .into_pointer_value()
// number of bytes we will allocated
let number_of_bytes = builder.build_int_add(
len_type.const_int(extra_bytes as u64, false),
number_of_data_bytes,
"add_extra_bytes",
);
env.call_alloc(number_of_bytes, alignment_bytes)
};
// We must return a pointer to the first element:
let data_ptr = {
let int_type = env.ptr_int();
let as_usize_ptr = builder
.build_bitcast(
ptr,
int_type.ptr_type(AddressSpace::Generic),
"to_usize_ptr",
)
.into_pointer_value();
let index = match extra_bytes {
n if n == ptr_width_u32 => 1,
n if n == 2 * ptr_width_u32 => 2,
_ => unreachable!("invalid extra_bytes, {}", extra_bytes),
};
let index_intvalue = int_type.const_int(index, false);
let ptr_type = value_type.ptr_type(AddressSpace::Generic);
unsafe {
builder.build_pointer_cast(
env.builder
.build_in_bounds_gep(as_usize_ptr, &[index_intvalue], "get_data_ptr"),
ptr_type,
"alloc_cast_to_desired",
)
}
};
let refcount_ptr = match extra_bytes {
n if n == ptr_width_u32 => {
// the allocated pointer is the same as the refcounted pointer
unsafe { PointerToRefcount::from_ptr(env, ptr) }
}
n if n == 2 * ptr_width_u32 => {
// the refcount is stored just before the start of the actual data
// but in this case (because of alignment) not at the start of the allocated buffer
PointerToRefcount::from_ptr_to_data(env, data_ptr)
}
n => unreachable!("invalid extra_bytes {}", n),
};
// let rc1 = crate::llvm::refcounting::refcount_1(ctx, env.ptr_bytes);
refcount_ptr.set_refcount(env, initial_refcount);
data_ptr
} }
macro_rules! dict_key_value_layout { macro_rules! dict_key_value_layout {

View file

@ -1259,7 +1259,6 @@ pub fn allocate_list<'a, 'ctx, 'env>(
number_of_elements: IntValue<'ctx>, number_of_elements: IntValue<'ctx>,
) -> PointerValue<'ctx> { ) -> PointerValue<'ctx> {
let builder = env.builder; let builder = env.builder;
let ctx = env.context;
let len_type = env.ptr_int(); let len_type = env.ptr_int();
let elem_bytes = elem_layout.stack_size(env.target_info) as u64; let elem_bytes = elem_layout.stack_size(env.target_info) as u64;
@ -1267,13 +1266,9 @@ pub fn allocate_list<'a, 'ctx, 'env>(
let number_of_data_bytes = let number_of_data_bytes =
builder.build_int_mul(bytes_per_element, number_of_elements, "data_length"); builder.build_int_mul(bytes_per_element, number_of_elements, "data_length");
// the refcount of a new list is initially 1
// we assume that the list is indeed used (dead variables are eliminated)
let rc1 = crate::llvm::refcounting::refcount_1(ctx, env.target_info);
let basic_type = basic_type_from_layout(env, elem_layout); let basic_type = basic_type_from_layout(env, elem_layout);
let alignment_bytes = elem_layout.alignment_bytes(env.target_info); let alignment_bytes = elem_layout.alignment_bytes(env.target_info);
allocate_with_refcount_help(env, basic_type, alignment_bytes, number_of_data_bytes, rc1) allocate_with_refcount_help(env, basic_type, alignment_bytes, number_of_data_bytes)
} }
pub fn store_list<'a, 'ctx, 'env>( pub fn store_list<'a, 'ctx, 'env>(

View file

@ -23,17 +23,6 @@ use roc_target::TargetInfo;
use super::build::load_roc_value; use super::build::load_roc_value;
use super::convert::{argument_type_from_layout, argument_type_from_union_layout}; use super::convert::{argument_type_from_layout, argument_type_from_union_layout};
/// "Infinite" reference count, for static values
/// Ref counts are encoded as negative numbers where isize::MIN represents 1
pub const REFCOUNT_MAX: usize = 0_usize;
pub fn refcount_1(ctx: &Context, target_info: TargetInfo) -> IntValue<'_> {
match target_info.ptr_width() {
roc_target::PtrWidth::Bytes4 => ctx.i32_type().const_int(i32::MIN as u64, false),
roc_target::PtrWidth::Bytes8 => ctx.i64_type().const_int(i64::MIN as u64, false),
}
}
pub struct PointerToRefcount<'ctx> { pub struct PointerToRefcount<'ctx> {
value: PointerValue<'ctx>, value: PointerValue<'ctx>,
} }
@ -96,7 +85,14 @@ impl<'ctx> PointerToRefcount<'ctx> {
pub fn is_1<'a, 'env>(&self, env: &Env<'a, 'ctx, 'env>) -> IntValue<'ctx> { pub fn is_1<'a, 'env>(&self, env: &Env<'a, 'ctx, 'env>) -> IntValue<'ctx> {
let current = self.get_refcount(env); let current = self.get_refcount(env);
let one = refcount_1(env.context, env.target_info); let one = match env.target_info.ptr_width() {
roc_target::PtrWidth::Bytes4 => {
env.context.i32_type().const_int(i32::MIN as u64, false)
}
roc_target::PtrWidth::Bytes8 => {
env.context.i64_type().const_int(i64::MIN as u64, false)
}
};
env.builder env.builder
.build_int_compare(IntPredicate::EQ, current, one, "is_one") .build_int_compare(IntPredicate::EQ, current, one, "is_one")