mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 06:14:46 +00:00
Update LLVM to properly increment and decrement lists
This commit is contained in:
parent
255cc31ad9
commit
3c842196fa
12 changed files with 337 additions and 176 deletions
|
@ -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>],
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue