Update LLVM to properly increment and decrement lists

This commit is contained in:
Brendan Hansknecht 2024-04-04 22:36:07 -07:00
parent 255cc31ad9
commit 3c842196fa
No known key found for this signature in database
GPG key ID: 0EA784685083E75B
12 changed files with 337 additions and 176 deletions

View file

@ -0,0 +1,2 @@
pub const packages = struct {};
pub const root_deps: []const struct { []const u8, []const u8 } = &.{};

View file

@ -10,7 +10,7 @@ use std::{env, path::PathBuf, process::Command};
use tempfile::tempdir; use tempfile::tempdir;
/// To debug the zig code with debug prints, we need to disable the wasm code gen /// To debug the zig code with debug prints, we need to disable the wasm code gen
const DEBUG: bool = false; const DEBUG: bool = true;
fn main() { fn main() {
println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=build.rs");

View file

@ -10,7 +10,7 @@ use std::{env, path::PathBuf, process::Command};
use tempfile::tempdir; use tempfile::tempdir;
/// To debug the zig code with debug prints, we need to disable the wasm code gen /// To debug the zig code with debug prints, we need to disable the wasm code gen
const DEBUG: bool = false; const DEBUG: bool = true;
fn main() { fn main() {
println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=build.rs");

View file

@ -129,14 +129,24 @@ pub const RocList = extern struct {
} }
} }
// TODO: expose these both to roc and ensure lists always call them. // This needs to be called when creating seamless slices from unique list.
// It will put the allocation size on the heap to enable the seamless slice to free the underlying allocation.
fn setAllocationElementCount(self: RocList, elements_refcounted: bool) void {
if (elements_refcounted) {
// - 1 is refcount.
// - 2 is size on heap.
const ptr = @as([*]usize, @alignCast(@ptrCast(self.getAllocationPtr()))) - 2;
ptr[0] = self.length;
}
}
pub fn incref(self: RocList, amount: isize, elements_refcounted: bool) void { pub fn incref(self: RocList, amount: isize, elements_refcounted: bool) void {
// If the list is unique and not a seamless slice, the length needs to be store on the heap if the elements are refcounted. // If the list is unique and not a seamless slice, the length needs to be store on the heap if the elements are refcounted.
if (elements_refcounted and self.isUnique() and !self.isSeamlessSlice()) { if (elements_refcounted and self.isUnique() and !self.isSeamlessSlice()) {
// - 1 is refcount. // - 1 is refcount.
// - 2 is size on heap. // - 2 is size on heap.
const ptr = @as([*]usize, self.getAllocationPtr()) - 2; const ptr = @as([*]usize, @alignCast(@ptrCast(self.getAllocationPtr()))) - 2;
ptr.* = self.length; ptr[0] = self.length;
} }
utils.increfDataPtrC(self.getAllocationPtr(), amount); utils.increfDataPtrC(self.getAllocationPtr(), amount);
} }
@ -327,6 +337,14 @@ pub const RocList = extern struct {
} }
}; };
pub fn listIncref(list: RocList, amount: isize, elements_refcounted: bool) callconv(.C) void {
list.incref(amount, elements_refcounted);
}
pub fn listDecref(list: RocList, alignment: u32, element_width: usize, elements_refcounted: bool, dec: Dec) callconv(.C) void {
list.decref(alignment, element_width, elements_refcounted, dec);
}
const Caller0 = *const fn (?[*]u8, ?[*]u8) callconv(.C) void; const Caller0 = *const fn (?[*]u8, ?[*]u8) callconv(.C) void;
const Caller1 = *const fn (?[*]u8, ?[*]u8, ?[*]u8) callconv(.C) void; const Caller1 = *const fn (?[*]u8, ?[*]u8, ?[*]u8) callconv(.C) void;
const Caller2 = *const fn (?[*]u8, ?[*]u8, ?[*]u8, ?[*]u8) callconv(.C) void; const Caller2 = *const fn (?[*]u8, ?[*]u8, ?[*]u8, ?[*]u8) callconv(.C) void;
@ -686,6 +704,10 @@ pub fn listSwap(
dec: Dec, dec: Dec,
update_mode: UpdateMode, update_mode: UpdateMode,
) callconv(.C) RocList { ) callconv(.C) RocList {
// Early exit to avoid swapping the same element.
if (index_1 == index_2)
return list;
const size = @as(u64, @intCast(list.len())); const size = @as(u64, @intCast(list.len()));
if (index_1 == index_2 or index_1 >= size or index_2 >= size) { if (index_1 == index_2 or index_1 >= size or index_2 >= size) {
// Either one index was out of bounds, or both indices were the same; just return // Either one index was out of bounds, or both indices were the same; just return
@ -742,7 +764,6 @@ pub fn listSublist(
// This cast is lossless because we would have early-returned already // This cast is lossless because we would have early-returned already
// if `start_u64` were greater than `size`, and `size` fits in usize. // if `start_u64` were greater than `size`, and `size` fits in usize.
const start: usize = @intCast(start_u64); const start: usize = @intCast(start_u64);
const drop_start_len = start;
// (size - start) can't overflow because we would have early-returned already // (size - start) can't overflow because we would have early-returned already
// if `start` were greater than `size`. // if `start` were greater than `size`.
@ -753,32 +774,23 @@ pub fn listSublist(
// than something that fit in usize. // than something that fit in usize.
const keep_len = @as(usize, @intCast(@min(len_u64, @as(u64, @intCast(size_minus_start))))); const keep_len = @as(usize, @intCast(@min(len_u64, @as(u64, @intCast(size_minus_start)))));
// This can't overflow because if len > size_minus_start,
// then keep_len == size_minus_start and this will be 0.
// Alternatively, if len <= size_minus_start, then keep_len will
// be equal to len, meaning keep_len <= size_minus_start too,
// which in turn means this won't overflow.
const drop_end_len = size_minus_start - keep_len;
// Decrement the reference counts of elements before `start`.
var i: usize = 0;
while (i < drop_start_len) : (i += 1) {
const element = source_ptr + i * element_width;
dec(element);
}
// Decrement the reference counts of elements after `start + keep_len`.
i = 0;
while (i < drop_end_len) : (i += 1) {
const element = source_ptr + (start + keep_len + i) * element_width;
dec(element);
}
if (start == 0 and list.isUnique()) { if (start == 0 and list.isUnique()) {
// The list is unique, we actually have to decrement refcounts to elements we aren't keeping around.
// Decrement the reference counts of elements after `start + keep_len`.
const drop_end_len = size_minus_start - keep_len;
var i: usize = 0;
while (i < drop_end_len) : (i += 1) {
const element = source_ptr + (start + keep_len + i) * element_width;
dec(element);
}
var output = list; var output = list;
output.length = keep_len; output.length = keep_len;
return output; return output;
} else { } else {
if (list.isUnique()) {
list.setAllocationElementCount(elements_refcounted);
}
const list_alloc_ptr = (@intFromPtr(source_ptr) >> 1) | SEAMLESS_SLICE_BIT; const list_alloc_ptr = (@intFromPtr(source_ptr) >> 1) | SEAMLESS_SLICE_BIT;
const slice_alloc_ptr = list.capacity_or_alloc_ptr; const slice_alloc_ptr = list.capacity_or_alloc_ptr;
const slice_mask = list.seamlessSliceMask(); const slice_mask = list.seamlessSliceMask();

View file

@ -86,6 +86,8 @@ comptime {
exportListFn(list.listAllocationPtr, "allocation_ptr"); exportListFn(list.listAllocationPtr, "allocation_ptr");
exportListFn(list.listReleaseExcessCapacity, "release_excess_capacity"); exportListFn(list.listReleaseExcessCapacity, "release_excess_capacity");
exportListFn(list.listConcatUtf8, "concat_utf8"); exportListFn(list.listConcatUtf8, "concat_utf8");
exportListFn(list.listIncref, "incref");
exportListFn(list.listDecref, "decref");
} }
// Num Module // Num Module

View file

@ -391,6 +391,8 @@ pub const LIST_CAPACITY: &str = "roc_builtins.list.capacity";
pub const LIST_ALLOCATION_PTR: &str = "roc_builtins.list.allocation_ptr"; pub const LIST_ALLOCATION_PTR: &str = "roc_builtins.list.allocation_ptr";
pub const LIST_RELEASE_EXCESS_CAPACITY: &str = "roc_builtins.list.release_excess_capacity"; pub const LIST_RELEASE_EXCESS_CAPACITY: &str = "roc_builtins.list.release_excess_capacity";
pub const LIST_CONCAT_UTF8: &str = "roc_builtins.list.concat_utf8"; pub const LIST_CONCAT_UTF8: &str = "roc_builtins.list.concat_utf8";
pub const LIST_INCREF: &str = "roc_builtins.list.incref";
pub const LIST_DECREF: &str = "roc_builtins.list.decref";
pub const DEC_ABS: &str = "roc_builtins.dec.abs"; pub const DEC_ABS: &str = "roc_builtins.dec.abs";
pub const DEC_ACOS: &str = "roc_builtins.dec.acos"; pub const DEC_ACOS: &str = "roc_builtins.dec.acos";

View file

@ -1113,6 +1113,57 @@ pub(crate) fn call_str_bitcode_fn<'ctx>(
} }
} }
pub(crate) fn call_void_list_bitcode_fn<'ctx>(
env: &Env<'_, 'ctx, '_>,
lists: &[StructValue<'ctx>],
other_arguments: &[BasicValueEnum<'ctx>],
fn_name: &str,
) {
use bumpalo::collections::Vec;
use roc_target::Architecture::*;
match env.target.architecture() {
Aarch32 | X86_32 => {
let mut arguments: Vec<BasicValueEnum> =
Vec::with_capacity_in(other_arguments.len() + 2 * lists.len(), env.arena);
for list in lists {
let (a, b) = pass_list_or_string_to_zig_32bit(env, *list);
arguments.push(a.into());
arguments.push(b.into());
}
arguments.extend(other_arguments);
call_void_bitcode_fn(env, &arguments, fn_name);
}
X86_64 | Aarch64 => {
let capacity = other_arguments.len() + lists.len();
let mut arguments: Vec<BasicValueEnum> = Vec::with_capacity_in(capacity, env.arena);
for list in lists {
arguments.push(pass_list_to_zig_64bit(env, (*list).into()).into());
}
arguments.extend(other_arguments);
call_void_bitcode_fn(env, &arguments, fn_name);
}
Wasm32 => {
let capacity = other_arguments.len() + lists.len();
let mut arguments: Vec<BasicValueEnum> = Vec::with_capacity_in(capacity, env.arena);
for list in lists {
arguments.push(pass_list_to_zig_wasm(env, (*list).into()).into());
}
arguments.extend(other_arguments);
call_void_bitcode_fn(env, &arguments, fn_name);
}
}
}
pub(crate) fn call_list_bitcode_fn<'ctx>( pub(crate) fn call_list_bitcode_fn<'ctx>(
env: &Env<'_, 'ctx, '_>, env: &Env<'_, 'ctx, '_>,
lists: &[StructValue<'ctx>], lists: &[StructValue<'ctx>],

View file

@ -1,5 +1,7 @@
use crate::llvm::bitcode::call_bitcode_fn; use crate::llvm::bitcode::{build_dec_wrapper, call_bitcode_fn, call_void_list_bitcode_fn};
use crate::llvm::build_list::{self, allocate_list, empty_polymorphic_list}; use crate::llvm::build_list::{
allocate_list, empty_polymorphic_list, layout_refcounted, layout_width,
};
use crate::llvm::convert::{ use crate::llvm::convert::{
argument_type_from_layout, basic_type_from_builtin, basic_type_from_layout, zig_str_type, argument_type_from_layout, basic_type_from_builtin, basic_type_from_layout, zig_str_type,
}; };
@ -2860,19 +2862,6 @@ fn union_field_ptr_at_index<'a, 'ctx>(
.into_pointer_value() .into_pointer_value()
} }
pub fn reserve_with_refcount<'a, 'ctx>(
env: &Env<'a, 'ctx, '_>,
layout_interner: &STLayoutInterner<'a>,
layout: InLayout<'a>,
) -> PointerValue<'ctx> {
let stack_size = layout_interner.stack_size(layout);
let alignment_bytes = layout_interner.alignment_bytes(layout);
let basic_type = basic_type_from_layout(env, layout_interner, layout_interner.get_repr(layout));
reserve_with_refcount_help(env, basic_type, stack_size, alignment_bytes)
}
fn reserve_with_refcount_union_as_block_of_memory<'a, 'ctx>( fn reserve_with_refcount_union_as_block_of_memory<'a, 'ctx>(
env: &Env<'a, 'ctx, '_>, env: &Env<'a, 'ctx, '_>,
layout_interner: &STLayoutInterner<'a>, layout_interner: &STLayoutInterner<'a>,
@ -2887,7 +2876,7 @@ fn reserve_with_refcount_union_as_block_of_memory<'a, 'ctx>(
RocUnion::untagged_from_slices(layout_interner, env.context, fields) RocUnion::untagged_from_slices(layout_interner, env.context, fields)
}; };
reserve_with_refcount_help( reserve_union_with_refcount_help(
env, env,
roc_union.struct_type(), roc_union.struct_type(),
roc_union.tag_width(), roc_union.tag_width(),
@ -2895,7 +2884,7 @@ fn reserve_with_refcount_union_as_block_of_memory<'a, 'ctx>(
) )
} }
fn reserve_with_refcount_help<'a, 'ctx, 'env>( fn reserve_union_with_refcount_help<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>, env: &Env<'a, 'ctx, 'env>,
basic_type: impl BasicType<'ctx>, basic_type: impl BasicType<'ctx>,
stack_size: u32, stack_size: u32,
@ -2905,21 +2894,15 @@ fn reserve_with_refcount_help<'a, 'ctx, 'env>(
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);
allocate_with_refcount_help(env, basic_type, alignment_bytes, value_bytes_intvalue) // elem_refcounted does not apply to unions, only lists.
} let elem_refcounted = env.context.bool_type().const_zero().into();
allocate_with_refcount_help(
pub fn allocate_with_refcount<'a, 'ctx>( env,
env: &Env<'a, 'ctx, '_>, basic_type,
layout_interner: &STLayoutInterner<'a>, alignment_bytes,
layout: InLayout<'a>, value_bytes_intvalue,
value: BasicValueEnum<'ctx>, elem_refcounted,
) -> PointerValue<'ctx> { )
let data_ptr = reserve_with_refcount(env, layout_interner, layout);
// store the value in the pointer
env.builder.new_build_store(data_ptr, value);
data_ptr
} }
pub fn allocate_with_refcount_help<'a, 'ctx, 'env>( pub fn allocate_with_refcount_help<'a, 'ctx, 'env>(
@ -2927,12 +2910,14 @@ 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>,
elem_refcounted: BasicValueEnum<'ctx>,
) -> PointerValue<'ctx> { ) -> PointerValue<'ctx> {
let ptr = call_bitcode_fn( let ptr = call_bitcode_fn(
env, env,
&[ &[
number_of_data_bytes.into(), number_of_data_bytes.into(),
env.alignment_const(alignment_bytes).into(), env.alignment_const(alignment_bytes).into(),
elem_refcounted,
], ],
roc_builtins::bitcode::UTILS_ALLOCATE_WITH_REFCOUNT, roc_builtins::bitcode::UTILS_ALLOCATE_WITH_REFCOUNT,
) )
@ -3473,10 +3458,19 @@ pub(crate) fn build_exp_stmt<'a, 'ctx>(
LayoutRepr::Builtin(Builtin::Str) => todo!(), LayoutRepr::Builtin(Builtin::Str) => todo!(),
LayoutRepr::Builtin(Builtin::List(element_layout)) => { LayoutRepr::Builtin(Builtin::List(element_layout)) => {
debug_assert!(value.is_struct_value()); debug_assert!(value.is_struct_value());
let element_layout = layout_interner.get_repr(element_layout); let dec_element_fn =
let alignment = element_layout.alignment_bytes(layout_interner); build_dec_wrapper(env, layout_interner, layout_ids, element_layout);
call_void_list_bitcode_fn(
build_list::decref(env, value.into_struct_value(), alignment); env,
&[value.into_struct_value()],
&[
env.alignment_intvalue(layout_interner, element_layout),
layout_width(env, layout_interner, element_layout),
layout_refcounted(env, layout_interner, element_layout),
dec_element_fn.as_global_value().as_pointer_value().into(),
],
bitcode::LIST_DECREF,
)
} }
other_layout if other_layout.is_refcounted(layout_interner) => { other_layout if other_layout.is_refcounted(layout_interner) => {
@ -3546,7 +3540,8 @@ pub(crate) fn build_exp_stmt<'a, 'ctx>(
debug_assert!(value.is_pointer_value()); debug_assert!(value.is_pointer_value());
let value = value.into_pointer_value(); let value = value.into_pointer_value();
let clear_tag_id = match layout_interner.runtime_representation(layout) { let runtime_layout = layout_interner.runtime_representation(layout);
let clear_tag_id = match runtime_layout {
LayoutRepr::Union(union) => union.stores_tag_id_in_pointer(env.target), LayoutRepr::Union(union) => union.stores_tag_id_in_pointer(env.target),
_ => false, _ => false,
}; };
@ -3558,7 +3553,7 @@ pub(crate) fn build_exp_stmt<'a, 'ctx>(
}; };
let rc_ptr = PointerToRefcount::from_ptr_to_data(env, ptr); let rc_ptr = PointerToRefcount::from_ptr_to_data(env, ptr);
rc_ptr.deallocate(env, alignment); rc_ptr.deallocate(env, alignment, runtime_layout);
build_exp_stmt( build_exp_stmt(
env, env,

View file

@ -12,7 +12,7 @@ use roc_mono::layout::{
Builtin, InLayout, Layout, LayoutIds, LayoutInterner, LayoutRepr, STLayoutInterner, Builtin, InLayout, Layout, LayoutIds, LayoutInterner, LayoutRepr, STLayoutInterner,
}; };
use super::bitcode::{call_list_bitcode_fn, BitcodeReturns}; use super::bitcode::{build_inc_wrapper, call_list_bitcode_fn, BitcodeReturns};
use super::build::{ use super::build::{
create_entry_block_alloca, load_roc_value, store_roc_value, use_roc_value, BuilderExt, create_entry_block_alloca, load_roc_value, store_roc_value, use_roc_value, BuilderExt,
}; };
@ -97,6 +97,20 @@ pub(crate) fn layout_width<'a, 'ctx>(
.into() .into()
} }
pub(crate) fn layout_refcounted<'a, 'ctx>(
env: &Env<'a, 'ctx, '_>,
layout_interner: &STLayoutInterner<'a>,
layout: InLayout<'a>,
) -> BasicValueEnum<'ctx> {
let is_refcounted = layout_interner
.get_repr(layout)
.is_refcounted(layout_interner);
env.context
.bool_type()
.const_int(is_refcounted as u64, false)
.into()
}
pub(crate) fn pass_as_opaque<'ctx>( pub(crate) fn pass_as_opaque<'ctx>(
env: &Env<'_, 'ctx, '_>, env: &Env<'_, 'ctx, '_>,
ptr: PointerValue<'ctx>, ptr: PointerValue<'ctx>,
@ -113,9 +127,11 @@ pub(crate) fn pass_as_opaque<'ctx>(
pub(crate) fn list_with_capacity<'a, 'ctx>( pub(crate) fn list_with_capacity<'a, 'ctx>(
env: &Env<'a, 'ctx, '_>, env: &Env<'a, 'ctx, '_>,
layout_interner: &STLayoutInterner<'a>, layout_interner: &STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
capacity: IntValue<'ctx>, capacity: IntValue<'ctx>,
element_layout: InLayout<'a>, element_layout: InLayout<'a>,
) -> BasicValueEnum<'ctx> { ) -> BasicValueEnum<'ctx> {
let inc_element_fn = build_inc_wrapper(env, layout_interner, layout_ids, element_layout);
call_list_bitcode_fn( call_list_bitcode_fn(
env, env,
&[], &[],
@ -123,6 +139,8 @@ pub(crate) fn list_with_capacity<'a, 'ctx>(
capacity.into(), capacity.into(),
env.alignment_intvalue(layout_interner, element_layout), env.alignment_intvalue(layout_interner, element_layout),
layout_width(env, layout_interner, element_layout), layout_width(env, layout_interner, element_layout),
layout_refcounted(env, layout_interner, element_layout),
inc_element_fn.as_global_value().as_pointer_value().into(),
], ],
BitcodeReturns::List, BitcodeReturns::List,
bitcode::LIST_WITH_CAPACITY, bitcode::LIST_WITH_CAPACITY,
@ -173,11 +191,13 @@ pub(crate) fn list_get_unsafe<'a, 'ctx>(
pub(crate) fn list_reserve<'a, 'ctx>( pub(crate) fn list_reserve<'a, 'ctx>(
env: &Env<'a, 'ctx, '_>, env: &Env<'a, 'ctx, '_>,
layout_interner: &STLayoutInterner<'a>, layout_interner: &STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
list: BasicValueEnum<'ctx>, list: BasicValueEnum<'ctx>,
spare: BasicValueEnum<'ctx>, spare: BasicValueEnum<'ctx>,
element_layout: InLayout<'a>, element_layout: InLayout<'a>,
update_mode: UpdateMode, update_mode: UpdateMode,
) -> BasicValueEnum<'ctx> { ) -> BasicValueEnum<'ctx> {
let inc_element_fn = build_inc_wrapper(env, layout_interner, layout_ids, element_layout);
call_list_bitcode_fn_1( call_list_bitcode_fn_1(
env, env,
list.into_struct_value(), list.into_struct_value(),
@ -185,6 +205,8 @@ pub(crate) fn list_reserve<'a, 'ctx>(
env.alignment_intvalue(layout_interner, element_layout), env.alignment_intvalue(layout_interner, element_layout),
spare, spare,
layout_width(env, layout_interner, element_layout), layout_width(env, layout_interner, element_layout),
layout_refcounted(env, layout_interner, element_layout),
inc_element_fn.as_global_value().as_pointer_value().into(),
pass_update_mode(env, update_mode), pass_update_mode(env, update_mode),
], ],
bitcode::LIST_RESERVE, bitcode::LIST_RESERVE,
@ -195,16 +217,20 @@ pub(crate) fn list_reserve<'a, 'ctx>(
pub(crate) fn list_release_excess_capacity<'a, 'ctx>( pub(crate) fn list_release_excess_capacity<'a, 'ctx>(
env: &Env<'a, 'ctx, '_>, env: &Env<'a, 'ctx, '_>,
layout_interner: &STLayoutInterner<'a>, layout_interner: &STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
list: BasicValueEnum<'ctx>, list: BasicValueEnum<'ctx>,
element_layout: InLayout<'a>, element_layout: InLayout<'a>,
update_mode: UpdateMode, update_mode: UpdateMode,
) -> BasicValueEnum<'ctx> { ) -> BasicValueEnum<'ctx> {
let dec_element_fn = build_dec_wrapper(env, layout_interner, layout_ids, element_layout);
call_list_bitcode_fn_1( call_list_bitcode_fn_1(
env, env,
list.into_struct_value(), list.into_struct_value(),
&[ &[
env.alignment_intvalue(layout_interner, element_layout), env.alignment_intvalue(layout_interner, element_layout),
layout_width(env, layout_interner, element_layout), layout_width(env, layout_interner, element_layout),
layout_refcounted(env, layout_interner, element_layout),
dec_element_fn.as_global_value().as_pointer_value().into(),
pass_update_mode(env, update_mode), pass_update_mode(env, update_mode),
], ],
bitcode::LIST_RELEASE_EXCESS_CAPACITY, bitcode::LIST_RELEASE_EXCESS_CAPACITY,
@ -234,10 +260,12 @@ pub(crate) fn list_append_unsafe<'a, 'ctx>(
pub(crate) fn list_prepend<'a, 'ctx>( pub(crate) fn list_prepend<'a, 'ctx>(
env: &Env<'a, 'ctx, '_>, env: &Env<'a, 'ctx, '_>,
layout_interner: &STLayoutInterner<'a>, layout_interner: &STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
original_wrapper: StructValue<'ctx>, original_wrapper: StructValue<'ctx>,
element: BasicValueEnum<'ctx>, element: BasicValueEnum<'ctx>,
element_layout: InLayout<'a>, element_layout: InLayout<'a>,
) -> BasicValueEnum<'ctx> { ) -> BasicValueEnum<'ctx> {
let inc_element_fn = build_inc_wrapper(env, layout_interner, layout_ids, element_layout);
call_list_bitcode_fn_1( call_list_bitcode_fn_1(
env, env,
original_wrapper, original_wrapper,
@ -245,21 +273,50 @@ pub(crate) fn list_prepend<'a, 'ctx>(
env.alignment_intvalue(layout_interner, element_layout), env.alignment_intvalue(layout_interner, element_layout),
pass_element_as_opaque(env, layout_interner, element, element_layout), pass_element_as_opaque(env, layout_interner, element, element_layout),
layout_width(env, layout_interner, element_layout), layout_width(env, layout_interner, element_layout),
layout_refcounted(env, layout_interner, element_layout),
inc_element_fn.as_global_value().as_pointer_value().into(),
], ],
bitcode::LIST_PREPEND, bitcode::LIST_PREPEND,
) )
} }
pub(crate) fn list_clone<'a, 'ctx>(
env: &Env<'a, 'ctx, '_>,
layout_interner: &STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
list: StructValue<'ctx>,
element_layout: InLayout<'a>,
) -> BasicValueEnum<'ctx> {
let inc_element_fn = build_inc_wrapper(env, layout_interner, layout_ids, element_layout);
let dec_element_fn = build_dec_wrapper(env, layout_interner, layout_ids, element_layout);
call_list_bitcode_fn_1(
env,
list,
&[
env.alignment_intvalue(layout_interner, element_layout),
layout_width(env, layout_interner, element_layout),
layout_refcounted(env, layout_interner, element_layout),
inc_element_fn.as_global_value().as_pointer_value().into(),
dec_element_fn.as_global_value().as_pointer_value().into(),
],
bitcode::LIST_CLONE,
)
}
/// List.swap : List elem, U64, U64 -> List elem /// List.swap : List elem, U64, U64 -> List elem
pub(crate) fn list_swap<'a, 'ctx>( pub(crate) fn list_swap<'a, 'ctx>(
env: &Env<'a, 'ctx, '_>, env: &Env<'a, 'ctx, '_>,
layout_interner: &STLayoutInterner<'a>, layout_interner: &STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
original_wrapper: StructValue<'ctx>, original_wrapper: StructValue<'ctx>,
index_1: IntValue<'ctx>, index_1: IntValue<'ctx>,
index_2: IntValue<'ctx>, index_2: IntValue<'ctx>,
element_layout: InLayout<'a>, element_layout: InLayout<'a>,
update_mode: UpdateMode, update_mode: UpdateMode,
) -> BasicValueEnum<'ctx> { ) -> BasicValueEnum<'ctx> {
let inc_element_fn = build_inc_wrapper(env, layout_interner, layout_ids, element_layout);
let dec_element_fn = build_dec_wrapper(env, layout_interner, layout_ids, element_layout);
call_list_bitcode_fn_1( call_list_bitcode_fn_1(
env, env,
original_wrapper, original_wrapper,
@ -268,6 +325,9 @@ pub(crate) fn list_swap<'a, 'ctx>(
layout_width(env, layout_interner, element_layout), layout_width(env, layout_interner, element_layout),
index_1.into(), index_1.into(),
index_2.into(), index_2.into(),
layout_refcounted(env, layout_interner, element_layout),
inc_element_fn.as_global_value().as_pointer_value().into(),
dec_element_fn.as_global_value().as_pointer_value().into(),
pass_update_mode(env, update_mode), pass_update_mode(env, update_mode),
], ],
bitcode::LIST_SWAP, bitcode::LIST_SWAP,
@ -291,6 +351,7 @@ pub(crate) fn list_sublist<'a, 'ctx>(
&[ &[
env.alignment_intvalue(layout_interner, element_layout), env.alignment_intvalue(layout_interner, element_layout),
layout_width(env, layout_interner, element_layout), layout_width(env, layout_interner, element_layout),
layout_refcounted(env, layout_interner, element_layout),
start.into(), start.into(),
len.into(), len.into(),
dec_element_fn.as_global_value().as_pointer_value().into(), dec_element_fn.as_global_value().as_pointer_value().into(),
@ -315,6 +376,7 @@ pub(crate) fn list_drop_at<'a, 'ctx>(
&[ &[
env.alignment_intvalue(layout_interner, element_layout), env.alignment_intvalue(layout_interner, element_layout),
layout_width(env, layout_interner, element_layout), layout_width(env, layout_interner, element_layout),
layout_refcounted(env, layout_interner, element_layout),
count.into(), count.into(),
dec_element_fn.as_global_value().as_pointer_value().into(), dec_element_fn.as_global_value().as_pointer_value().into(),
], ],
@ -326,7 +388,7 @@ pub(crate) fn list_drop_at<'a, 'ctx>(
pub(crate) fn list_replace_unsafe<'a, 'ctx>( pub(crate) fn list_replace_unsafe<'a, 'ctx>(
env: &Env<'a, 'ctx, '_>, env: &Env<'a, 'ctx, '_>,
layout_interner: &STLayoutInterner<'a>, layout_interner: &STLayoutInterner<'a>,
_layout_ids: &mut LayoutIds<'a>, layout_ids: &mut LayoutIds<'a>,
list: BasicValueEnum<'ctx>, list: BasicValueEnum<'ctx>,
index: IntValue<'ctx>, index: IntValue<'ctx>,
element: BasicValueEnum<'ctx>, element: BasicValueEnum<'ctx>,
@ -356,18 +418,27 @@ pub(crate) fn list_replace_unsafe<'a, 'ctx>(
], ],
bitcode::LIST_REPLACE_IN_PLACE, bitcode::LIST_REPLACE_IN_PLACE,
), ),
UpdateMode::Immutable => call_list_bitcode_fn_1( UpdateMode::Immutable => {
env, let inc_element_fn =
list.into_struct_value(), build_inc_wrapper(env, layout_interner, layout_ids, element_layout);
&[ let dec_element_fn =
env.alignment_intvalue(layout_interner, element_layout), build_dec_wrapper(env, layout_interner, layout_ids, element_layout);
index.into(), call_list_bitcode_fn_1(
pass_element_as_opaque(env, layout_interner, element, element_layout), env,
layout_width(env, layout_interner, element_layout), list.into_struct_value(),
pass_as_opaque(env, element_ptr), &[
], env.alignment_intvalue(layout_interner, element_layout),
bitcode::LIST_REPLACE, index.into(),
), pass_element_as_opaque(env, layout_interner, element, element_layout),
layout_width(env, layout_interner, element_layout),
layout_refcounted(env, layout_interner, element_layout),
pass_as_opaque(env, element_ptr),
inc_element_fn.as_global_value().as_pointer_value().into(),
dec_element_fn.as_global_value().as_pointer_value().into(),
],
bitcode::LIST_REPLACE,
)
}
}; };
// Load the element and returned list into a struct. // Load the element and returned list into a struct.
@ -493,11 +564,14 @@ pub(crate) fn destructure<'ctx>(
pub(crate) fn list_sort_with<'a, 'ctx>( pub(crate) fn list_sort_with<'a, 'ctx>(
env: &Env<'a, 'ctx, '_>, env: &Env<'a, 'ctx, '_>,
layout_interner: &STLayoutInterner<'a>, layout_interner: &STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
roc_function_call: RocFunctionCall<'ctx>, roc_function_call: RocFunctionCall<'ctx>,
compare_wrapper: PointerValue<'ctx>, compare_wrapper: PointerValue<'ctx>,
list: BasicValueEnum<'ctx>, list: BasicValueEnum<'ctx>,
element_layout: InLayout<'a>, element_layout: InLayout<'a>,
) -> BasicValueEnum<'ctx> { ) -> BasicValueEnum<'ctx> {
let inc_element_fn = build_inc_wrapper(env, layout_interner, layout_ids, element_layout);
let dec_element_fn = build_dec_wrapper(env, layout_interner, layout_ids, element_layout);
call_list_bitcode_fn_1( call_list_bitcode_fn_1(
env, env,
list.into_struct_value(), list.into_struct_value(),
@ -508,6 +582,9 @@ pub(crate) fn list_sort_with<'a, 'ctx>(
roc_function_call.data_is_owned.into(), roc_function_call.data_is_owned.into(),
env.alignment_intvalue(layout_interner, element_layout), env.alignment_intvalue(layout_interner, element_layout),
layout_width(env, layout_interner, element_layout), layout_width(env, layout_interner, element_layout),
layout_refcounted(env, layout_interner, element_layout),
inc_element_fn.as_global_value().as_pointer_value().into(),
dec_element_fn.as_global_value().as_pointer_value().into(),
], ],
bitcode::LIST_SORT_WITH, bitcode::LIST_SORT_WITH,
) )
@ -533,6 +610,7 @@ pub(crate) fn list_map<'a, 'ctx>(
env.alignment_intvalue(layout_interner, return_layout), env.alignment_intvalue(layout_interner, return_layout),
layout_width(env, layout_interner, element_layout), layout_width(env, layout_interner, element_layout),
layout_width(env, layout_interner, return_layout), layout_width(env, layout_interner, return_layout),
layout_refcounted(env, layout_interner, return_layout),
], ],
bitcode::LIST_MAP, bitcode::LIST_MAP,
) )
@ -566,6 +644,7 @@ pub(crate) fn list_map2<'a, 'ctx>(
layout_width(env, layout_interner, return_layout), layout_width(env, layout_interner, return_layout),
dec_a.as_global_value().as_pointer_value().into(), dec_a.as_global_value().as_pointer_value().into(),
dec_b.as_global_value().as_pointer_value().into(), dec_b.as_global_value().as_pointer_value().into(),
layout_refcounted(env, layout_interner, return_layout),
], ],
BitcodeReturns::List, BitcodeReturns::List,
bitcode::LIST_MAP2, bitcode::LIST_MAP2,
@ -609,6 +688,7 @@ pub(crate) fn list_map3<'a, 'ctx>(
dec_a.as_global_value().as_pointer_value().into(), dec_a.as_global_value().as_pointer_value().into(),
dec_b.as_global_value().as_pointer_value().into(), dec_b.as_global_value().as_pointer_value().into(),
dec_c.as_global_value().as_pointer_value().into(), dec_c.as_global_value().as_pointer_value().into(),
layout_refcounted(env, layout_interner, result_layout),
], ],
BitcodeReturns::List, BitcodeReturns::List,
bitcode::LIST_MAP3, bitcode::LIST_MAP3,
@ -658,6 +738,7 @@ pub(crate) fn list_map4<'a, 'ctx>(
dec_b.as_global_value().as_pointer_value().into(), dec_b.as_global_value().as_pointer_value().into(),
dec_c.as_global_value().as_pointer_value().into(), dec_c.as_global_value().as_pointer_value().into(),
dec_d.as_global_value().as_pointer_value().into(), dec_d.as_global_value().as_pointer_value().into(),
layout_refcounted(env, layout_interner, result_layout),
], ],
BitcodeReturns::List, BitcodeReturns::List,
bitcode::LIST_MAP4, bitcode::LIST_MAP4,
@ -668,16 +749,22 @@ pub(crate) fn list_map4<'a, 'ctx>(
pub(crate) fn list_concat<'a, 'ctx>( pub(crate) fn list_concat<'a, 'ctx>(
env: &Env<'a, 'ctx, '_>, env: &Env<'a, 'ctx, '_>,
layout_interner: &STLayoutInterner<'a>, layout_interner: &STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
list1: BasicValueEnum<'ctx>, list1: BasicValueEnum<'ctx>,
list2: BasicValueEnum<'ctx>, list2: BasicValueEnum<'ctx>,
element_layout: InLayout<'a>, element_layout: InLayout<'a>,
) -> BasicValueEnum<'ctx> { ) -> BasicValueEnum<'ctx> {
let inc_element_fn = build_inc_wrapper(env, layout_interner, layout_ids, element_layout);
let dec_element_fn = build_dec_wrapper(env, layout_interner, layout_ids, element_layout);
call_list_bitcode_fn( call_list_bitcode_fn(
env, env,
&[list1.into_struct_value(), list2.into_struct_value()], &[list1.into_struct_value(), list2.into_struct_value()],
&[ &[
env.alignment_intvalue(layout_interner, element_layout), env.alignment_intvalue(layout_interner, element_layout),
layout_width(env, layout_interner, element_layout), layout_width(env, layout_interner, element_layout),
layout_refcounted(env, layout_interner, element_layout),
inc_element_fn.as_global_value().as_pointer_value().into(),
dec_element_fn.as_global_value().as_pointer_value().into(),
], ],
BitcodeReturns::List, BitcodeReturns::List,
bitcode::LIST_CONCAT, bitcode::LIST_CONCAT,
@ -838,7 +925,14 @@ pub(crate) fn allocate_list<'a, 'ctx>(
let basic_type = let basic_type =
basic_type_from_layout(env, layout_interner, layout_interner.get_repr(elem_layout)); basic_type_from_layout(env, layout_interner, layout_interner.get_repr(elem_layout));
let alignment_bytes = layout_interner.alignment_bytes(elem_layout); let alignment_bytes = layout_interner.alignment_bytes(elem_layout);
allocate_with_refcount_help(env, basic_type, alignment_bytes, number_of_data_bytes) let elem_refcounted = layout_refcounted(env, layout_interner, elem_layout);
allocate_with_refcount_help(
env,
basic_type,
alignment_bytes,
number_of_data_bytes,
elem_refcounted,
)
} }
pub(crate) fn store_list<'ctx>( pub(crate) fn store_list<'ctx>(
@ -860,13 +954,3 @@ pub(crate) fn store_list<'ctx>(
.into_iter(), .into_iter(),
) )
} }
pub(crate) fn decref<'ctx>(
env: &Env<'_, 'ctx, '_>,
wrapper_struct: StructValue<'ctx>,
alignment: u32,
) {
let refcount_ptr = list_allocation_ptr(env, wrapper_struct);
crate::llvm::refcounting::decref_pointer_check_null(env, refcount_ptr, alignment);
}

View file

@ -35,7 +35,7 @@ use crate::llvm::{
BuilderExt, FuncBorrowSpec, RocReturn, BuilderExt, FuncBorrowSpec, RocReturn,
}, },
build_list::{ build_list::{
layout_width, list_append_unsafe, list_concat, list_drop_at, list_get_unsafe, list_append_unsafe, list_clone, list_concat, list_drop_at, list_get_unsafe,
list_len_usize, list_map, list_map2, list_map3, list_map4, list_prepend, list_len_usize, list_map, list_map2, list_map3, list_map4, list_prepend,
list_release_excess_capacity, list_replace_unsafe, list_reserve, list_sort_with, list_release_excess_capacity, list_replace_unsafe, list_reserve, list_sort_with,
list_sublist, list_swap, list_symbol_to_c_abi, list_with_capacity, pass_update_mode, list_sublist, list_swap, list_symbol_to_c_abi, list_with_capacity, pass_update_mode,
@ -645,6 +645,7 @@ pub(crate) fn run_low_level<'a, 'ctx>(
list_with_capacity( list_with_capacity(
env, env,
layout_interner, layout_interner,
layout_ids,
list_len.into_int_value(), list_len.into_int_value(),
list_element_layout!(layout_interner, result_layout), list_element_layout!(layout_interner, result_layout),
) )
@ -661,6 +662,7 @@ pub(crate) fn run_low_level<'a, 'ctx>(
list_concat( list_concat(
env, env,
layout_interner, layout_interner,
layout_ids,
first_list, first_list,
second_list, second_list,
element_layout, element_layout,
@ -682,7 +684,14 @@ pub(crate) fn run_low_level<'a, 'ctx>(
let original_wrapper = scope.load_symbol(&args[0]).into_struct_value(); let original_wrapper = scope.load_symbol(&args[0]).into_struct_value();
let (elem, elem_layout) = scope.load_symbol_and_layout(&args[1]); let (elem, elem_layout) = scope.load_symbol_and_layout(&args[1]);
list_prepend(env, layout_interner, original_wrapper, elem, elem_layout) list_prepend(
env,
layout_interner,
layout_ids,
original_wrapper,
elem,
elem_layout,
)
} }
ListReserve => { ListReserve => {
// List.reserve : List elem, U64 -> List elem // List.reserve : List elem, U64 -> List elem
@ -695,6 +704,7 @@ pub(crate) fn run_low_level<'a, 'ctx>(
list_reserve( list_reserve(
env, env,
layout_interner, layout_interner,
layout_ids,
list, list,
spare, spare,
element_layout, element_layout,
@ -708,7 +718,14 @@ pub(crate) fn run_low_level<'a, 'ctx>(
let (list, list_layout) = scope.load_symbol_and_layout(&args[0]); let (list, list_layout) = scope.load_symbol_and_layout(&args[0]);
let element_layout = list_element_layout!(layout_interner, list_layout); let element_layout = list_element_layout!(layout_interner, list_layout);
list_release_excess_capacity(env, layout_interner, list, element_layout, update_mode) list_release_excess_capacity(
env,
layout_interner,
layout_ids,
list,
element_layout,
update_mode,
)
} }
ListSwap => { ListSwap => {
// List.swap : List elem, U64, U64 -> List elem // List.swap : List elem, U64, U64 -> List elem
@ -724,6 +741,7 @@ pub(crate) fn run_low_level<'a, 'ctx>(
list_swap( list_swap(
env, env,
layout_interner, layout_interner,
layout_ids,
original_wrapper, original_wrapper,
index_1.into_int_value(), index_1.into_int_value(),
index_2.into_int_value(), index_2.into_int_value(),
@ -826,19 +844,13 @@ pub(crate) fn run_low_level<'a, 'ctx>(
let element_layout = list_element_layout!(layout_interner, list_layout); let element_layout = list_element_layout!(layout_interner, list_layout);
match update_mode { match update_mode {
UpdateMode::Immutable => { UpdateMode::Immutable => list_clone(
// env,
call_list_bitcode_fn( layout_interner,
env, layout_ids,
&[list.into_struct_value()], list.into_struct_value(),
&[ element_layout,
env.alignment_intvalue(layout_interner, element_layout), ),
layout_width(env, layout_interner, element_layout),
],
BitcodeReturns::List,
bitcode::LIST_CLONE,
)
}
UpdateMode::InPlace => { UpdateMode::InPlace => {
// we statically know the list is unique // we statically know the list is unique
list list
@ -3030,6 +3042,7 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx>(
list_sort_with( list_sort_with(
env, env,
layout_interner, layout_interner,
layout_ids,
roc_function_call, roc_function_call,
compare_wrapper, compare_wrapper,
list, list,

View file

@ -1,12 +1,10 @@
use crate::debug_info_init; use crate::debug_info_init;
use crate::llvm::bitcode::call_void_bitcode_fn; use crate::llvm::bitcode::{build_dec_wrapper, call_void_bitcode_fn, call_void_list_bitcode_fn};
use crate::llvm::build::BuilderExt; use crate::llvm::build::BuilderExt;
use crate::llvm::build::{ use crate::llvm::build::{
add_func, cast_basic_basic, get_tag_id, tag_pointer_clear_tag_id, Env, FAST_CALL_CONV, add_func, cast_basic_basic, get_tag_id, tag_pointer_clear_tag_id, Env, FAST_CALL_CONV,
}; };
use crate::llvm::build_list::{ use crate::llvm::build_list::{layout_refcounted, layout_width};
incrementing_elem_loop, list_allocation_ptr, list_capacity_or_ref_ptr, load_list,
};
use crate::llvm::build_str::str_allocation_ptr; use crate::llvm::build_str::str_allocation_ptr;
use crate::llvm::convert::{basic_type_from_layout, zig_str_type, RocUnion}; use crate::llvm::convert::{basic_type_from_layout, zig_str_type, RocUnion};
use crate::llvm::struct_::RocStruct; use crate::llvm::struct_::RocStruct;
@ -16,6 +14,7 @@ use inkwell::module::Linkage;
use inkwell::types::{AnyTypeEnum, BasicMetadataTypeEnum, BasicType, BasicTypeEnum}; use inkwell::types::{AnyTypeEnum, BasicMetadataTypeEnum, BasicType, BasicTypeEnum};
use inkwell::values::{BasicValueEnum, FunctionValue, InstructionValue, IntValue, PointerValue}; use inkwell::values::{BasicValueEnum, FunctionValue, InstructionValue, IntValue, PointerValue};
use inkwell::{AddressSpace, IntPredicate}; use inkwell::{AddressSpace, IntPredicate};
use roc_builtins::bitcode;
use roc_module::symbol::Interns; use roc_module::symbol::Interns;
use roc_module::symbol::Symbol; use roc_module::symbol::Symbol;
use roc_mono::ir::ErasedField; use roc_mono::ir::ErasedField;
@ -111,13 +110,18 @@ impl<'ctx> PointerToRefcount<'ctx> {
layout_interner: &STLayoutInterner<'a>, layout_interner: &STLayoutInterner<'a>,
) { ) {
match mode { match mode {
CallMode::Inc(inc_amount) => self.increment(inc_amount, env), CallMode::Inc(inc_amount) => self.increment(inc_amount, env, layout),
CallMode::Dec => self.decrement(env, layout_interner, layout), CallMode::Dec => self.decrement(env, layout_interner, layout),
} }
} }
fn increment<'a, 'env>(&self, amount: IntValue<'ctx>, env: &Env<'a, 'ctx, 'env>) { fn increment<'a, 'env>(
incref_pointer(env, self.value, amount); &self,
amount: IntValue<'ctx>,
env: &Env<'a, 'ctx, 'env>,
layout: LayoutRepr<'a>,
) {
incref_pointer(env, self.value, amount, layout);
} }
pub fn decrement<'a, 'env>( pub fn decrement<'a, 'env>(
@ -158,7 +162,7 @@ impl<'ctx> PointerToRefcount<'ctx> {
debug_info_init!(env, function_value); debug_info_init!(env, function_value);
Self::build_decrement_function_body(env, function_value, alignment); Self::build_decrement_function_body(env, function_value, alignment, layout);
function_value function_value
} }
@ -180,6 +184,7 @@ impl<'ctx> PointerToRefcount<'ctx> {
env: &Env<'a, 'ctx, 'env>, env: &Env<'a, 'ctx, 'env>,
parent: FunctionValue<'ctx>, parent: FunctionValue<'ctx>,
alignment: u32, alignment: u32,
layout: LayoutRepr<'a>,
) { ) {
let builder = env.builder; let builder = env.builder;
let ctx = env.context; let ctx = env.context;
@ -193,6 +198,7 @@ impl<'ctx> PointerToRefcount<'ctx> {
env, env,
parent.get_nth_param(0).unwrap().into_pointer_value(), parent.get_nth_param(0).unwrap().into_pointer_value(),
alignment, alignment,
layout,
); );
builder.new_build_return(None); builder.new_build_return(None);
@ -202,16 +208,23 @@ impl<'ctx> PointerToRefcount<'ctx> {
&self, &self,
env: &Env<'a, 'ctx, 'env>, env: &Env<'a, 'ctx, 'env>,
alignment: u32, alignment: u32,
layout: LayoutRepr<'a>,
) -> InstructionValue<'ctx> { ) -> InstructionValue<'ctx> {
free_pointer(env, self.value, alignment) free_pointer(env, self.value, alignment, layout)
} }
} }
fn debug_assert_not_list(layout: LayoutRepr<'_>) {
debug_assert!(!matches!(layout, LayoutRepr::Builtin(Builtin::List(_))), "List are no longer safe to refcount through pointer alone. They must go through the zig bitcode functions");
}
fn incref_pointer<'ctx>( fn incref_pointer<'ctx>(
env: &Env<'_, 'ctx, '_>, env: &Env<'_, 'ctx, '_>,
pointer: PointerValue<'ctx>, pointer: PointerValue<'ctx>,
amount: IntValue<'ctx>, amount: IntValue<'ctx>,
layout: LayoutRepr<'_>,
) { ) {
debug_assert_not_list(layout);
call_void_bitcode_fn( call_void_bitcode_fn(
env, env,
&[ &[
@ -232,7 +245,9 @@ fn free_pointer<'ctx>(
env: &Env<'_, 'ctx, '_>, env: &Env<'_, 'ctx, '_>,
pointer: PointerValue<'ctx>, pointer: PointerValue<'ctx>,
alignment: u32, alignment: u32,
layout: LayoutRepr<'_>,
) -> InstructionValue<'ctx> { ) -> InstructionValue<'ctx> {
debug_assert_not_list(layout);
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(
env, env,
@ -245,12 +260,19 @@ fn free_pointer<'ctx>(
) )
.into(), .into(),
alignment.into(), alignment.into(),
env.context.bool_type().const_int(0, false).into(),
], ],
roc_builtins::bitcode::UTILS_FREE_RC_PTR, 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,
layout: LayoutRepr<'_>,
) {
debug_assert_not_list(layout);
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(
env, env,
@ -263,6 +285,7 @@ fn decref_pointer<'ctx>(env: &Env<'_, 'ctx, '_>, pointer: PointerValue<'ctx>, al
) )
.into(), .into(),
alignment.into(), alignment.into(),
env.context.bool_type().const_int(0, false).into(),
], ],
roc_builtins::bitcode::UTILS_DECREF_RC_PTR, roc_builtins::bitcode::UTILS_DECREF_RC_PTR,
); );
@ -273,7 +296,9 @@ pub fn decref_pointer_check_null<'ctx>(
env: &Env<'_, 'ctx, '_>, env: &Env<'_, 'ctx, '_>,
pointer: PointerValue<'ctx>, pointer: PointerValue<'ctx>,
alignment: u32, alignment: u32,
layout: LayoutRepr<'_>,
) { ) {
debug_assert_not_list(layout);
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(
env, env,
@ -286,6 +311,7 @@ pub fn decref_pointer_check_null<'ctx>(
) )
.into(), .into(),
alignment.into(), alignment.into(),
env.context.bool_type().const_int(0, false).into(),
], ],
roc_builtins::bitcode::UTILS_DECREF_CHECK_NULL, roc_builtins::bitcode::UTILS_DECREF_CHECK_NULL,
); );
@ -764,7 +790,6 @@ fn modify_refcount_list<'a, 'ctx>(
layout_interner, layout_interner,
layout_ids, layout_ids,
mode, mode,
list_layout,
element_layout, element_layout,
function_value, function_value,
); );
@ -791,7 +816,6 @@ fn modify_refcount_list_help<'a, 'ctx>(
layout_interner: &STLayoutInterner<'a>, layout_interner: &STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>, layout_ids: &mut LayoutIds<'a>,
mode: Mode, mode: Mode,
layout: LayoutRepr<'a>,
element_layout: InLayout<'a>, element_layout: InLayout<'a>,
fn_val: FunctionValue<'ctx>, fn_val: FunctionValue<'ctx>,
) { ) {
@ -807,73 +831,49 @@ fn modify_refcount_list_help<'a, 'ctx>(
// Add args to scope // Add args to scope
let arg_symbol = Symbol::ARG_1; let arg_symbol = Symbol::ARG_1;
let arg_val = fn_val.get_param_iter().next().unwrap(); let mut param_iter = fn_val.get_param_iter();
let arg_val = param_iter.next().unwrap();
arg_val.set_name(arg_symbol.as_str(&env.interns)); arg_val.set_name(arg_symbol.as_str(&env.interns));
let parent = fn_val;
let original_wrapper = arg_val.into_struct_value(); let original_wrapper = arg_val.into_struct_value();
// We use the raw capacity to ensure we always decrement the refcount of seamless slices. // List incrementing and decrementing is more complex now.
let capacity = list_capacity_or_ref_ptr(builder, original_wrapper); // Always go through zig.
match mode {
let is_non_empty = builder.new_build_int_compare( Mode::Dec => {
IntPredicate::UGT, let dec_element_fn =
capacity, build_dec_wrapper(env, layout_interner, layout_ids, element_layout);
env.ptr_int().const_zero(), call_void_list_bitcode_fn(
"cap > 0",
);
// build blocks
let modification_list_block = ctx.append_basic_block(parent, "modification_list_block");
let cont_block = ctx.append_basic_block(parent, "modify_rc_list_cont");
builder.new_build_conditional_branch(is_non_empty, modification_list_block, cont_block);
builder.position_at_end(modification_list_block);
if layout_interner.contains_refcounted(element_layout) {
let ptr_type = basic_type_from_layout(
env,
layout_interner,
layout_interner.get_repr(element_layout),
)
.ptr_type(AddressSpace::default());
let (len, ptr) = load_list(env.builder, original_wrapper, ptr_type);
let loop_fn = |layout_interner, _index, element| {
modify_refcount_layout_help(
env, env,
layout_interner, &[original_wrapper],
layout_ids, &[
mode.to_call_mode(fn_val), env.alignment_intvalue(layout_interner, element_layout),
element, layout_width(env, layout_interner, element_layout),
element_layout, layout_refcounted(env, layout_interner, element_layout),
); dec_element_fn.as_global_value().as_pointer_value().into(),
}; ],
bitcode::LIST_DECREF,
)
}
Mode::Inc => {
let inc_amount_symbol = Symbol::ARG_2;
let inc_amount_val = param_iter.next().unwrap();
incrementing_elem_loop( inc_amount_val.set_name(inc_amount_symbol.as_str(&env.interns));
env,
layout_interner, call_void_list_bitcode_fn(
parent, env,
element_layout, &[original_wrapper],
ptr, &[
len, inc_amount_val.into_int_value().into(),
"modify_rc_index", layout_refcounted(env, layout_interner, element_layout),
loop_fn, ],
); bitcode::LIST_INCREF,
)
}
} }
let refcount_ptr =
PointerToRefcount::from_ptr_to_data(env, list_allocation_ptr(env, original_wrapper));
let call_mode = mode_to_call_mode(fn_val, mode);
refcount_ptr.modify(call_mode, layout, env, layout_interner);
builder.new_build_unconditional_branch(cont_block);
builder.position_at_end(cont_block);
// this function returns void // this function returns void
builder.new_build_return(None); builder.new_build_return(None);
} }