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

@ -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>(
env: &Env<'_, 'ctx, '_>,
lists: &[StructValue<'ctx>],

View file

@ -1,5 +1,7 @@
use crate::llvm::bitcode::call_bitcode_fn;
use crate::llvm::build_list::{self, allocate_list, empty_polymorphic_list};
use crate::llvm::bitcode::{build_dec_wrapper, call_bitcode_fn, call_void_list_bitcode_fn};
use crate::llvm::build_list::{
allocate_list, empty_polymorphic_list, layout_refcounted, layout_width,
};
use crate::llvm::convert::{
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()
}
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>(
env: &Env<'a, 'ctx, '_>,
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)
};
reserve_with_refcount_help(
reserve_union_with_refcount_help(
env,
roc_union.struct_type(),
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>,
basic_type: impl BasicType<'ctx>,
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);
allocate_with_refcount_help(env, basic_type, alignment_bytes, value_bytes_intvalue)
}
pub fn allocate_with_refcount<'a, 'ctx>(
env: &Env<'a, 'ctx, '_>,
layout_interner: &STLayoutInterner<'a>,
layout: InLayout<'a>,
value: BasicValueEnum<'ctx>,
) -> 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
// elem_refcounted does not apply to unions, only lists.
let elem_refcounted = env.context.bool_type().const_zero().into();
allocate_with_refcount_help(
env,
basic_type,
alignment_bytes,
value_bytes_intvalue,
elem_refcounted,
)
}
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>,
alignment_bytes: u32,
number_of_data_bytes: IntValue<'ctx>,
elem_refcounted: BasicValueEnum<'ctx>,
) -> PointerValue<'ctx> {
let ptr = call_bitcode_fn(
env,
&[
number_of_data_bytes.into(),
env.alignment_const(alignment_bytes).into(),
elem_refcounted,
],
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::List(element_layout)) => {
debug_assert!(value.is_struct_value());
let element_layout = layout_interner.get_repr(element_layout);
let alignment = element_layout.alignment_bytes(layout_interner);
build_list::decref(env, value.into_struct_value(), alignment);
let dec_element_fn =
build_dec_wrapper(env, layout_interner, layout_ids, element_layout);
call_void_list_bitcode_fn(
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) => {
@ -3546,7 +3540,8 @@ pub(crate) fn build_exp_stmt<'a, 'ctx>(
debug_assert!(value.is_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),
_ => false,
};
@ -3558,7 +3553,7 @@ pub(crate) fn build_exp_stmt<'a, 'ctx>(
};
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(
env,

View file

@ -12,7 +12,7 @@ use roc_mono::layout::{
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::{
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()
}
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>(
env: &Env<'_, 'ctx, '_>,
ptr: PointerValue<'ctx>,
@ -113,9 +127,11 @@ pub(crate) fn pass_as_opaque<'ctx>(
pub(crate) fn list_with_capacity<'a, 'ctx>(
env: &Env<'a, 'ctx, '_>,
layout_interner: &STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
capacity: IntValue<'ctx>,
element_layout: InLayout<'a>,
) -> BasicValueEnum<'ctx> {
let inc_element_fn = build_inc_wrapper(env, layout_interner, layout_ids, element_layout);
call_list_bitcode_fn(
env,
&[],
@ -123,6 +139,8 @@ pub(crate) fn list_with_capacity<'a, 'ctx>(
capacity.into(),
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(),
],
BitcodeReturns::List,
bitcode::LIST_WITH_CAPACITY,
@ -173,11 +191,13 @@ pub(crate) fn list_get_unsafe<'a, 'ctx>(
pub(crate) fn list_reserve<'a, 'ctx>(
env: &Env<'a, 'ctx, '_>,
layout_interner: &STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
list: BasicValueEnum<'ctx>,
spare: BasicValueEnum<'ctx>,
element_layout: InLayout<'a>,
update_mode: UpdateMode,
) -> BasicValueEnum<'ctx> {
let inc_element_fn = build_inc_wrapper(env, layout_interner, layout_ids, element_layout);
call_list_bitcode_fn_1(
env,
list.into_struct_value(),
@ -185,6 +205,8 @@ pub(crate) fn list_reserve<'a, 'ctx>(
env.alignment_intvalue(layout_interner, element_layout),
spare,
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),
],
bitcode::LIST_RESERVE,
@ -195,16 +217,20 @@ pub(crate) fn list_reserve<'a, 'ctx>(
pub(crate) fn list_release_excess_capacity<'a, 'ctx>(
env: &Env<'a, 'ctx, '_>,
layout_interner: &STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
list: BasicValueEnum<'ctx>,
element_layout: InLayout<'a>,
update_mode: UpdateMode,
) -> BasicValueEnum<'ctx> {
let dec_element_fn = build_dec_wrapper(env, layout_interner, layout_ids, element_layout);
call_list_bitcode_fn_1(
env,
list.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(),
pass_update_mode(env, update_mode),
],
bitcode::LIST_RELEASE_EXCESS_CAPACITY,
@ -234,10 +260,12 @@ pub(crate) fn list_append_unsafe<'a, 'ctx>(
pub(crate) fn list_prepend<'a, 'ctx>(
env: &Env<'a, 'ctx, '_>,
layout_interner: &STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
original_wrapper: StructValue<'ctx>,
element: BasicValueEnum<'ctx>,
element_layout: InLayout<'a>,
) -> BasicValueEnum<'ctx> {
let inc_element_fn = build_inc_wrapper(env, layout_interner, layout_ids, element_layout);
call_list_bitcode_fn_1(
env,
original_wrapper,
@ -245,21 +273,50 @@ pub(crate) fn list_prepend<'a, 'ctx>(
env.alignment_intvalue(layout_interner, element_layout),
pass_element_as_opaque(env, layout_interner, element, 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,
)
}
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
pub(crate) fn list_swap<'a, 'ctx>(
env: &Env<'a, 'ctx, '_>,
layout_interner: &STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
original_wrapper: StructValue<'ctx>,
index_1: IntValue<'ctx>,
index_2: IntValue<'ctx>,
element_layout: InLayout<'a>,
update_mode: UpdateMode,
) -> 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,
original_wrapper,
@ -268,6 +325,9 @@ pub(crate) fn list_swap<'a, 'ctx>(
layout_width(env, layout_interner, element_layout),
index_1.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),
],
bitcode::LIST_SWAP,
@ -291,6 +351,7 @@ pub(crate) fn list_sublist<'a, 'ctx>(
&[
env.alignment_intvalue(layout_interner, element_layout),
layout_width(env, layout_interner, element_layout),
layout_refcounted(env, layout_interner, element_layout),
start.into(),
len.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),
layout_width(env, layout_interner, element_layout),
layout_refcounted(env, layout_interner, element_layout),
count.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>(
env: &Env<'a, 'ctx, '_>,
layout_interner: &STLayoutInterner<'a>,
_layout_ids: &mut LayoutIds<'a>,
layout_ids: &mut LayoutIds<'a>,
list: BasicValueEnum<'ctx>,
index: IntValue<'ctx>,
element: BasicValueEnum<'ctx>,
@ -356,18 +418,27 @@ pub(crate) fn list_replace_unsafe<'a, 'ctx>(
],
bitcode::LIST_REPLACE_IN_PLACE,
),
UpdateMode::Immutable => call_list_bitcode_fn_1(
env,
list.into_struct_value(),
&[
env.alignment_intvalue(layout_interner, element_layout),
index.into(),
pass_element_as_opaque(env, layout_interner, element, element_layout),
layout_width(env, layout_interner, element_layout),
pass_as_opaque(env, element_ptr),
],
bitcode::LIST_REPLACE,
),
UpdateMode::Immutable => {
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.into_struct_value(),
&[
env.alignment_intvalue(layout_interner, element_layout),
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.
@ -493,11 +564,14 @@ pub(crate) fn destructure<'ctx>(
pub(crate) fn list_sort_with<'a, 'ctx>(
env: &Env<'a, 'ctx, '_>,
layout_interner: &STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
roc_function_call: RocFunctionCall<'ctx>,
compare_wrapper: PointerValue<'ctx>,
list: BasicValueEnum<'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.into_struct_value(),
@ -508,6 +582,9 @@ pub(crate) fn list_sort_with<'a, 'ctx>(
roc_function_call.data_is_owned.into(),
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_SORT_WITH,
)
@ -533,6 +610,7 @@ pub(crate) fn list_map<'a, 'ctx>(
env.alignment_intvalue(layout_interner, return_layout),
layout_width(env, layout_interner, element_layout),
layout_width(env, layout_interner, return_layout),
layout_refcounted(env, layout_interner, return_layout),
],
bitcode::LIST_MAP,
)
@ -566,6 +644,7 @@ pub(crate) fn list_map2<'a, 'ctx>(
layout_width(env, layout_interner, return_layout),
dec_a.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,
bitcode::LIST_MAP2,
@ -609,6 +688,7 @@ pub(crate) fn list_map3<'a, 'ctx>(
dec_a.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(),
layout_refcounted(env, layout_interner, result_layout),
],
BitcodeReturns::List,
bitcode::LIST_MAP3,
@ -658,6 +738,7 @@ pub(crate) fn list_map4<'a, 'ctx>(
dec_b.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(),
layout_refcounted(env, layout_interner, result_layout),
],
BitcodeReturns::List,
bitcode::LIST_MAP4,
@ -668,16 +749,22 @@ pub(crate) fn list_map4<'a, 'ctx>(
pub(crate) fn list_concat<'a, 'ctx>(
env: &Env<'a, 'ctx, '_>,
layout_interner: &STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
list1: BasicValueEnum<'ctx>,
list2: BasicValueEnum<'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(
env,
&[list1.into_struct_value(), list2.into_struct_value()],
&[
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(),
],
BitcodeReturns::List,
bitcode::LIST_CONCAT,
@ -838,7 +925,14 @@ pub(crate) fn allocate_list<'a, 'ctx>(
let basic_type =
basic_type_from_layout(env, layout_interner, layout_interner.get_repr(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>(
@ -860,13 +954,3 @@ pub(crate) fn store_list<'ctx>(
.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,
},
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_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,
@ -645,6 +645,7 @@ pub(crate) fn run_low_level<'a, 'ctx>(
list_with_capacity(
env,
layout_interner,
layout_ids,
list_len.into_int_value(),
list_element_layout!(layout_interner, result_layout),
)
@ -661,6 +662,7 @@ pub(crate) fn run_low_level<'a, 'ctx>(
list_concat(
env,
layout_interner,
layout_ids,
first_list,
second_list,
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 (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 => {
// List.reserve : List elem, U64 -> List elem
@ -695,6 +704,7 @@ pub(crate) fn run_low_level<'a, 'ctx>(
list_reserve(
env,
layout_interner,
layout_ids,
list,
spare,
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 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 => {
// List.swap : List elem, U64, U64 -> List elem
@ -724,6 +741,7 @@ pub(crate) fn run_low_level<'a, 'ctx>(
list_swap(
env,
layout_interner,
layout_ids,
original_wrapper,
index_1.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);
match update_mode {
UpdateMode::Immutable => {
//
call_list_bitcode_fn(
env,
&[list.into_struct_value()],
&[
env.alignment_intvalue(layout_interner, element_layout),
layout_width(env, layout_interner, element_layout),
],
BitcodeReturns::List,
bitcode::LIST_CLONE,
)
}
UpdateMode::Immutable => list_clone(
env,
layout_interner,
layout_ids,
list.into_struct_value(),
element_layout,
),
UpdateMode::InPlace => {
// we statically know the list is unique
list
@ -3030,6 +3042,7 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx>(
list_sort_with(
env,
layout_interner,
layout_ids,
roc_function_call,
compare_wrapper,
list,

View file

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