mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
Push mutable layout interner through llvm backend
This commit is contained in:
parent
e4b5252e51
commit
512a1721ae
8 changed files with 1289 additions and 555 deletions
|
@ -17,7 +17,7 @@ use inkwell::values::{
|
||||||
use inkwell::AddressSpace;
|
use inkwell::AddressSpace;
|
||||||
use roc_error_macros::internal_error;
|
use roc_error_macros::internal_error;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_mono::layout::{Builtin, LambdaSet, Layout, LayoutIds};
|
use roc_mono::layout::{Builtin, LambdaSet, Layout, LayoutIds, STLayoutInterner};
|
||||||
|
|
||||||
use super::build::{create_entry_block_alloca, BuilderExt};
|
use super::build::{create_entry_block_alloca, BuilderExt};
|
||||||
use super::convert::zig_list_type;
|
use super::convert::zig_list_type;
|
||||||
|
@ -95,13 +95,14 @@ fn call_bitcode_fn_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
pub fn call_bitcode_fn_fixing_for_convention<'a, 'ctx, 'env>(
|
pub fn call_bitcode_fn_fixing_for_convention<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
bitcode_return_type: StructType<'ctx>,
|
bitcode_return_type: StructType<'ctx>,
|
||||||
args: &[BasicValueEnum<'ctx>],
|
args: &[BasicValueEnum<'ctx>],
|
||||||
return_layout: &Layout<'_>,
|
return_layout: &Layout<'a>,
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
// Calling zig bitcode, so we must follow C calling conventions.
|
// Calling zig bitcode, so we must follow C calling conventions.
|
||||||
let cc_return = to_cc_return(env, return_layout);
|
let cc_return = to_cc_return(env, layout_interner, return_layout);
|
||||||
match cc_return {
|
match cc_return {
|
||||||
CCReturn::Return => {
|
CCReturn::Return => {
|
||||||
// We'll get a return value
|
// We'll get a return value
|
||||||
|
@ -109,7 +110,7 @@ pub fn call_bitcode_fn_fixing_for_convention<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
CCReturn::ByPointer => {
|
CCReturn::ByPointer => {
|
||||||
// We need to pass the return value by pointer.
|
// We need to pass the return value by pointer.
|
||||||
let roc_return_type = basic_type_from_layout(env, return_layout);
|
let roc_return_type = basic_type_from_layout(env, layout_interner, return_layout);
|
||||||
|
|
||||||
let cc_return_type: BasicTypeEnum<'ctx> = bitcode_return_type.into();
|
let cc_return_type: BasicTypeEnum<'ctx> = bitcode_return_type.into();
|
||||||
|
|
||||||
|
@ -164,6 +165,7 @@ const ARGUMENT_SYMBOLS: [Symbol; 8] = [
|
||||||
|
|
||||||
pub(crate) fn build_transform_caller<'a, 'ctx, 'env>(
|
pub(crate) fn build_transform_caller<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
function: FunctionValue<'ctx>,
|
function: FunctionValue<'ctx>,
|
||||||
closure_data_layout: LambdaSet<'a>,
|
closure_data_layout: LambdaSet<'a>,
|
||||||
argument_layouts: &[Layout<'a>],
|
argument_layouts: &[Layout<'a>],
|
||||||
|
@ -178,6 +180,7 @@ pub(crate) fn build_transform_caller<'a, 'ctx, 'env>(
|
||||||
Some(function_value) => function_value,
|
Some(function_value) => function_value,
|
||||||
None => build_transform_caller_help(
|
None => build_transform_caller_help(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
function,
|
function,
|
||||||
closure_data_layout,
|
closure_data_layout,
|
||||||
argument_layouts,
|
argument_layouts,
|
||||||
|
@ -189,6 +192,7 @@ pub(crate) fn build_transform_caller<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
fn build_transform_caller_help<'a, 'ctx, 'env>(
|
fn build_transform_caller_help<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
roc_function: FunctionValue<'ctx>,
|
roc_function: FunctionValue<'ctx>,
|
||||||
closure_data_layout: LambdaSet<'a>,
|
closure_data_layout: LambdaSet<'a>,
|
||||||
argument_layouts: &[Layout<'a>],
|
argument_layouts: &[Layout<'a>],
|
||||||
|
@ -237,7 +241,8 @@ fn build_transform_caller_help<'a, 'ctx, 'env>(
|
||||||
bumpalo::collections::Vec::with_capacity_in(arguments.len(), env.arena);
|
bumpalo::collections::Vec::with_capacity_in(arguments.len(), env.arena);
|
||||||
|
|
||||||
for (argument_ptr, layout) in arguments.iter().zip(argument_layouts) {
|
for (argument_ptr, layout) in arguments.iter().zip(argument_layouts) {
|
||||||
let basic_type = basic_type_from_layout(env, layout).ptr_type(AddressSpace::Generic);
|
let basic_type =
|
||||||
|
basic_type_from_layout(env, layout_interner, layout).ptr_type(AddressSpace::Generic);
|
||||||
|
|
||||||
let cast_ptr = env.builder.build_pointer_cast(
|
let cast_ptr = env.builder.build_pointer_cast(
|
||||||
argument_ptr.into_pointer_value(),
|
argument_ptr.into_pointer_value(),
|
||||||
|
@ -245,28 +250,36 @@ fn build_transform_caller_help<'a, 'ctx, 'env>(
|
||||||
"cast_ptr_to_tag_build_transform_caller_help",
|
"cast_ptr_to_tag_build_transform_caller_help",
|
||||||
);
|
);
|
||||||
|
|
||||||
let argument = load_roc_value(env, *layout, cast_ptr, "zig_helper_load_opaque");
|
let argument = load_roc_value(
|
||||||
|
env,
|
||||||
|
layout_interner,
|
||||||
|
*layout,
|
||||||
|
cast_ptr,
|
||||||
|
"zig_helper_load_opaque",
|
||||||
|
);
|
||||||
|
|
||||||
arguments_cast.push(argument);
|
arguments_cast.push(argument);
|
||||||
}
|
}
|
||||||
|
|
||||||
match (
|
match (
|
||||||
closure_data_layout
|
closure_data_layout
|
||||||
.is_represented(env.layout_interner)
|
.is_represented(layout_interner)
|
||||||
.is_some(),
|
.is_some(),
|
||||||
closure_data_layout.runtime_representation(env.layout_interner),
|
closure_data_layout.runtime_representation(layout_interner),
|
||||||
) {
|
) {
|
||||||
(false, _) => {
|
(false, _) => {
|
||||||
// the function doesn't expect a closure argument, nothing to add
|
// the function doesn't expect a closure argument, nothing to add
|
||||||
}
|
}
|
||||||
(true, layout) => {
|
(true, layout) => {
|
||||||
let closure_type = basic_type_from_layout(env, &layout).ptr_type(AddressSpace::Generic);
|
let closure_type = basic_type_from_layout(env, layout_interner, &layout)
|
||||||
|
.ptr_type(AddressSpace::Generic);
|
||||||
|
|
||||||
let closure_cast =
|
let closure_cast =
|
||||||
env.builder
|
env.builder
|
||||||
.build_pointer_cast(closure_ptr, closure_type, "cast_opaque_closure");
|
.build_pointer_cast(closure_ptr, closure_type, "cast_opaque_closure");
|
||||||
|
|
||||||
let closure_data = load_roc_value(env, layout, closure_cast, "load_closure");
|
let closure_data =
|
||||||
|
load_roc_value(env, layout_interner, layout, closure_cast, "load_closure");
|
||||||
|
|
||||||
arguments_cast.push(closure_data);
|
arguments_cast.push(closure_data);
|
||||||
}
|
}
|
||||||
|
@ -274,6 +287,7 @@ fn build_transform_caller_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let result = crate::llvm::build::call_roc_function(
|
let result = crate::llvm::build::call_roc_function(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
roc_function,
|
roc_function,
|
||||||
&result_layout,
|
&result_layout,
|
||||||
arguments_cast.as_slice(),
|
arguments_cast.as_slice(),
|
||||||
|
@ -284,7 +298,13 @@ fn build_transform_caller_help<'a, 'ctx, 'env>(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.into_pointer_value();
|
.into_pointer_value();
|
||||||
|
|
||||||
crate::llvm::build::store_roc_value_opaque(env, result_layout, result_u8_ptr, result);
|
crate::llvm::build::store_roc_value_opaque(
|
||||||
|
env,
|
||||||
|
layout_interner,
|
||||||
|
result_layout,
|
||||||
|
result_u8_ptr,
|
||||||
|
result,
|
||||||
|
);
|
||||||
env.builder.build_return(None);
|
env.builder.build_return(None);
|
||||||
|
|
||||||
env.builder.position_at_end(block);
|
env.builder.position_at_end(block);
|
||||||
|
@ -303,31 +323,35 @@ enum Mode {
|
||||||
/// a function that accepts two arguments: the value to increment, and an amount to increment by
|
/// a function that accepts two arguments: the value to increment, and an amount to increment by
|
||||||
pub fn build_inc_n_wrapper<'a, 'ctx, 'env>(
|
pub fn build_inc_n_wrapper<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
layout: &Layout<'a>,
|
layout: &Layout<'a>,
|
||||||
) -> FunctionValue<'ctx> {
|
) -> FunctionValue<'ctx> {
|
||||||
build_rc_wrapper(env, layout_ids, layout, Mode::IncN)
|
build_rc_wrapper(env, layout_interner, layout_ids, layout, Mode::IncN)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// a function that accepts two arguments: the value to increment; increments by 1
|
/// a function that accepts two arguments: the value to increment; increments by 1
|
||||||
pub fn build_inc_wrapper<'a, 'ctx, 'env>(
|
pub fn build_inc_wrapper<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
layout: &Layout<'a>,
|
layout: &Layout<'a>,
|
||||||
) -> FunctionValue<'ctx> {
|
) -> FunctionValue<'ctx> {
|
||||||
build_rc_wrapper(env, layout_ids, layout, Mode::Inc)
|
build_rc_wrapper(env, layout_interner, layout_ids, layout, Mode::Inc)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_dec_wrapper<'a, 'ctx, 'env>(
|
pub fn build_dec_wrapper<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
layout: &Layout<'a>,
|
layout: &Layout<'a>,
|
||||||
) -> FunctionValue<'ctx> {
|
) -> FunctionValue<'ctx> {
|
||||||
build_rc_wrapper(env, layout_ids, layout, Mode::Dec)
|
build_rc_wrapper(env, layout_interner, layout_ids, layout, Mode::Dec)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_rc_wrapper<'a, 'ctx, 'env>(
|
fn build_rc_wrapper<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
layout: &Layout<'a>,
|
layout: &Layout<'a>,
|
||||||
rc_operation: Mode,
|
rc_operation: Mode,
|
||||||
|
@ -384,7 +408,7 @@ fn build_rc_wrapper<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
generic_value_ptr.set_name(Symbol::ARG_1.as_str(&env.interns));
|
generic_value_ptr.set_name(Symbol::ARG_1.as_str(&env.interns));
|
||||||
|
|
||||||
let value_type = basic_type_from_layout(env, layout);
|
let value_type = basic_type_from_layout(env, layout_interner, layout);
|
||||||
let value_ptr_type = value_type.ptr_type(AddressSpace::Generic);
|
let value_ptr_type = value_type.ptr_type(AddressSpace::Generic);
|
||||||
let value_ptr =
|
let value_ptr =
|
||||||
env.builder
|
env.builder
|
||||||
|
@ -393,7 +417,7 @@ fn build_rc_wrapper<'a, 'ctx, 'env>(
|
||||||
// even though this looks like a `load_roc_value`, that gives segfaults in practice.
|
// even though this looks like a `load_roc_value`, that gives segfaults in practice.
|
||||||
// I suspect it has something to do with the lifetime of the alloca that is created by
|
// I suspect it has something to do with the lifetime of the alloca that is created by
|
||||||
// `load_roc_value`
|
// `load_roc_value`
|
||||||
let value = if layout.is_passed_by_reference(env.layout_interner, env.target_info) {
|
let value = if layout.is_passed_by_reference(layout_interner, env.target_info) {
|
||||||
value_ptr.into()
|
value_ptr.into()
|
||||||
} else {
|
} else {
|
||||||
env.builder
|
env.builder
|
||||||
|
@ -403,16 +427,16 @@ fn build_rc_wrapper<'a, 'ctx, 'env>(
|
||||||
match rc_operation {
|
match rc_operation {
|
||||||
Mode::Inc => {
|
Mode::Inc => {
|
||||||
let n = 1;
|
let n = 1;
|
||||||
increment_refcount_layout(env, layout_ids, n, value, layout);
|
increment_refcount_layout(env, layout_interner, layout_ids, n, value, layout);
|
||||||
}
|
}
|
||||||
Mode::IncN => {
|
Mode::IncN => {
|
||||||
let n = it.next().unwrap().into_int_value();
|
let n = it.next().unwrap().into_int_value();
|
||||||
n.set_name(Symbol::ARG_2.as_str(&env.interns));
|
n.set_name(Symbol::ARG_2.as_str(&env.interns));
|
||||||
|
|
||||||
increment_n_refcount_layout(env, layout_ids, n, value, layout);
|
increment_n_refcount_layout(env, layout_interner, layout_ids, n, value, layout);
|
||||||
}
|
}
|
||||||
Mode::Dec => {
|
Mode::Dec => {
|
||||||
decrement_refcount_layout(env, layout_ids, value, layout);
|
decrement_refcount_layout(env, layout_interner, layout_ids, value, layout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,6 +455,7 @@ fn build_rc_wrapper<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
pub fn build_eq_wrapper<'a, 'ctx, 'env>(
|
pub fn build_eq_wrapper<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
layout: &Layout<'a>,
|
layout: &Layout<'a>,
|
||||||
) -> FunctionValue<'ctx> {
|
) -> FunctionValue<'ctx> {
|
||||||
|
@ -474,7 +499,8 @@ pub fn build_eq_wrapper<'a, 'ctx, 'env>(
|
||||||
value_ptr1.set_name(Symbol::ARG_1.as_str(&env.interns));
|
value_ptr1.set_name(Symbol::ARG_1.as_str(&env.interns));
|
||||||
value_ptr2.set_name(Symbol::ARG_2.as_str(&env.interns));
|
value_ptr2.set_name(Symbol::ARG_2.as_str(&env.interns));
|
||||||
|
|
||||||
let value_type = basic_type_from_layout(env, layout).ptr_type(AddressSpace::Generic);
|
let value_type = basic_type_from_layout(env, layout_interner, layout)
|
||||||
|
.ptr_type(AddressSpace::Generic);
|
||||||
|
|
||||||
let value_cast1 = env
|
let value_cast1 = env
|
||||||
.builder
|
.builder
|
||||||
|
@ -485,11 +511,18 @@ pub fn build_eq_wrapper<'a, 'ctx, 'env>(
|
||||||
.build_pointer_cast(value_ptr2, value_type, "load_opaque");
|
.build_pointer_cast(value_ptr2, value_type, "load_opaque");
|
||||||
|
|
||||||
// load_roc_value(env, *element_layout, elem_ptr, "get_elem")
|
// load_roc_value(env, *element_layout, elem_ptr, "get_elem")
|
||||||
let value1 = load_roc_value(env, *layout, value_cast1, "load_opaque");
|
let value1 = load_roc_value(env, layout_interner, *layout, value_cast1, "load_opaque");
|
||||||
let value2 = load_roc_value(env, *layout, value_cast2, "load_opaque");
|
let value2 = load_roc_value(env, layout_interner, *layout, value_cast2, "load_opaque");
|
||||||
|
|
||||||
let result =
|
let result = crate::llvm::compare::generic_eq(
|
||||||
crate::llvm::compare::generic_eq(env, layout_ids, value1, value2, layout, layout);
|
env,
|
||||||
|
layout_interner,
|
||||||
|
layout_ids,
|
||||||
|
value1,
|
||||||
|
value2,
|
||||||
|
layout,
|
||||||
|
layout,
|
||||||
|
);
|
||||||
|
|
||||||
env.builder.build_return(Some(&result));
|
env.builder.build_return(Some(&result));
|
||||||
|
|
||||||
|
@ -506,6 +539,7 @@ pub fn build_eq_wrapper<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
pub fn build_compare_wrapper<'a, 'ctx, 'env>(
|
pub fn build_compare_wrapper<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
roc_function: FunctionValue<'ctx>,
|
roc_function: FunctionValue<'ctx>,
|
||||||
closure_data_layout: LambdaSet<'a>,
|
closure_data_layout: LambdaSet<'a>,
|
||||||
layout: &Layout<'a>,
|
layout: &Layout<'a>,
|
||||||
|
@ -555,7 +589,7 @@ pub fn build_compare_wrapper<'a, 'ctx, 'env>(
|
||||||
value_ptr1.set_name(Symbol::ARG_2.as_str(&env.interns));
|
value_ptr1.set_name(Symbol::ARG_2.as_str(&env.interns));
|
||||||
value_ptr2.set_name(Symbol::ARG_3.as_str(&env.interns));
|
value_ptr2.set_name(Symbol::ARG_3.as_str(&env.interns));
|
||||||
|
|
||||||
let value_type = basic_type_from_layout(env, layout);
|
let value_type = basic_type_from_layout(env, layout_interner, layout);
|
||||||
let value_ptr_type = value_type.ptr_type(AddressSpace::Generic);
|
let value_ptr_type = value_type.ptr_type(AddressSpace::Generic);
|
||||||
|
|
||||||
let value_cast1 =
|
let value_cast1 =
|
||||||
|
@ -575,33 +609,32 @@ pub fn build_compare_wrapper<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let default = [value1.into(), value2.into()];
|
let default = [value1.into(), value2.into()];
|
||||||
|
|
||||||
let arguments_cast =
|
let arguments_cast = match closure_data_layout.runtime_representation(layout_interner) {
|
||||||
match closure_data_layout.runtime_representation(env.layout_interner) {
|
Layout::Struct {
|
||||||
Layout::Struct {
|
field_layouts: &[], ..
|
||||||
field_layouts: &[], ..
|
} => {
|
||||||
} => {
|
// nothing to add
|
||||||
// nothing to add
|
&default
|
||||||
&default
|
}
|
||||||
}
|
other => {
|
||||||
other => {
|
let closure_type = basic_type_from_layout(env, layout_interner, &other);
|
||||||
let closure_type = basic_type_from_layout(env, &other);
|
let closure_ptr_type = closure_type.ptr_type(AddressSpace::Generic);
|
||||||
let closure_ptr_type = closure_type.ptr_type(AddressSpace::Generic);
|
|
||||||
|
|
||||||
let closure_cast = env.builder.build_pointer_cast(
|
let closure_cast = env.builder.build_pointer_cast(
|
||||||
closure_ptr,
|
closure_ptr,
|
||||||
closure_ptr_type,
|
closure_ptr_type,
|
||||||
"load_opaque",
|
"load_opaque",
|
||||||
);
|
);
|
||||||
|
|
||||||
let closure_data =
|
let closure_data =
|
||||||
env.builder
|
env.builder
|
||||||
.new_build_load(closure_type, closure_cast, "load_opaque");
|
.new_build_load(closure_type, closure_cast, "load_opaque");
|
||||||
|
|
||||||
env.arena
|
env.arena
|
||||||
.alloc([value1.into(), value2.into(), closure_data.into()])
|
.alloc([value1.into(), value2.into(), closure_data.into()])
|
||||||
as &[_]
|
as &[_]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let call = env.builder.build_call(
|
let call = env.builder.build_call(
|
||||||
roc_function,
|
roc_function,
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -13,7 +13,7 @@ use morphic_lib::UpdateMode;
|
||||||
use roc_builtins::bitcode;
|
use roc_builtins::bitcode;
|
||||||
use roc_intern::Interner;
|
use roc_intern::Interner;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_mono::layout::{Builtin, InLayout, Layout, LayoutIds};
|
use roc_mono::layout::{Builtin, InLayout, Layout, LayoutIds, STLayoutInterner};
|
||||||
|
|
||||||
use super::bitcode::{call_list_bitcode_fn, BitcodeReturns};
|
use super::bitcode::{call_list_bitcode_fn, BitcodeReturns};
|
||||||
use super::build::{
|
use super::build::{
|
||||||
|
@ -63,14 +63,15 @@ pub(crate) fn pass_update_mode<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
fn pass_element_as_opaque<'a, 'ctx, 'env>(
|
fn pass_element_as_opaque<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
element: BasicValueEnum<'ctx>,
|
element: BasicValueEnum<'ctx>,
|
||||||
layout: Layout<'a>,
|
layout: Layout<'a>,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
let element_type = basic_type_from_layout(env, &layout);
|
let element_type = basic_type_from_layout(env, layout_interner, &layout);
|
||||||
let element_ptr = env
|
let element_ptr = env
|
||||||
.builder
|
.builder
|
||||||
.build_alloca(element_type, "element_to_pass_as_opaque");
|
.build_alloca(element_type, "element_to_pass_as_opaque");
|
||||||
store_roc_value(env, layout, element_ptr, element);
|
store_roc_value(env, layout_interner, layout, element_ptr, element);
|
||||||
|
|
||||||
env.builder
|
env.builder
|
||||||
.build_pointer_cast(
|
.build_pointer_cast(
|
||||||
|
@ -83,11 +84,12 @@ fn pass_element_as_opaque<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
pub(crate) fn layout_width<'a, 'ctx, 'env>(
|
pub(crate) fn layout_width<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout: &Layout<'a>,
|
layout: &Layout<'a>,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
env.ptr_int()
|
env.ptr_int()
|
||||||
.const_int(
|
.const_int(
|
||||||
layout.stack_size(env.layout_interner, env.target_info) as u64,
|
layout.stack_size(layout_interner, env.target_info) as u64,
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
.into()
|
.into()
|
||||||
|
@ -108,17 +110,18 @@ pub(crate) fn pass_as_opaque<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
pub(crate) fn list_with_capacity<'a, 'ctx, 'env>(
|
pub(crate) fn list_with_capacity<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
capacity: IntValue<'ctx>,
|
capacity: IntValue<'ctx>,
|
||||||
element_layout: InLayout<'a>,
|
element_layout: InLayout<'a>,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
let element_layout = env.layout_interner.get(element_layout);
|
let element_layout = layout_interner.get(element_layout);
|
||||||
call_list_bitcode_fn(
|
call_list_bitcode_fn(
|
||||||
env,
|
env,
|
||||||
&[],
|
&[],
|
||||||
&[
|
&[
|
||||||
capacity.into(),
|
capacity.into(),
|
||||||
env.alignment_intvalue(element_layout),
|
env.alignment_intvalue(layout_interner, element_layout),
|
||||||
layout_width(env, element_layout),
|
layout_width(env, layout_interner, element_layout),
|
||||||
],
|
],
|
||||||
BitcodeReturns::List,
|
BitcodeReturns::List,
|
||||||
bitcode::LIST_WITH_CAPACITY,
|
bitcode::LIST_WITH_CAPACITY,
|
||||||
|
@ -127,6 +130,7 @@ pub(crate) fn list_with_capacity<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
pub(crate) fn list_get_unsafe<'a, 'ctx, 'env>(
|
pub(crate) fn list_get_unsafe<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
element_layout: InLayout<'a>,
|
element_layout: InLayout<'a>,
|
||||||
elem_index: IntValue<'ctx>,
|
elem_index: IntValue<'ctx>,
|
||||||
|
@ -134,8 +138,8 @@ pub(crate) fn list_get_unsafe<'a, 'ctx, 'env>(
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
let builder = env.builder;
|
let builder = env.builder;
|
||||||
|
|
||||||
let element_layout = env.layout_interner.get(element_layout);
|
let element_layout = layout_interner.get(element_layout);
|
||||||
let elem_type = basic_type_from_layout(env, element_layout);
|
let elem_type = basic_type_from_layout(env, layout_interner, element_layout);
|
||||||
let ptr_type = elem_type.ptr_type(AddressSpace::Generic);
|
let ptr_type = elem_type.ptr_type(AddressSpace::Generic);
|
||||||
// Load the pointer to the array data
|
// Load the pointer to the array data
|
||||||
let array_data_ptr = load_list_ptr(builder, wrapper_struct, ptr_type);
|
let array_data_ptr = load_list_ptr(builder, wrapper_struct, ptr_type);
|
||||||
|
@ -151,9 +155,15 @@ pub(crate) fn list_get_unsafe<'a, 'ctx, 'env>(
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = load_roc_value(env, *element_layout, elem_ptr, "list_get_load_element");
|
let result = load_roc_value(
|
||||||
|
env,
|
||||||
|
layout_interner,
|
||||||
|
*element_layout,
|
||||||
|
elem_ptr,
|
||||||
|
"list_get_load_element",
|
||||||
|
);
|
||||||
|
|
||||||
increment_refcount_layout(env, layout_ids, 1, result, element_layout);
|
increment_refcount_layout(env, layout_interner, layout_ids, 1, result, element_layout);
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
@ -161,19 +171,20 @@ pub(crate) fn list_get_unsafe<'a, 'ctx, 'env>(
|
||||||
/// List.reserve : List elem, Nat -> List elem
|
/// List.reserve : List elem, Nat -> List elem
|
||||||
pub(crate) fn list_reserve<'a, 'ctx, 'env>(
|
pub(crate) fn list_reserve<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'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 element_layout = env.layout_interner.get(element_layout);
|
let element_layout = layout_interner.get(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(element_layout),
|
env.alignment_intvalue(layout_interner, element_layout),
|
||||||
spare,
|
spare,
|
||||||
layout_width(env, element_layout),
|
layout_width(env, layout_interner, element_layout),
|
||||||
pass_update_mode(env, update_mode),
|
pass_update_mode(env, update_mode),
|
||||||
],
|
],
|
||||||
bitcode::LIST_RESERVE,
|
bitcode::LIST_RESERVE,
|
||||||
|
@ -183,6 +194,7 @@ pub(crate) fn list_reserve<'a, 'ctx, 'env>(
|
||||||
/// List.appendUnsafe : List elem, elem -> List elem
|
/// List.appendUnsafe : List elem, elem -> List elem
|
||||||
pub(crate) fn list_append_unsafe<'a, 'ctx, 'env>(
|
pub(crate) fn list_append_unsafe<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
original_wrapper: StructValue<'ctx>,
|
original_wrapper: StructValue<'ctx>,
|
||||||
element: BasicValueEnum<'ctx>,
|
element: BasicValueEnum<'ctx>,
|
||||||
element_layout: &Layout<'a>,
|
element_layout: &Layout<'a>,
|
||||||
|
@ -191,8 +203,8 @@ pub(crate) fn list_append_unsafe<'a, 'ctx, 'env>(
|
||||||
env,
|
env,
|
||||||
original_wrapper,
|
original_wrapper,
|
||||||
&[
|
&[
|
||||||
pass_element_as_opaque(env, element, *element_layout),
|
pass_element_as_opaque(env, layout_interner, element, *element_layout),
|
||||||
layout_width(env, element_layout),
|
layout_width(env, layout_interner, element_layout),
|
||||||
],
|
],
|
||||||
bitcode::LIST_APPEND_UNSAFE,
|
bitcode::LIST_APPEND_UNSAFE,
|
||||||
)
|
)
|
||||||
|
@ -201,6 +213,7 @@ pub(crate) fn list_append_unsafe<'a, 'ctx, 'env>(
|
||||||
/// List.prepend : List elem, elem -> List elem
|
/// List.prepend : List elem, elem -> List elem
|
||||||
pub(crate) fn list_prepend<'a, 'ctx, 'env>(
|
pub(crate) fn list_prepend<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
original_wrapper: StructValue<'ctx>,
|
original_wrapper: StructValue<'ctx>,
|
||||||
element: BasicValueEnum<'ctx>,
|
element: BasicValueEnum<'ctx>,
|
||||||
element_layout: &Layout<'a>,
|
element_layout: &Layout<'a>,
|
||||||
|
@ -209,9 +222,9 @@ pub(crate) fn list_prepend<'a, 'ctx, 'env>(
|
||||||
env,
|
env,
|
||||||
original_wrapper,
|
original_wrapper,
|
||||||
&[
|
&[
|
||||||
env.alignment_intvalue(element_layout),
|
env.alignment_intvalue(layout_interner, element_layout),
|
||||||
pass_element_as_opaque(env, element, *element_layout),
|
pass_element_as_opaque(env, layout_interner, element, *element_layout),
|
||||||
layout_width(env, element_layout),
|
layout_width(env, layout_interner, element_layout),
|
||||||
],
|
],
|
||||||
bitcode::LIST_PREPEND,
|
bitcode::LIST_PREPEND,
|
||||||
)
|
)
|
||||||
|
@ -220,19 +233,20 @@ pub(crate) fn list_prepend<'a, 'ctx, 'env>(
|
||||||
/// List.swap : List elem, Nat, Nat -> List elem
|
/// List.swap : List elem, Nat, Nat -> List elem
|
||||||
pub(crate) fn list_swap<'a, 'ctx, 'env>(
|
pub(crate) fn list_swap<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'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 element_layout = env.layout_interner.get(element_layout);
|
let element_layout = layout_interner.get(element_layout);
|
||||||
call_list_bitcode_fn_1(
|
call_list_bitcode_fn_1(
|
||||||
env,
|
env,
|
||||||
original_wrapper,
|
original_wrapper,
|
||||||
&[
|
&[
|
||||||
env.alignment_intvalue(element_layout),
|
env.alignment_intvalue(layout_interner, element_layout),
|
||||||
layout_width(env, element_layout),
|
layout_width(env, layout_interner, element_layout),
|
||||||
index_1.into(),
|
index_1.into(),
|
||||||
index_2.into(),
|
index_2.into(),
|
||||||
pass_update_mode(env, update_mode),
|
pass_update_mode(env, update_mode),
|
||||||
|
@ -244,20 +258,21 @@ pub(crate) fn list_swap<'a, 'ctx, 'env>(
|
||||||
/// List.sublist : List elem, { start : Nat, len : Nat } -> List elem
|
/// List.sublist : List elem, { start : Nat, len : Nat } -> List elem
|
||||||
pub(crate) fn list_sublist<'a, 'ctx, 'env>(
|
pub(crate) fn list_sublist<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
original_wrapper: StructValue<'ctx>,
|
original_wrapper: StructValue<'ctx>,
|
||||||
start: IntValue<'ctx>,
|
start: IntValue<'ctx>,
|
||||||
len: IntValue<'ctx>,
|
len: IntValue<'ctx>,
|
||||||
element_layout: InLayout<'a>,
|
element_layout: InLayout<'a>,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
let element_layout = env.layout_interner.get(element_layout);
|
let element_layout = layout_interner.get(element_layout);
|
||||||
let dec_element_fn = build_dec_wrapper(env, 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,
|
||||||
&[
|
&[
|
||||||
env.alignment_intvalue(element_layout),
|
env.alignment_intvalue(layout_interner, element_layout),
|
||||||
layout_width(env, element_layout),
|
layout_width(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(),
|
||||||
|
@ -269,19 +284,20 @@ pub(crate) fn list_sublist<'a, 'ctx, 'env>(
|
||||||
/// List.dropAt : List elem, Nat -> List elem
|
/// List.dropAt : List elem, Nat -> List elem
|
||||||
pub(crate) fn list_drop_at<'a, 'ctx, 'env>(
|
pub(crate) fn list_drop_at<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
original_wrapper: StructValue<'ctx>,
|
original_wrapper: StructValue<'ctx>,
|
||||||
count: IntValue<'ctx>,
|
count: IntValue<'ctx>,
|
||||||
element_layout: InLayout<'a>,
|
element_layout: InLayout<'a>,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
let element_layout = env.layout_interner.get(element_layout);
|
let element_layout = layout_interner.get(element_layout);
|
||||||
let dec_element_fn = build_dec_wrapper(env, 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,
|
||||||
&[
|
&[
|
||||||
env.alignment_intvalue(element_layout),
|
env.alignment_intvalue(layout_interner, element_layout),
|
||||||
layout_width(env, element_layout),
|
layout_width(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(),
|
||||||
],
|
],
|
||||||
|
@ -292,6 +308,7 @@ pub(crate) fn list_drop_at<'a, 'ctx, 'env>(
|
||||||
/// List.replace_unsafe : List elem, Nat, elem -> { list: List elem, value: elem }
|
/// List.replace_unsafe : List elem, Nat, elem -> { list: List elem, value: elem }
|
||||||
pub(crate) fn list_replace_unsafe<'a, 'ctx, 'env>(
|
pub(crate) fn list_replace_unsafe<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
_layout_ids: &mut LayoutIds<'a>,
|
_layout_ids: &mut LayoutIds<'a>,
|
||||||
list: BasicValueEnum<'ctx>,
|
list: BasicValueEnum<'ctx>,
|
||||||
index: IntValue<'ctx>,
|
index: IntValue<'ctx>,
|
||||||
|
@ -299,7 +316,7 @@ pub(crate) fn list_replace_unsafe<'a, 'ctx, 'env>(
|
||||||
element_layout: &Layout<'a>,
|
element_layout: &Layout<'a>,
|
||||||
update_mode: UpdateMode,
|
update_mode: UpdateMode,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
let element_type = basic_type_from_layout(env, element_layout);
|
let element_type = basic_type_from_layout(env, layout_interner, element_layout);
|
||||||
let element_ptr = env
|
let element_ptr = env
|
||||||
.builder
|
.builder
|
||||||
.build_alloca(element_type, "output_element_as_opaque");
|
.build_alloca(element_type, "output_element_as_opaque");
|
||||||
|
@ -312,8 +329,8 @@ pub(crate) fn list_replace_unsafe<'a, 'ctx, 'env>(
|
||||||
list.into_struct_value(),
|
list.into_struct_value(),
|
||||||
&[
|
&[
|
||||||
index.into(),
|
index.into(),
|
||||||
pass_element_as_opaque(env, element, *element_layout),
|
pass_element_as_opaque(env, layout_interner, element, *element_layout),
|
||||||
layout_width(env, element_layout),
|
layout_width(env, layout_interner, element_layout),
|
||||||
pass_as_opaque(env, element_ptr),
|
pass_as_opaque(env, element_ptr),
|
||||||
],
|
],
|
||||||
bitcode::LIST_REPLACE_IN_PLACE,
|
bitcode::LIST_REPLACE_IN_PLACE,
|
||||||
|
@ -322,10 +339,10 @@ pub(crate) fn list_replace_unsafe<'a, 'ctx, 'env>(
|
||||||
env,
|
env,
|
||||||
list.into_struct_value(),
|
list.into_struct_value(),
|
||||||
&[
|
&[
|
||||||
env.alignment_intvalue(element_layout),
|
env.alignment_intvalue(layout_interner, element_layout),
|
||||||
index.into(),
|
index.into(),
|
||||||
pass_element_as_opaque(env, element, *element_layout),
|
pass_element_as_opaque(env, layout_interner, element, *element_layout),
|
||||||
layout_width(env, element_layout),
|
layout_width(env, layout_interner, element_layout),
|
||||||
pass_as_opaque(env, element_ptr),
|
pass_as_opaque(env, element_ptr),
|
||||||
],
|
],
|
||||||
bitcode::LIST_REPLACE,
|
bitcode::LIST_REPLACE,
|
||||||
|
@ -339,7 +356,7 @@ pub(crate) fn list_replace_unsafe<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
// the list has the same alignment as a usize / ptr. The element comes first in the struct if
|
// the list has the same alignment as a usize / ptr. The element comes first in the struct if
|
||||||
// its alignment is bigger than that of a list.
|
// its alignment is bigger than that of a list.
|
||||||
let element_align = element_layout.alignment_bytes(env.layout_interner, env.target_info);
|
let element_align = element_layout.alignment_bytes(layout_interner, env.target_info);
|
||||||
let element_first = element_align > env.target_info.ptr_width() as u32;
|
let element_first = element_align > env.target_info.ptr_width() as u32;
|
||||||
|
|
||||||
let fields = if element_first {
|
let fields = if element_first {
|
||||||
|
@ -424,6 +441,7 @@ pub(crate) fn destructure<'ctx>(
|
||||||
/// List.sortWith : List a, (a, a -> Ordering) -> List a
|
/// List.sortWith : List a, (a, a -> Ordering) -> List a
|
||||||
pub(crate) fn list_sort_with<'a, 'ctx, 'env>(
|
pub(crate) fn list_sort_with<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'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>,
|
||||||
|
@ -437,8 +455,8 @@ pub(crate) fn list_sort_with<'a, 'ctx, 'env>(
|
||||||
pass_as_opaque(env, roc_function_call.data),
|
pass_as_opaque(env, roc_function_call.data),
|
||||||
roc_function_call.inc_n_data.into(),
|
roc_function_call.inc_n_data.into(),
|
||||||
roc_function_call.data_is_owned.into(),
|
roc_function_call.data_is_owned.into(),
|
||||||
env.alignment_intvalue(element_layout),
|
env.alignment_intvalue(layout_interner, element_layout),
|
||||||
layout_width(env, element_layout),
|
layout_width(env, layout_interner, element_layout),
|
||||||
],
|
],
|
||||||
bitcode::LIST_SORT_WITH,
|
bitcode::LIST_SORT_WITH,
|
||||||
)
|
)
|
||||||
|
@ -447,6 +465,7 @@ pub(crate) fn list_sort_with<'a, 'ctx, 'env>(
|
||||||
/// List.map : List before, (before -> after) -> List after
|
/// List.map : List before, (before -> after) -> List after
|
||||||
pub(crate) fn list_map<'a, 'ctx, 'env>(
|
pub(crate) fn list_map<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
roc_function_call: RocFunctionCall<'ctx>,
|
roc_function_call: RocFunctionCall<'ctx>,
|
||||||
list: BasicValueEnum<'ctx>,
|
list: BasicValueEnum<'ctx>,
|
||||||
element_layout: &Layout<'a>,
|
element_layout: &Layout<'a>,
|
||||||
|
@ -460,9 +479,9 @@ pub(crate) fn list_map<'a, 'ctx, 'env>(
|
||||||
pass_as_opaque(env, roc_function_call.data),
|
pass_as_opaque(env, roc_function_call.data),
|
||||||
roc_function_call.inc_n_data.into(),
|
roc_function_call.inc_n_data.into(),
|
||||||
roc_function_call.data_is_owned.into(),
|
roc_function_call.data_is_owned.into(),
|
||||||
env.alignment_intvalue(return_layout),
|
env.alignment_intvalue(layout_interner, return_layout),
|
||||||
layout_width(env, element_layout),
|
layout_width(env, layout_interner, element_layout),
|
||||||
layout_width(env, return_layout),
|
layout_width(env, layout_interner, return_layout),
|
||||||
],
|
],
|
||||||
bitcode::LIST_MAP,
|
bitcode::LIST_MAP,
|
||||||
)
|
)
|
||||||
|
@ -470,6 +489,7 @@ pub(crate) fn list_map<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
pub(crate) fn list_map2<'a, 'ctx, 'env>(
|
pub(crate) fn list_map2<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
roc_function_call: RocFunctionCall<'ctx>,
|
roc_function_call: RocFunctionCall<'ctx>,
|
||||||
list1: BasicValueEnum<'ctx>,
|
list1: BasicValueEnum<'ctx>,
|
||||||
|
@ -478,8 +498,8 @@ pub(crate) fn list_map2<'a, 'ctx, 'env>(
|
||||||
element2_layout: &Layout<'a>,
|
element2_layout: &Layout<'a>,
|
||||||
return_layout: &Layout<'a>,
|
return_layout: &Layout<'a>,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
let dec_a = build_dec_wrapper(env, layout_ids, element1_layout);
|
let dec_a = build_dec_wrapper(env, layout_interner, layout_ids, element1_layout);
|
||||||
let dec_b = build_dec_wrapper(env, layout_ids, element2_layout);
|
let dec_b = build_dec_wrapper(env, layout_interner, layout_ids, element2_layout);
|
||||||
|
|
||||||
call_list_bitcode_fn(
|
call_list_bitcode_fn(
|
||||||
env,
|
env,
|
||||||
|
@ -489,10 +509,10 @@ pub(crate) fn list_map2<'a, 'ctx, 'env>(
|
||||||
pass_as_opaque(env, roc_function_call.data),
|
pass_as_opaque(env, roc_function_call.data),
|
||||||
roc_function_call.inc_n_data.into(),
|
roc_function_call.inc_n_data.into(),
|
||||||
roc_function_call.data_is_owned.into(),
|
roc_function_call.data_is_owned.into(),
|
||||||
env.alignment_intvalue(return_layout),
|
env.alignment_intvalue(layout_interner, return_layout),
|
||||||
layout_width(env, element1_layout),
|
layout_width(env, layout_interner, element1_layout),
|
||||||
layout_width(env, element2_layout),
|
layout_width(env, layout_interner, element2_layout),
|
||||||
layout_width(env, 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(),
|
||||||
],
|
],
|
||||||
|
@ -503,6 +523,7 @@ pub(crate) fn list_map2<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
pub(crate) fn list_map3<'a, 'ctx, 'env>(
|
pub(crate) fn list_map3<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
roc_function_call: RocFunctionCall<'ctx>,
|
roc_function_call: RocFunctionCall<'ctx>,
|
||||||
list1: BasicValueEnum<'ctx>,
|
list1: BasicValueEnum<'ctx>,
|
||||||
|
@ -513,9 +534,9 @@ pub(crate) fn list_map3<'a, 'ctx, 'env>(
|
||||||
element3_layout: &Layout<'a>,
|
element3_layout: &Layout<'a>,
|
||||||
result_layout: &Layout<'a>,
|
result_layout: &Layout<'a>,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
let dec_a = build_dec_wrapper(env, layout_ids, element1_layout);
|
let dec_a = build_dec_wrapper(env, layout_interner, layout_ids, element1_layout);
|
||||||
let dec_b = build_dec_wrapper(env, layout_ids, element2_layout);
|
let dec_b = build_dec_wrapper(env, layout_interner, layout_ids, element2_layout);
|
||||||
let dec_c = build_dec_wrapper(env, layout_ids, element3_layout);
|
let dec_c = build_dec_wrapper(env, layout_interner, layout_ids, element3_layout);
|
||||||
|
|
||||||
call_list_bitcode_fn(
|
call_list_bitcode_fn(
|
||||||
env,
|
env,
|
||||||
|
@ -529,11 +550,11 @@ pub(crate) fn list_map3<'a, 'ctx, 'env>(
|
||||||
pass_as_opaque(env, roc_function_call.data),
|
pass_as_opaque(env, roc_function_call.data),
|
||||||
roc_function_call.inc_n_data.into(),
|
roc_function_call.inc_n_data.into(),
|
||||||
roc_function_call.data_is_owned.into(),
|
roc_function_call.data_is_owned.into(),
|
||||||
env.alignment_intvalue(result_layout),
|
env.alignment_intvalue(layout_interner, result_layout),
|
||||||
layout_width(env, element1_layout),
|
layout_width(env, layout_interner, element1_layout),
|
||||||
layout_width(env, element2_layout),
|
layout_width(env, layout_interner, element2_layout),
|
||||||
layout_width(env, element3_layout),
|
layout_width(env, layout_interner, element3_layout),
|
||||||
layout_width(env, result_layout),
|
layout_width(env, layout_interner, result_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(),
|
||||||
dec_c.as_global_value().as_pointer_value().into(),
|
dec_c.as_global_value().as_pointer_value().into(),
|
||||||
|
@ -545,6 +566,7 @@ pub(crate) fn list_map3<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
pub(crate) fn list_map4<'a, 'ctx, 'env>(
|
pub(crate) fn list_map4<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
roc_function_call: RocFunctionCall<'ctx>,
|
roc_function_call: RocFunctionCall<'ctx>,
|
||||||
list1: BasicValueEnum<'ctx>,
|
list1: BasicValueEnum<'ctx>,
|
||||||
|
@ -557,10 +579,10 @@ pub(crate) fn list_map4<'a, 'ctx, 'env>(
|
||||||
element4_layout: &Layout<'a>,
|
element4_layout: &Layout<'a>,
|
||||||
result_layout: &Layout<'a>,
|
result_layout: &Layout<'a>,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
let dec_a = build_dec_wrapper(env, layout_ids, element1_layout);
|
let dec_a = build_dec_wrapper(env, layout_interner, layout_ids, element1_layout);
|
||||||
let dec_b = build_dec_wrapper(env, layout_ids, element2_layout);
|
let dec_b = build_dec_wrapper(env, layout_interner, layout_ids, element2_layout);
|
||||||
let dec_c = build_dec_wrapper(env, layout_ids, element3_layout);
|
let dec_c = build_dec_wrapper(env, layout_interner, layout_ids, element3_layout);
|
||||||
let dec_d = build_dec_wrapper(env, layout_ids, element4_layout);
|
let dec_d = build_dec_wrapper(env, layout_interner, layout_ids, element4_layout);
|
||||||
|
|
||||||
call_list_bitcode_fn(
|
call_list_bitcode_fn(
|
||||||
env,
|
env,
|
||||||
|
@ -575,12 +597,12 @@ pub(crate) fn list_map4<'a, 'ctx, 'env>(
|
||||||
pass_as_opaque(env, roc_function_call.data),
|
pass_as_opaque(env, roc_function_call.data),
|
||||||
roc_function_call.inc_n_data.into(),
|
roc_function_call.inc_n_data.into(),
|
||||||
roc_function_call.data_is_owned.into(),
|
roc_function_call.data_is_owned.into(),
|
||||||
env.alignment_intvalue(result_layout),
|
env.alignment_intvalue(layout_interner, result_layout),
|
||||||
layout_width(env, element1_layout),
|
layout_width(env, layout_interner, element1_layout),
|
||||||
layout_width(env, element2_layout),
|
layout_width(env, layout_interner, element2_layout),
|
||||||
layout_width(env, element3_layout),
|
layout_width(env, layout_interner, element3_layout),
|
||||||
layout_width(env, element4_layout),
|
layout_width(env, layout_interner, element4_layout),
|
||||||
layout_width(env, result_layout),
|
layout_width(env, layout_interner, result_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(),
|
||||||
dec_c.as_global_value().as_pointer_value().into(),
|
dec_c.as_global_value().as_pointer_value().into(),
|
||||||
|
@ -594,25 +616,27 @@ pub(crate) fn list_map4<'a, 'ctx, 'env>(
|
||||||
/// List.concat : List elem, List elem -> List elem
|
/// List.concat : List elem, List elem -> List elem
|
||||||
pub(crate) fn list_concat<'a, 'ctx, 'env>(
|
pub(crate) fn list_concat<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'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 element_layout = env.layout_interner.get(element_layout);
|
let element_layout = layout_interner.get(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(element_layout),
|
env.alignment_intvalue(layout_interner, element_layout),
|
||||||
layout_width(env, element_layout),
|
layout_width(env, layout_interner, element_layout),
|
||||||
],
|
],
|
||||||
BitcodeReturns::List,
|
BitcodeReturns::List,
|
||||||
bitcode::LIST_CONCAT,
|
bitcode::LIST_CONCAT,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn incrementing_elem_loop<'a, 'ctx, 'env, LoopFn>(
|
pub(crate) fn incrementing_elem_loop<'a, 'r, 'ctx, 'env, LoopFn>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &'r mut STLayoutInterner<'a>,
|
||||||
parent: FunctionValue<'ctx>,
|
parent: FunctionValue<'ctx>,
|
||||||
element_layout: Layout<'a>,
|
element_layout: Layout<'a>,
|
||||||
ptr: PointerValue<'ctx>,
|
ptr: PointerValue<'ctx>,
|
||||||
|
@ -621,39 +645,49 @@ pub(crate) fn incrementing_elem_loop<'a, 'ctx, 'env, LoopFn>(
|
||||||
mut loop_fn: LoopFn,
|
mut loop_fn: LoopFn,
|
||||||
) -> PointerValue<'ctx>
|
) -> PointerValue<'ctx>
|
||||||
where
|
where
|
||||||
LoopFn: FnMut(IntValue<'ctx>, BasicValueEnum<'ctx>),
|
LoopFn: FnMut(&'r mut STLayoutInterner<'a>, IntValue<'ctx>, BasicValueEnum<'ctx>),
|
||||||
{
|
{
|
||||||
let builder = env.builder;
|
let builder = env.builder;
|
||||||
|
|
||||||
let element_type = basic_type_from_layout(env, &element_layout);
|
let element_type = basic_type_from_layout(env, layout_interner, &element_layout);
|
||||||
|
|
||||||
incrementing_index_loop(env, parent, len, index_name, |index| {
|
incrementing_index_loop(
|
||||||
// The pointer to the element in the list
|
env,
|
||||||
let element_ptr =
|
layout_interner,
|
||||||
unsafe { builder.new_build_in_bounds_gep(element_type, ptr, &[index], "load_index") };
|
parent,
|
||||||
|
len,
|
||||||
|
index_name,
|
||||||
|
|layout_interner, index| {
|
||||||
|
// The pointer to the element in the list
|
||||||
|
let element_ptr = unsafe {
|
||||||
|
builder.new_build_in_bounds_gep(element_type, ptr, &[index], "load_index")
|
||||||
|
};
|
||||||
|
|
||||||
let elem = load_roc_value(
|
let elem = load_roc_value(
|
||||||
env,
|
env,
|
||||||
element_layout,
|
layout_interner,
|
||||||
element_ptr,
|
element_layout,
|
||||||
"incrementing_element_loop_load",
|
element_ptr,
|
||||||
);
|
"incrementing_element_loop_load",
|
||||||
|
);
|
||||||
|
|
||||||
loop_fn(index, elem);
|
loop_fn(layout_interner, index, elem);
|
||||||
})
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This helper simulates a basic for loop, where
|
// This helper simulates a basic for loop, where
|
||||||
// and index increments up from 0 to some end value
|
// and index increments up from 0 to some end value
|
||||||
pub(crate) fn incrementing_index_loop<'a, 'ctx, 'env, LoopFn>(
|
pub(crate) fn incrementing_index_loop<'a, 'r, 'ctx, 'env, LoopFn>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &'r mut STLayoutInterner<'a>,
|
||||||
parent: FunctionValue<'ctx>,
|
parent: FunctionValue<'ctx>,
|
||||||
end: IntValue<'ctx>,
|
end: IntValue<'ctx>,
|
||||||
index_name: &str,
|
index_name: &str,
|
||||||
mut loop_fn: LoopFn,
|
mut loop_fn: LoopFn,
|
||||||
) -> PointerValue<'ctx>
|
) -> PointerValue<'ctx>
|
||||||
where
|
where
|
||||||
LoopFn: FnMut(IntValue<'ctx>),
|
LoopFn: FnMut(&'r mut STLayoutInterner<'a>, IntValue<'ctx>),
|
||||||
{
|
{
|
||||||
let ctx = env.context;
|
let ctx = env.context;
|
||||||
let builder = env.builder;
|
let builder = env.builder;
|
||||||
|
@ -682,7 +716,7 @@ where
|
||||||
builder.build_store(index_alloca, next_index);
|
builder.build_store(index_alloca, next_index);
|
||||||
|
|
||||||
// The body of the loop
|
// The body of the loop
|
||||||
loop_fn(current_index);
|
loop_fn(layout_interner, current_index);
|
||||||
|
|
||||||
// #index < end
|
// #index < end
|
||||||
let loop_end_cond = bounds_check_comparison(builder, next_index, end);
|
let loop_end_cond = bounds_check_comparison(builder, next_index, end);
|
||||||
|
@ -737,19 +771,20 @@ pub(crate) fn load_list_ptr<'ctx>(
|
||||||
|
|
||||||
pub(crate) fn allocate_list<'a, 'ctx, 'env>(
|
pub(crate) fn allocate_list<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
elem_layout: &Layout<'a>,
|
elem_layout: &Layout<'a>,
|
||||||
number_of_elements: IntValue<'ctx>,
|
number_of_elements: IntValue<'ctx>,
|
||||||
) -> PointerValue<'ctx> {
|
) -> PointerValue<'ctx> {
|
||||||
let builder = env.builder;
|
let builder = env.builder;
|
||||||
|
|
||||||
let len_type = env.ptr_int();
|
let len_type = env.ptr_int();
|
||||||
let elem_bytes = elem_layout.stack_size(env.layout_interner, env.target_info) as u64;
|
let elem_bytes = elem_layout.stack_size(layout_interner, env.target_info) as u64;
|
||||||
let bytes_per_element = len_type.const_int(elem_bytes, false);
|
let bytes_per_element = len_type.const_int(elem_bytes, false);
|
||||||
let number_of_data_bytes =
|
let number_of_data_bytes =
|
||||||
builder.build_int_mul(bytes_per_element, number_of_elements, "data_length");
|
builder.build_int_mul(bytes_per_element, number_of_elements, "data_length");
|
||||||
|
|
||||||
let basic_type = basic_type_from_layout(env, elem_layout);
|
let basic_type = basic_type_from_layout(env, layout_interner, elem_layout);
|
||||||
let alignment_bytes = elem_layout.alignment_bytes(env.layout_interner, env.target_info);
|
let alignment_bytes = elem_layout.alignment_bytes(layout_interner, env.target_info);
|
||||||
allocate_with_refcount_help(env, basic_type, alignment_bytes, number_of_data_bytes)
|
allocate_with_refcount_help(env, basic_type, alignment_bytes, number_of_data_bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ use roc_builtins::bitcode;
|
||||||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||||
use roc_intern::Interner;
|
use roc_intern::Interner;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_mono::layout::{Builtin, InLayout, Layout, LayoutIds, UnionLayout};
|
use roc_mono::layout::{Builtin, InLayout, Layout, LayoutIds, STLayoutInterner, UnionLayout};
|
||||||
|
|
||||||
use super::build::{load_roc_value, use_roc_value, BuilderExt};
|
use super::build::{load_roc_value, use_roc_value, BuilderExt};
|
||||||
use super::convert::argument_type_from_union_layout;
|
use super::convert::argument_type_from_union_layout;
|
||||||
|
@ -22,6 +22,7 @@ use super::lowlevel::dec_binop_with_unchecked;
|
||||||
|
|
||||||
pub fn generic_eq<'a, 'ctx, 'env>(
|
pub fn generic_eq<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
lhs_val: BasicValueEnum<'ctx>,
|
lhs_val: BasicValueEnum<'ctx>,
|
||||||
rhs_val: BasicValueEnum<'ctx>,
|
rhs_val: BasicValueEnum<'ctx>,
|
||||||
|
@ -30,6 +31,7 @@ pub fn generic_eq<'a, 'ctx, 'env>(
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
build_eq(
|
build_eq(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
lhs_val,
|
lhs_val,
|
||||||
rhs_val,
|
rhs_val,
|
||||||
|
@ -41,6 +43,7 @@ pub fn generic_eq<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
pub fn generic_neq<'a, 'ctx, 'env>(
|
pub fn generic_neq<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
lhs_val: BasicValueEnum<'ctx>,
|
lhs_val: BasicValueEnum<'ctx>,
|
||||||
rhs_val: BasicValueEnum<'ctx>,
|
rhs_val: BasicValueEnum<'ctx>,
|
||||||
|
@ -49,6 +52,7 @@ pub fn generic_neq<'a, 'ctx, 'env>(
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
build_neq(
|
build_neq(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
lhs_val,
|
lhs_val,
|
||||||
rhs_val,
|
rhs_val,
|
||||||
|
@ -60,6 +64,7 @@ pub fn generic_neq<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
fn build_eq_builtin<'a, 'ctx, 'env>(
|
fn build_eq_builtin<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
lhs_val: BasicValueEnum<'ctx>,
|
lhs_val: BasicValueEnum<'ctx>,
|
||||||
rhs_val: BasicValueEnum<'ctx>,
|
rhs_val: BasicValueEnum<'ctx>,
|
||||||
|
@ -125,6 +130,7 @@ fn build_eq_builtin<'a, 'ctx, 'env>(
|
||||||
Builtin::Str => str_equal(env, lhs_val, rhs_val),
|
Builtin::Str => str_equal(env, lhs_val, rhs_val),
|
||||||
Builtin::List(elem) => build_list_eq(
|
Builtin::List(elem) => build_list_eq(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
&Layout::Builtin(*builtin),
|
&Layout::Builtin(*builtin),
|
||||||
*elem,
|
*elem,
|
||||||
|
@ -137,6 +143,7 @@ fn build_eq_builtin<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
fn build_eq<'a, 'ctx, 'env>(
|
fn build_eq<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
lhs_val: BasicValueEnum<'ctx>,
|
lhs_val: BasicValueEnum<'ctx>,
|
||||||
rhs_val: BasicValueEnum<'ctx>,
|
rhs_val: BasicValueEnum<'ctx>,
|
||||||
|
@ -144,8 +151,8 @@ fn build_eq<'a, 'ctx, 'env>(
|
||||||
rhs_layout: &Layout<'a>,
|
rhs_layout: &Layout<'a>,
|
||||||
when_recursive: WhenRecursive<'a>,
|
when_recursive: WhenRecursive<'a>,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
let lhs_layout = &lhs_layout.runtime_representation(env.layout_interner);
|
let lhs_layout = &lhs_layout.runtime_representation(layout_interner);
|
||||||
let rhs_layout = &rhs_layout.runtime_representation(env.layout_interner);
|
let rhs_layout = &rhs_layout.runtime_representation(layout_interner);
|
||||||
if lhs_layout != rhs_layout {
|
if lhs_layout != rhs_layout {
|
||||||
panic!(
|
panic!(
|
||||||
"Equality of different layouts; did you have a type mismatch?\n{:?} == {:?}",
|
"Equality of different layouts; did you have a type mismatch?\n{:?} == {:?}",
|
||||||
|
@ -154,12 +161,19 @@ fn build_eq<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
|
|
||||||
match lhs_layout {
|
match lhs_layout {
|
||||||
Layout::Builtin(builtin) => {
|
Layout::Builtin(builtin) => build_eq_builtin(
|
||||||
build_eq_builtin(env, layout_ids, lhs_val, rhs_val, builtin, when_recursive)
|
env,
|
||||||
}
|
layout_interner,
|
||||||
|
layout_ids,
|
||||||
|
lhs_val,
|
||||||
|
rhs_val,
|
||||||
|
builtin,
|
||||||
|
when_recursive,
|
||||||
|
),
|
||||||
|
|
||||||
Layout::Struct { field_layouts, .. } => build_struct_eq(
|
Layout::Struct { field_layouts, .. } => build_struct_eq(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
field_layouts,
|
field_layouts,
|
||||||
when_recursive,
|
when_recursive,
|
||||||
|
@ -171,6 +185,7 @@ fn build_eq<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
Layout::Union(union_layout) => build_tag_eq(
|
Layout::Union(union_layout) => build_tag_eq(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
when_recursive,
|
when_recursive,
|
||||||
union_layout,
|
union_layout,
|
||||||
|
@ -180,6 +195,7 @@ fn build_eq<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
Layout::Boxed(inner_layout) => build_box_eq(
|
Layout::Boxed(inner_layout) => build_box_eq(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
when_recursive,
|
when_recursive,
|
||||||
lhs_layout,
|
lhs_layout,
|
||||||
|
@ -196,7 +212,7 @@ fn build_eq<'a, 'ctx, 'env>(
|
||||||
WhenRecursive::Loop(union_layout) => {
|
WhenRecursive::Loop(union_layout) => {
|
||||||
let layout = Layout::Union(union_layout);
|
let layout = Layout::Union(union_layout);
|
||||||
|
|
||||||
let bt = basic_type_from_layout(env, &layout);
|
let bt = basic_type_from_layout(env, layout_interner, &layout);
|
||||||
|
|
||||||
// cast the i64 pointer to a pointer to block of memory
|
// cast the i64 pointer to a pointer to block of memory
|
||||||
let field1_cast = env.builder.build_pointer_cast(
|
let field1_cast = env.builder.build_pointer_cast(
|
||||||
|
@ -213,6 +229,7 @@ fn build_eq<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
build_tag_eq(
|
build_tag_eq(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
WhenRecursive::Loop(union_layout),
|
WhenRecursive::Loop(union_layout),
|
||||||
&union_layout,
|
&union_layout,
|
||||||
|
@ -226,6 +243,7 @@ fn build_eq<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
fn build_neq_builtin<'a, 'ctx, 'env>(
|
fn build_neq_builtin<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
lhs_val: BasicValueEnum<'ctx>,
|
lhs_val: BasicValueEnum<'ctx>,
|
||||||
rhs_val: BasicValueEnum<'ctx>,
|
rhs_val: BasicValueEnum<'ctx>,
|
||||||
|
@ -297,6 +315,7 @@ fn build_neq_builtin<'a, 'ctx, 'env>(
|
||||||
Builtin::List(elem) => {
|
Builtin::List(elem) => {
|
||||||
let is_equal = build_list_eq(
|
let is_equal = build_list_eq(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
&Layout::Builtin(*builtin),
|
&Layout::Builtin(*builtin),
|
||||||
*elem,
|
*elem,
|
||||||
|
@ -315,6 +334,7 @@ fn build_neq_builtin<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
fn build_neq<'a, 'ctx, 'env>(
|
fn build_neq<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
lhs_val: BasicValueEnum<'ctx>,
|
lhs_val: BasicValueEnum<'ctx>,
|
||||||
rhs_val: BasicValueEnum<'ctx>,
|
rhs_val: BasicValueEnum<'ctx>,
|
||||||
|
@ -330,13 +350,20 @@ fn build_neq<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
|
|
||||||
match lhs_layout {
|
match lhs_layout {
|
||||||
Layout::Builtin(builtin) => {
|
Layout::Builtin(builtin) => build_neq_builtin(
|
||||||
build_neq_builtin(env, layout_ids, lhs_val, rhs_val, builtin, when_recursive)
|
env,
|
||||||
}
|
layout_interner,
|
||||||
|
layout_ids,
|
||||||
|
lhs_val,
|
||||||
|
rhs_val,
|
||||||
|
builtin,
|
||||||
|
when_recursive,
|
||||||
|
),
|
||||||
|
|
||||||
Layout::Struct { field_layouts, .. } => {
|
Layout::Struct { field_layouts, .. } => {
|
||||||
let is_equal = build_struct_eq(
|
let is_equal = build_struct_eq(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
field_layouts,
|
field_layouts,
|
||||||
when_recursive,
|
when_recursive,
|
||||||
|
@ -353,6 +380,7 @@ fn build_neq<'a, 'ctx, 'env>(
|
||||||
Layout::Union(union_layout) => {
|
Layout::Union(union_layout) => {
|
||||||
let is_equal = build_tag_eq(
|
let is_equal = build_tag_eq(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
when_recursive,
|
when_recursive,
|
||||||
union_layout,
|
union_layout,
|
||||||
|
@ -369,6 +397,7 @@ fn build_neq<'a, 'ctx, 'env>(
|
||||||
Layout::Boxed(inner_layout) => {
|
Layout::Boxed(inner_layout) => {
|
||||||
let is_equal = build_box_eq(
|
let is_equal = build_box_eq(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
when_recursive,
|
when_recursive,
|
||||||
lhs_layout,
|
lhs_layout,
|
||||||
|
@ -392,6 +421,7 @@ fn build_neq<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
fn build_list_eq<'a, 'ctx, 'env>(
|
fn build_list_eq<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
list_layout: &Layout<'a>,
|
list_layout: &Layout<'a>,
|
||||||
element_layout: InLayout<'a>,
|
element_layout: InLayout<'a>,
|
||||||
|
@ -403,7 +433,7 @@ fn build_list_eq<'a, 'ctx, 'env>(
|
||||||
let di_location = env.builder.get_current_debug_location().unwrap();
|
let di_location = env.builder.get_current_debug_location().unwrap();
|
||||||
|
|
||||||
let symbol = Symbol::LIST_EQ;
|
let symbol = Symbol::LIST_EQ;
|
||||||
let element_layout = env.layout_interner.get(element_layout);
|
let element_layout = layout_interner.get(element_layout);
|
||||||
let element_layout = when_recursive.unwrap_recursive_pointer(*element_layout);
|
let element_layout = when_recursive.unwrap_recursive_pointer(*element_layout);
|
||||||
let fn_name = layout_ids
|
let fn_name = layout_ids
|
||||||
.get(symbol, &element_layout)
|
.get(symbol, &element_layout)
|
||||||
|
@ -412,7 +442,7 @@ fn build_list_eq<'a, 'ctx, 'env>(
|
||||||
let function = match env.module.get_function(fn_name.as_str()) {
|
let function = match env.module.get_function(fn_name.as_str()) {
|
||||||
Some(function_value) => function_value,
|
Some(function_value) => function_value,
|
||||||
None => {
|
None => {
|
||||||
let arg_type = basic_type_from_layout(env, list_layout);
|
let arg_type = basic_type_from_layout(env, layout_interner, list_layout);
|
||||||
|
|
||||||
let function_value = crate::llvm::refcounting::build_header_help(
|
let function_value = crate::llvm::refcounting::build_header_help(
|
||||||
env,
|
env,
|
||||||
|
@ -423,6 +453,7 @@ fn build_list_eq<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
build_list_eq_help(
|
build_list_eq_help(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
when_recursive,
|
when_recursive,
|
||||||
function_value,
|
function_value,
|
||||||
|
@ -447,6 +478,7 @@ fn build_list_eq<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
fn build_list_eq_help<'a, 'ctx, 'env>(
|
fn build_list_eq_help<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
when_recursive: WhenRecursive<'a>,
|
when_recursive: WhenRecursive<'a>,
|
||||||
parent: FunctionValue<'ctx>,
|
parent: FunctionValue<'ctx>,
|
||||||
|
@ -509,7 +541,7 @@ fn build_list_eq_help<'a, 'ctx, 'env>(
|
||||||
env.builder.position_at_end(then_block);
|
env.builder.position_at_end(then_block);
|
||||||
|
|
||||||
let builder = env.builder;
|
let builder = env.builder;
|
||||||
let element_type = basic_type_from_layout(env, element_layout);
|
let element_type = basic_type_from_layout(env, layout_interner, element_layout);
|
||||||
let ptr_type = element_type.ptr_type(AddressSpace::Generic);
|
let ptr_type = element_type.ptr_type(AddressSpace::Generic);
|
||||||
let ptr1 = load_list_ptr(env.builder, list1, ptr_type);
|
let ptr1 = load_list_ptr(env.builder, list1, ptr_type);
|
||||||
let ptr2 = load_list_ptr(env.builder, list2, ptr_type);
|
let ptr2 = load_list_ptr(env.builder, list2, ptr_type);
|
||||||
|
@ -549,18 +581,19 @@ fn build_list_eq_help<'a, 'ctx, 'env>(
|
||||||
let elem_ptr = unsafe {
|
let elem_ptr = unsafe {
|
||||||
builder.new_build_in_bounds_gep(element_type, ptr1, &[curr_index], "load_index")
|
builder.new_build_in_bounds_gep(element_type, ptr1, &[curr_index], "load_index")
|
||||||
};
|
};
|
||||||
load_roc_value(env, *element_layout, elem_ptr, "get_elem")
|
load_roc_value(env, layout_interner, *element_layout, elem_ptr, "get_elem")
|
||||||
};
|
};
|
||||||
|
|
||||||
let elem2 = {
|
let elem2 = {
|
||||||
let elem_ptr = unsafe {
|
let elem_ptr = unsafe {
|
||||||
builder.new_build_in_bounds_gep(element_type, ptr2, &[curr_index], "load_index")
|
builder.new_build_in_bounds_gep(element_type, ptr2, &[curr_index], "load_index")
|
||||||
};
|
};
|
||||||
load_roc_value(env, *element_layout, elem_ptr, "get_elem")
|
load_roc_value(env, layout_interner, *element_layout, elem_ptr, "get_elem")
|
||||||
};
|
};
|
||||||
|
|
||||||
let are_equal = build_eq(
|
let are_equal = build_eq(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
elem1,
|
elem1,
|
||||||
elem2,
|
elem2,
|
||||||
|
@ -605,6 +638,7 @@ fn build_list_eq_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
fn build_struct_eq<'a, 'ctx, 'env>(
|
fn build_struct_eq<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
field_layouts: &'a [Layout<'a>],
|
field_layouts: &'a [Layout<'a>],
|
||||||
when_recursive: WhenRecursive<'a>,
|
when_recursive: WhenRecursive<'a>,
|
||||||
|
@ -624,7 +658,7 @@ fn build_struct_eq<'a, 'ctx, 'env>(
|
||||||
let function = match env.module.get_function(fn_name.as_str()) {
|
let function = match env.module.get_function(fn_name.as_str()) {
|
||||||
Some(function_value) => function_value,
|
Some(function_value) => function_value,
|
||||||
None => {
|
None => {
|
||||||
let arg_type = basic_type_from_layout(env, &struct_layout);
|
let arg_type = basic_type_from_layout(env, layout_interner, &struct_layout);
|
||||||
|
|
||||||
let function_value = crate::llvm::refcounting::build_header_help(
|
let function_value = crate::llvm::refcounting::build_header_help(
|
||||||
env,
|
env,
|
||||||
|
@ -635,6 +669,7 @@ fn build_struct_eq<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
build_struct_eq_help(
|
build_struct_eq_help(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
function_value,
|
function_value,
|
||||||
when_recursive,
|
when_recursive,
|
||||||
|
@ -659,6 +694,7 @@ fn build_struct_eq<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
fn build_struct_eq_help<'a, 'ctx, 'env>(
|
fn build_struct_eq_help<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
parent: FunctionValue<'ctx>,
|
parent: FunctionValue<'ctx>,
|
||||||
when_recursive: WhenRecursive<'a>,
|
when_recursive: WhenRecursive<'a>,
|
||||||
|
@ -727,7 +763,7 @@ fn build_struct_eq_help<'a, 'ctx, 'env>(
|
||||||
WhenRecursive::Loop(union_layout) => {
|
WhenRecursive::Loop(union_layout) => {
|
||||||
let field_layout = Layout::Union(*union_layout);
|
let field_layout = Layout::Union(*union_layout);
|
||||||
|
|
||||||
let bt = basic_type_from_layout(env, &field_layout);
|
let bt = basic_type_from_layout(env, layout_interner, &field_layout);
|
||||||
|
|
||||||
// cast the i64 pointer to a pointer to block of memory
|
// cast the i64 pointer to a pointer to block of memory
|
||||||
let field1_cast = env.builder.build_pointer_cast(
|
let field1_cast = env.builder.build_pointer_cast(
|
||||||
|
@ -744,6 +780,7 @@ fn build_struct_eq_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
build_eq(
|
build_eq(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
field1_cast.into(),
|
field1_cast.into(),
|
||||||
field2_cast.into(),
|
field2_cast.into(),
|
||||||
|
@ -755,11 +792,14 @@ fn build_struct_eq_help<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
let lhs = use_roc_value(env, layout_interner, *field_layout, field1, "field1");
|
||||||
|
let rhs = use_roc_value(env, layout_interner, *field_layout, field2, "field2");
|
||||||
build_eq(
|
build_eq(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
use_roc_value(env, *field_layout, field1, "field1"),
|
lhs,
|
||||||
use_roc_value(env, *field_layout, field2, "field2"),
|
rhs,
|
||||||
field_layout,
|
field_layout,
|
||||||
field_layout,
|
field_layout,
|
||||||
when_recursive,
|
when_recursive,
|
||||||
|
@ -791,6 +831,7 @@ fn build_struct_eq_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
fn build_tag_eq<'a, 'ctx, 'env>(
|
fn build_tag_eq<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
when_recursive: WhenRecursive<'a>,
|
when_recursive: WhenRecursive<'a>,
|
||||||
union_layout: &UnionLayout<'a>,
|
union_layout: &UnionLayout<'a>,
|
||||||
|
@ -809,7 +850,7 @@ fn build_tag_eq<'a, 'ctx, 'env>(
|
||||||
let function = match env.module.get_function(fn_name.as_str()) {
|
let function = match env.module.get_function(fn_name.as_str()) {
|
||||||
Some(function_value) => function_value,
|
Some(function_value) => function_value,
|
||||||
None => {
|
None => {
|
||||||
let arg_type = argument_type_from_union_layout(env, union_layout);
|
let arg_type = argument_type_from_union_layout(env, layout_interner, union_layout);
|
||||||
|
|
||||||
let function_value = crate::llvm::refcounting::build_header_help(
|
let function_value = crate::llvm::refcounting::build_header_help(
|
||||||
env,
|
env,
|
||||||
|
@ -820,6 +861,7 @@ fn build_tag_eq<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
build_tag_eq_help(
|
build_tag_eq_help(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
when_recursive,
|
when_recursive,
|
||||||
function_value,
|
function_value,
|
||||||
|
@ -844,6 +886,7 @@ fn build_tag_eq<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
fn build_tag_eq_help<'a, 'ctx, 'env>(
|
fn build_tag_eq_help<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
when_recursive: WhenRecursive<'a>,
|
when_recursive: WhenRecursive<'a>,
|
||||||
parent: FunctionValue<'ctx>,
|
parent: FunctionValue<'ctx>,
|
||||||
|
@ -924,8 +967,8 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
env.builder.position_at_end(compare_tag_ids);
|
env.builder.position_at_end(compare_tag_ids);
|
||||||
|
|
||||||
let id1 = get_tag_id(env, parent, union_layout, tag1);
|
let id1 = get_tag_id(env, layout_interner, parent, union_layout, tag1);
|
||||||
let id2 = get_tag_id(env, parent, union_layout, tag2);
|
let id2 = get_tag_id(env, layout_interner, parent, union_layout, tag2);
|
||||||
|
|
||||||
// clear the tag_id so we get a pointer to the actual data
|
// clear the tag_id so we get a pointer to the actual data
|
||||||
let tag1 = tag1.into_pointer_value();
|
let tag1 = tag1.into_pointer_value();
|
||||||
|
@ -952,6 +995,7 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let answer = eq_ptr_to_struct(
|
let answer = eq_ptr_to_struct(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
union_layout,
|
union_layout,
|
||||||
Some(when_recursive),
|
Some(when_recursive),
|
||||||
|
@ -994,8 +1038,8 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
env.builder.position_at_end(compare_tag_ids);
|
env.builder.position_at_end(compare_tag_ids);
|
||||||
|
|
||||||
let id1 = get_tag_id(env, parent, union_layout, tag1);
|
let id1 = get_tag_id(env, layout_interner, parent, union_layout, tag1);
|
||||||
let id2 = get_tag_id(env, parent, union_layout, tag2);
|
let id2 = get_tag_id(env, layout_interner, parent, union_layout, tag2);
|
||||||
|
|
||||||
// clear the tag_id so we get a pointer to the actual data
|
// clear the tag_id so we get a pointer to the actual data
|
||||||
let tag1 = tag_pointer_clear_tag_id(env, tag1.into_pointer_value());
|
let tag1 = tag_pointer_clear_tag_id(env, tag1.into_pointer_value());
|
||||||
|
@ -1022,6 +1066,7 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let answer = eq_ptr_to_struct(
|
let answer = eq_ptr_to_struct(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
union_layout,
|
union_layout,
|
||||||
None,
|
None,
|
||||||
|
@ -1082,6 +1127,7 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let answer = eq_ptr_to_struct(
|
let answer = eq_ptr_to_struct(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
union_layout,
|
union_layout,
|
||||||
None,
|
None,
|
||||||
|
@ -1150,8 +1196,8 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
env.builder.position_at_end(compare_other);
|
env.builder.position_at_end(compare_other);
|
||||||
|
|
||||||
let id1 = get_tag_id(env, parent, union_layout, tag1);
|
let id1 = get_tag_id(env, layout_interner, parent, union_layout, tag1);
|
||||||
let id2 = get_tag_id(env, parent, union_layout, tag2);
|
let id2 = get_tag_id(env, layout_interner, parent, union_layout, tag2);
|
||||||
|
|
||||||
// clear the tag_id so we get a pointer to the actual data
|
// clear the tag_id so we get a pointer to the actual data
|
||||||
let tag1 = tag_pointer_clear_tag_id(env, tag1.into_pointer_value());
|
let tag1 = tag_pointer_clear_tag_id(env, tag1.into_pointer_value());
|
||||||
|
@ -1179,6 +1225,7 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let answer = eq_ptr_to_struct(
|
let answer = eq_ptr_to_struct(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
union_layout,
|
union_layout,
|
||||||
None,
|
None,
|
||||||
|
@ -1217,6 +1264,7 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let answer = eq_ptr_to_struct(
|
let answer = eq_ptr_to_struct(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
union_layout,
|
union_layout,
|
||||||
None,
|
None,
|
||||||
|
@ -1232,6 +1280,7 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
fn eq_ptr_to_struct<'a, 'ctx, 'env>(
|
fn eq_ptr_to_struct<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
union_layout: &UnionLayout<'a>,
|
union_layout: &UnionLayout<'a>,
|
||||||
opt_when_recursive: Option<WhenRecursive<'a>>,
|
opt_when_recursive: Option<WhenRecursive<'a>>,
|
||||||
|
@ -1241,7 +1290,7 @@ fn eq_ptr_to_struct<'a, 'ctx, 'env>(
|
||||||
) -> IntValue<'ctx> {
|
) -> IntValue<'ctx> {
|
||||||
let struct_layout = Layout::struct_no_name_order(field_layouts);
|
let struct_layout = Layout::struct_no_name_order(field_layouts);
|
||||||
|
|
||||||
let wrapper_type = basic_type_from_layout(env, &struct_layout);
|
let wrapper_type = basic_type_from_layout(env, layout_interner, &struct_layout);
|
||||||
debug_assert!(wrapper_type.is_struct_type());
|
debug_assert!(wrapper_type.is_struct_type());
|
||||||
|
|
||||||
// cast the opaque pointer to a pointer of the correct shape
|
// cast the opaque pointer to a pointer of the correct shape
|
||||||
|
@ -1269,6 +1318,7 @@ fn eq_ptr_to_struct<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
build_struct_eq(
|
build_struct_eq(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
field_layouts,
|
field_layouts,
|
||||||
opt_when_recursive.unwrap_or(WhenRecursive::Loop(*union_layout)),
|
opt_when_recursive.unwrap_or(WhenRecursive::Loop(*union_layout)),
|
||||||
|
@ -1282,6 +1332,7 @@ fn eq_ptr_to_struct<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
fn build_box_eq<'a, 'ctx, 'env>(
|
fn build_box_eq<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
when_recursive: WhenRecursive<'a>,
|
when_recursive: WhenRecursive<'a>,
|
||||||
box_layout: &Layout<'a>,
|
box_layout: &Layout<'a>,
|
||||||
|
@ -1300,7 +1351,7 @@ fn build_box_eq<'a, 'ctx, 'env>(
|
||||||
let function = match env.module.get_function(fn_name.as_str()) {
|
let function = match env.module.get_function(fn_name.as_str()) {
|
||||||
Some(function_value) => function_value,
|
Some(function_value) => function_value,
|
||||||
None => {
|
None => {
|
||||||
let arg_type = basic_type_from_layout(env, box_layout);
|
let arg_type = basic_type_from_layout(env, layout_interner, box_layout);
|
||||||
|
|
||||||
let function_value = crate::llvm::refcounting::build_header_help(
|
let function_value = crate::llvm::refcounting::build_header_help(
|
||||||
env,
|
env,
|
||||||
|
@ -1311,6 +1362,7 @@ fn build_box_eq<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
build_box_eq_help(
|
build_box_eq_help(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
when_recursive,
|
when_recursive,
|
||||||
function_value,
|
function_value,
|
||||||
|
@ -1335,6 +1387,7 @@ fn build_box_eq<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
fn build_box_eq_help<'a, 'ctx, 'env>(
|
fn build_box_eq_help<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
when_recursive: WhenRecursive<'a>,
|
when_recursive: WhenRecursive<'a>,
|
||||||
parent: FunctionValue<'ctx>,
|
parent: FunctionValue<'ctx>,
|
||||||
|
@ -1402,13 +1455,14 @@ fn build_box_eq_help<'a, 'ctx, 'env>(
|
||||||
let box1 = box1.into_pointer_value();
|
let box1 = box1.into_pointer_value();
|
||||||
let box2 = box2.into_pointer_value();
|
let box2 = box2.into_pointer_value();
|
||||||
|
|
||||||
let inner_layout = env.layout_interner.get(inner_layout);
|
let inner_layout = layout_interner.get(inner_layout);
|
||||||
|
|
||||||
let value1 = load_roc_value(env, *inner_layout, box1, "load_box1");
|
let value1 = load_roc_value(env, layout_interner, *inner_layout, box1, "load_box1");
|
||||||
let value2 = load_roc_value(env, *inner_layout, box2, "load_box2");
|
let value2 = load_roc_value(env, layout_interner, *inner_layout, box2, "load_box2");
|
||||||
|
|
||||||
let is_equal = build_eq(
|
let is_equal = build_eq(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
value1,
|
value1,
|
||||||
value2,
|
value2,
|
||||||
|
|
|
@ -11,12 +11,13 @@ use roc_target::TargetInfo;
|
||||||
|
|
||||||
fn basic_type_from_record<'a, 'ctx, 'env>(
|
fn basic_type_from_record<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
fields: &[Layout<'_>],
|
fields: &[Layout<'_>],
|
||||||
) -> BasicTypeEnum<'ctx> {
|
) -> BasicTypeEnum<'ctx> {
|
||||||
let mut field_types = Vec::with_capacity_in(fields.len(), env.arena);
|
let mut field_types = Vec::with_capacity_in(fields.len(), env.arena);
|
||||||
|
|
||||||
for field_layout in fields.iter() {
|
for field_layout in fields.iter() {
|
||||||
field_types.push(basic_type_from_layout(env, field_layout));
|
field_types.push(basic_type_from_layout(env, layout_interner, field_layout));
|
||||||
}
|
}
|
||||||
|
|
||||||
env.context
|
env.context
|
||||||
|
@ -26,6 +27,7 @@ fn basic_type_from_record<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
pub fn basic_type_from_layout<'a, 'ctx, 'env>(
|
pub fn basic_type_from_layout<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &'env mut STLayoutInterner<'a>,
|
||||||
layout: &Layout<'_>,
|
layout: &Layout<'_>,
|
||||||
) -> BasicTypeEnum<'ctx> {
|
) -> BasicTypeEnum<'ctx> {
|
||||||
use Layout::*;
|
use Layout::*;
|
||||||
|
@ -34,17 +36,19 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>(
|
||||||
Struct {
|
Struct {
|
||||||
field_layouts: sorted_fields,
|
field_layouts: sorted_fields,
|
||||||
..
|
..
|
||||||
} => basic_type_from_record(env, sorted_fields),
|
} => basic_type_from_record(env, layout_interner, sorted_fields),
|
||||||
LambdaSet(lambda_set) => {
|
LambdaSet(lambda_set) => basic_type_from_layout(
|
||||||
basic_type_from_layout(env, &lambda_set.runtime_representation(env.layout_interner))
|
env,
|
||||||
}
|
layout_interner,
|
||||||
|
&lambda_set.runtime_representation(layout_interner),
|
||||||
|
),
|
||||||
Boxed(inner_layout) => {
|
Boxed(inner_layout) => {
|
||||||
let inner_layout = env.layout_interner.get(*inner_layout);
|
let inner_layout = layout_interner.get(*inner_layout);
|
||||||
let inner_type = basic_type_from_layout(env, inner_layout);
|
let inner_type = basic_type_from_layout(env, layout_interner, inner_layout);
|
||||||
|
|
||||||
inner_type.ptr_type(AddressSpace::Generic).into()
|
inner_type.ptr_type(AddressSpace::Generic).into()
|
||||||
}
|
}
|
||||||
Union(union_layout) => basic_type_from_union_layout(env, union_layout),
|
Union(union_layout) => basic_type_from_union_layout(env, layout_interner, union_layout),
|
||||||
RecursivePointer => env
|
RecursivePointer => env
|
||||||
.context
|
.context
|
||||||
.i64_type()
|
.i64_type()
|
||||||
|
@ -57,13 +61,14 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
pub fn struct_type_from_union_layout<'a, 'ctx, 'env>(
|
pub fn struct_type_from_union_layout<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
union_layout: &UnionLayout<'_>,
|
union_layout: &UnionLayout<'_>,
|
||||||
) -> StructType<'ctx> {
|
) -> StructType<'ctx> {
|
||||||
use UnionLayout::*;
|
use UnionLayout::*;
|
||||||
|
|
||||||
match union_layout {
|
match union_layout {
|
||||||
NonRecursive(tags) => {
|
NonRecursive(tags) => {
|
||||||
RocUnion::tagged_from_slices(env.layout_interner, env.context, tags, env.target_info)
|
RocUnion::tagged_from_slices(layout_interner, env.context, tags, env.target_info)
|
||||||
.struct_type()
|
.struct_type()
|
||||||
}
|
}
|
||||||
Recursive(tags)
|
Recursive(tags)
|
||||||
|
@ -71,47 +76,35 @@ pub fn struct_type_from_union_layout<'a, 'ctx, 'env>(
|
||||||
other_tags: tags, ..
|
other_tags: tags, ..
|
||||||
} => {
|
} => {
|
||||||
if union_layout.stores_tag_id_as_data(env.target_info) {
|
if union_layout.stores_tag_id_as_data(env.target_info) {
|
||||||
RocUnion::tagged_from_slices(
|
RocUnion::tagged_from_slices(layout_interner, env.context, tags, env.target_info)
|
||||||
env.layout_interner,
|
.struct_type()
|
||||||
env.context,
|
|
||||||
tags,
|
|
||||||
env.target_info,
|
|
||||||
)
|
|
||||||
.struct_type()
|
|
||||||
} else {
|
} else {
|
||||||
RocUnion::untagged_from_slices(
|
RocUnion::untagged_from_slices(layout_interner, env.context, tags, env.target_info)
|
||||||
env.layout_interner,
|
.struct_type()
|
||||||
env.context,
|
|
||||||
tags,
|
|
||||||
env.target_info,
|
|
||||||
)
|
|
||||||
.struct_type()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NullableUnwrapped { other_fields, .. } => RocUnion::untagged_from_slices(
|
NullableUnwrapped { other_fields, .. } => RocUnion::untagged_from_slices(
|
||||||
env.layout_interner,
|
layout_interner,
|
||||||
env.context,
|
env.context,
|
||||||
&[other_fields],
|
&[other_fields],
|
||||||
env.target_info,
|
env.target_info,
|
||||||
)
|
)
|
||||||
.struct_type(),
|
.struct_type(),
|
||||||
NonNullableUnwrapped(fields) => RocUnion::untagged_from_slices(
|
NonNullableUnwrapped(fields) => {
|
||||||
env.layout_interner,
|
RocUnion::untagged_from_slices(layout_interner, env.context, &[fields], env.target_info)
|
||||||
env.context,
|
.struct_type()
|
||||||
&[fields],
|
}
|
||||||
env.target_info,
|
|
||||||
)
|
|
||||||
.struct_type(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn basic_type_from_union_layout<'a, 'ctx, 'env>(
|
pub fn basic_type_from_union_layout<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
union_layout: &UnionLayout<'_>,
|
union_layout: &UnionLayout<'_>,
|
||||||
) -> BasicTypeEnum<'ctx> {
|
) -> BasicTypeEnum<'ctx> {
|
||||||
use UnionLayout::*;
|
use UnionLayout::*;
|
||||||
|
|
||||||
let struct_type = struct_type_from_union_layout(env, union_layout);
|
let struct_type = struct_type_from_union_layout(env, layout_interner, union_layout);
|
||||||
|
|
||||||
match union_layout {
|
match union_layout {
|
||||||
NonRecursive(_) => struct_type.into(),
|
NonRecursive(_) => struct_type.into(),
|
||||||
|
@ -153,34 +146,38 @@ pub fn basic_type_from_builtin<'a, 'ctx, 'env>(
|
||||||
/// is not currently implemented
|
/// is not currently implemented
|
||||||
pub fn argument_type_from_layout<'a, 'ctx, 'env>(
|
pub fn argument_type_from_layout<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout: &Layout<'_>,
|
layout: &Layout<'_>,
|
||||||
) -> BasicTypeEnum<'ctx> {
|
) -> BasicTypeEnum<'ctx> {
|
||||||
use Layout::*;
|
use Layout::*;
|
||||||
|
|
||||||
match layout {
|
match layout {
|
||||||
LambdaSet(lambda_set) => {
|
LambdaSet(lambda_set) => argument_type_from_layout(
|
||||||
argument_type_from_layout(env, &lambda_set.runtime_representation(env.layout_interner))
|
env,
|
||||||
}
|
layout_interner,
|
||||||
Union(union_layout) => argument_type_from_union_layout(env, union_layout),
|
&lambda_set.runtime_representation(layout_interner),
|
||||||
|
),
|
||||||
|
Union(union_layout) => argument_type_from_union_layout(env, layout_interner, union_layout),
|
||||||
Builtin(_) => {
|
Builtin(_) => {
|
||||||
let base = basic_type_from_layout(env, layout);
|
let base = basic_type_from_layout(env, layout_interner, layout);
|
||||||
|
|
||||||
if layout.is_passed_by_reference(env.layout_interner, env.target_info) {
|
if layout.is_passed_by_reference(layout_interner, env.target_info) {
|
||||||
base.ptr_type(AddressSpace::Generic).into()
|
base.ptr_type(AddressSpace::Generic).into()
|
||||||
} else {
|
} else {
|
||||||
base
|
base
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
other => basic_type_from_layout(env, other),
|
other => basic_type_from_layout(env, layout_interner, other),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Non-recursive tag unions are stored on the stack, but passed by-reference
|
/// Non-recursive tag unions are stored on the stack, but passed by-reference
|
||||||
pub fn argument_type_from_union_layout<'a, 'ctx, 'env>(
|
pub fn argument_type_from_union_layout<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
union_layout: &UnionLayout<'_>,
|
union_layout: &UnionLayout<'_>,
|
||||||
) -> BasicTypeEnum<'ctx> {
|
) -> BasicTypeEnum<'ctx> {
|
||||||
let heap_type = basic_type_from_union_layout(env, union_layout);
|
let heap_type = basic_type_from_union_layout(env, layout_interner, union_layout);
|
||||||
|
|
||||||
if let UnionLayout::NonRecursive(_) = union_layout {
|
if let UnionLayout::NonRecursive(_) = union_layout {
|
||||||
heap_type.ptr_type(AddressSpace::Generic).into()
|
heap_type.ptr_type(AddressSpace::Generic).into()
|
||||||
|
|
|
@ -12,7 +12,7 @@ use roc_builtins::bitcode;
|
||||||
use roc_intern::Interner;
|
use roc_intern::Interner;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_mono::ir::LookupType;
|
use roc_mono::ir::LookupType;
|
||||||
use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout};
|
use roc_mono::layout::{Builtin, Layout, LayoutIds, STLayoutInterner, UnionLayout};
|
||||||
use roc_region::all::Region;
|
use roc_region::all::Region;
|
||||||
|
|
||||||
use super::build::BuilderExt;
|
use super::build::BuilderExt;
|
||||||
|
@ -167,6 +167,7 @@ pub(crate) fn notify_parent_dbg(env: &Env, shared_memory: &SharedMemoryPointer)
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
|
pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
scope: &Scope<'a, 'ctx>,
|
scope: &Scope<'a, 'ctx>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
shared_memory: &SharedMemoryPointer<'ctx>,
|
shared_memory: &SharedMemoryPointer<'ctx>,
|
||||||
|
@ -201,7 +202,7 @@ pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
|
||||||
let (value, layout) = load_symbol_and_layout(scope, lookup);
|
let (value, layout) = load_symbol_and_layout(scope, lookup);
|
||||||
|
|
||||||
let stack_size = env.ptr_int().const_int(
|
let stack_size = env.ptr_int().const_int(
|
||||||
layout.stack_size(env.layout_interner, env.target_info) as u64,
|
layout.stack_size(layout_interner, env.target_info) as u64,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -214,6 +215,7 @@ pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
extra_offset = build_clone(
|
extra_offset = build_clone(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
original_ptr,
|
original_ptr,
|
||||||
cursors,
|
cursors,
|
||||||
|
@ -280,6 +282,7 @@ pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn build_clone<'a, 'ctx, 'env>(
|
fn build_clone<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
ptr: PointerValue<'ctx>,
|
ptr: PointerValue<'ctx>,
|
||||||
cursors: Cursors<'ctx>,
|
cursors: Cursors<'ctx>,
|
||||||
|
@ -290,6 +293,7 @@ fn build_clone<'a, 'ctx, 'env>(
|
||||||
match layout {
|
match layout {
|
||||||
Layout::Builtin(builtin) => build_clone_builtin(
|
Layout::Builtin(builtin) => build_clone_builtin(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
ptr,
|
ptr,
|
||||||
cursors,
|
cursors,
|
||||||
|
@ -300,6 +304,7 @@ fn build_clone<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
Layout::Struct { field_layouts, .. } => build_clone_struct(
|
Layout::Struct { field_layouts, .. } => build_clone_struct(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
ptr,
|
ptr,
|
||||||
cursors,
|
cursors,
|
||||||
|
@ -313,7 +318,7 @@ fn build_clone<'a, 'ctx, 'env>(
|
||||||
Layout::LambdaSet(_) => cursors.extra_offset,
|
Layout::LambdaSet(_) => cursors.extra_offset,
|
||||||
|
|
||||||
Layout::Union(union_layout) => {
|
Layout::Union(union_layout) => {
|
||||||
if layout.safe_to_memcpy(env.layout_interner) {
|
if layout.safe_to_memcpy(layout_interner) {
|
||||||
let ptr = unsafe {
|
let ptr = unsafe {
|
||||||
env.builder.new_build_in_bounds_gep(
|
env.builder.new_build_in_bounds_gep(
|
||||||
env.context.i8_type(),
|
env.context.i8_type(),
|
||||||
|
@ -328,12 +333,13 @@ fn build_clone<'a, 'ctx, 'env>(
|
||||||
.builder
|
.builder
|
||||||
.build_pointer_cast(ptr, ptr_type, "cast_ptr_type");
|
.build_pointer_cast(ptr, ptr_type, "cast_ptr_type");
|
||||||
|
|
||||||
store_roc_value(env, layout, ptr, value);
|
store_roc_value(env, layout_interner, layout, ptr, value);
|
||||||
|
|
||||||
cursors.extra_offset
|
cursors.extra_offset
|
||||||
} else {
|
} else {
|
||||||
build_clone_tag(
|
build_clone_tag(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
ptr,
|
ptr,
|
||||||
cursors,
|
cursors,
|
||||||
|
@ -349,11 +355,11 @@ fn build_clone<'a, 'ctx, 'env>(
|
||||||
build_copy(env, ptr, cursors.offset, cursors.extra_offset.into());
|
build_copy(env, ptr, cursors.offset, cursors.extra_offset.into());
|
||||||
|
|
||||||
let source = value.into_pointer_value();
|
let source = value.into_pointer_value();
|
||||||
let inner_layout = env.layout_interner.get(inner_layout);
|
let inner_layout = layout_interner.get(inner_layout);
|
||||||
let value = load_roc_value(env, *inner_layout, source, "inner");
|
let value = load_roc_value(env, layout_interner, *inner_layout, source, "inner");
|
||||||
|
|
||||||
let inner_width = env.ptr_int().const_int(
|
let inner_width = env.ptr_int().const_int(
|
||||||
inner_layout.stack_size(env.layout_interner, env.target_info) as u64,
|
inner_layout.stack_size(layout_interner, env.target_info) as u64,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -368,6 +374,7 @@ fn build_clone<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
build_clone(
|
build_clone(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
ptr,
|
ptr,
|
||||||
cursors,
|
cursors,
|
||||||
|
@ -385,7 +392,7 @@ fn build_clone<'a, 'ctx, 'env>(
|
||||||
WhenRecursive::Loop(union_layout) => {
|
WhenRecursive::Loop(union_layout) => {
|
||||||
let layout = Layout::Union(union_layout);
|
let layout = Layout::Union(union_layout);
|
||||||
|
|
||||||
let bt = basic_type_from_layout(env, &layout);
|
let bt = basic_type_from_layout(env, layout_interner, &layout);
|
||||||
|
|
||||||
// cast the i64 pointer to a pointer to block of memory
|
// cast the i64 pointer to a pointer to block of memory
|
||||||
let field1_cast = env.builder.build_pointer_cast(
|
let field1_cast = env.builder.build_pointer_cast(
|
||||||
|
@ -396,6 +403,7 @@ fn build_clone<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
build_clone_tag(
|
build_clone_tag(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
ptr,
|
ptr,
|
||||||
cursors,
|
cursors,
|
||||||
|
@ -411,6 +419,7 @@ fn build_clone<'a, 'ctx, 'env>(
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn build_clone_struct<'a, 'ctx, 'env>(
|
fn build_clone_struct<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
ptr: PointerValue<'ctx>,
|
ptr: PointerValue<'ctx>,
|
||||||
cursors: Cursors<'ctx>,
|
cursors: Cursors<'ctx>,
|
||||||
|
@ -420,7 +429,7 @@ fn build_clone_struct<'a, 'ctx, 'env>(
|
||||||
) -> IntValue<'ctx> {
|
) -> IntValue<'ctx> {
|
||||||
let layout = Layout::struct_no_name_order(field_layouts);
|
let layout = Layout::struct_no_name_order(field_layouts);
|
||||||
|
|
||||||
if layout.safe_to_memcpy(env.layout_interner) {
|
if layout.safe_to_memcpy(layout_interner) {
|
||||||
build_copy(env, ptr, cursors.offset, value)
|
build_copy(env, ptr, cursors.offset, value)
|
||||||
} else {
|
} else {
|
||||||
let mut cursors = cursors;
|
let mut cursors = cursors;
|
||||||
|
@ -433,10 +442,11 @@ fn build_clone_struct<'a, 'ctx, 'env>(
|
||||||
.build_extract_value(structure, i as _, "extract")
|
.build_extract_value(structure, i as _, "extract")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let field = use_roc_value(env, *field_layout, field, "field");
|
let field = use_roc_value(env, layout_interner, *field_layout, field, "field");
|
||||||
|
|
||||||
let new_extra = build_clone(
|
let new_extra = build_clone(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
ptr,
|
ptr,
|
||||||
cursors,
|
cursors,
|
||||||
|
@ -446,7 +456,7 @@ fn build_clone_struct<'a, 'ctx, 'env>(
|
||||||
);
|
);
|
||||||
|
|
||||||
let field_width = env.ptr_int().const_int(
|
let field_width = env.ptr_int().const_int(
|
||||||
field_layout.stack_size(env.layout_interner, env.target_info) as u64,
|
field_layout.stack_size(layout_interner, env.target_info) as u64,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -463,6 +473,7 @@ fn build_clone_struct<'a, 'ctx, 'env>(
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn build_clone_tag<'a, 'ctx, 'env>(
|
fn build_clone_tag<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
ptr: PointerValue<'ctx>,
|
ptr: PointerValue<'ctx>,
|
||||||
cursors: Cursors<'ctx>,
|
cursors: Cursors<'ctx>,
|
||||||
|
@ -505,6 +516,7 @@ fn build_clone_tag<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
build_clone_tag_help(
|
build_clone_tag_help(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
union_layout,
|
union_layout,
|
||||||
when_recursive,
|
when_recursive,
|
||||||
|
@ -539,11 +551,12 @@ fn build_clone_tag<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
fn load_tag_data<'a, 'ctx, 'env>(
|
fn load_tag_data<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
union_layout: UnionLayout<'a>,
|
union_layout: UnionLayout<'a>,
|
||||||
tag_value: PointerValue<'ctx>,
|
tag_value: PointerValue<'ctx>,
|
||||||
tag_type: BasicTypeEnum<'ctx>,
|
tag_type: BasicTypeEnum<'ctx>,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
let union_struct_type = struct_type_from_union_layout(env, &union_layout);
|
let union_struct_type = struct_type_from_union_layout(env, layout_interner, &union_layout);
|
||||||
|
|
||||||
let raw_data_ptr = env
|
let raw_data_ptr = env
|
||||||
.builder
|
.builder
|
||||||
|
@ -567,6 +580,7 @@ fn load_tag_data<'a, 'ctx, 'env>(
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn build_clone_tag_help<'a, 'ctx, 'env>(
|
fn build_clone_tag_help<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
union_layout: UnionLayout<'a>,
|
union_layout: UnionLayout<'a>,
|
||||||
when_recursive: WhenRecursive<'a>,
|
when_recursive: WhenRecursive<'a>,
|
||||||
|
@ -612,7 +626,7 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
||||||
env.builder.build_unreachable();
|
env.builder.build_unreachable();
|
||||||
}
|
}
|
||||||
NonRecursive(tags) => {
|
NonRecursive(tags) => {
|
||||||
let id = get_tag_id(env, parent, &union_layout, tag_value);
|
let id = get_tag_id(env, layout_interner, parent, &union_layout, tag_value);
|
||||||
|
|
||||||
let switch_block = env.context.append_basic_block(parent, "switch_block");
|
let switch_block = env.context.append_basic_block(parent, "switch_block");
|
||||||
env.builder.build_unconditional_branch(switch_block);
|
env.builder.build_unconditional_branch(switch_block);
|
||||||
|
@ -628,16 +642,25 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
||||||
env.arena.alloc([layout, union_layout.tag_id_layout()]),
|
env.arena.alloc([layout, union_layout.tag_id_layout()]),
|
||||||
);
|
);
|
||||||
|
|
||||||
let basic_type = basic_type_from_layout(env, &layout);
|
let basic_type = basic_type_from_layout(env, layout_interner, &layout);
|
||||||
let data = load_tag_data(
|
let data = load_tag_data(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
union_layout,
|
union_layout,
|
||||||
tag_value.into_pointer_value(),
|
tag_value.into_pointer_value(),
|
||||||
basic_type,
|
basic_type,
|
||||||
);
|
);
|
||||||
|
|
||||||
let answer =
|
let answer = build_clone(
|
||||||
build_clone(env, layout_ids, ptr, cursors, data, layout, when_recursive);
|
env,
|
||||||
|
layout_interner,
|
||||||
|
layout_ids,
|
||||||
|
ptr,
|
||||||
|
cursors,
|
||||||
|
data,
|
||||||
|
layout,
|
||||||
|
when_recursive,
|
||||||
|
);
|
||||||
|
|
||||||
env.builder.build_return(Some(&answer));
|
env.builder.build_return(Some(&answer));
|
||||||
|
|
||||||
|
@ -657,7 +680,7 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Recursive(tags) => {
|
Recursive(tags) => {
|
||||||
let id = get_tag_id(env, parent, &union_layout, tag_value);
|
let id = get_tag_id(env, layout_interner, parent, &union_layout, tag_value);
|
||||||
|
|
||||||
let switch_block = env.context.append_basic_block(parent, "switch_block");
|
let switch_block = env.context.append_basic_block(parent, "switch_block");
|
||||||
env.builder.build_unconditional_branch(switch_block);
|
env.builder.build_unconditional_branch(switch_block);
|
||||||
|
@ -682,11 +705,11 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let basic_type = basic_type_from_layout(env, &layout);
|
let basic_type = basic_type_from_layout(env, layout_interner, &layout);
|
||||||
let data = load_tag_data(env, union_layout, tag_value, basic_type);
|
let data = load_tag_data(env, layout_interner, union_layout, tag_value, basic_type);
|
||||||
|
|
||||||
let (width, _) =
|
let (width, _) =
|
||||||
union_layout.data_size_and_alignment(env.layout_interner, env.target_info);
|
union_layout.data_size_and_alignment(layout_interner, env.target_info);
|
||||||
|
|
||||||
let cursors = Cursors {
|
let cursors = Cursors {
|
||||||
offset: extra_offset,
|
offset: extra_offset,
|
||||||
|
@ -698,8 +721,16 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
||||||
};
|
};
|
||||||
|
|
||||||
let when_recursive = WhenRecursive::Loop(union_layout);
|
let when_recursive = WhenRecursive::Loop(union_layout);
|
||||||
let answer =
|
let answer = build_clone(
|
||||||
build_clone(env, layout_ids, ptr, cursors, data, layout, when_recursive);
|
env,
|
||||||
|
layout_interner,
|
||||||
|
layout_ids,
|
||||||
|
ptr,
|
||||||
|
cursors,
|
||||||
|
data,
|
||||||
|
layout,
|
||||||
|
when_recursive,
|
||||||
|
);
|
||||||
|
|
||||||
env.builder.build_return(Some(&answer));
|
env.builder.build_return(Some(&answer));
|
||||||
|
|
||||||
|
@ -724,10 +755,9 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
||||||
build_copy(env, ptr, offset, extra_offset.into());
|
build_copy(env, ptr, offset, extra_offset.into());
|
||||||
|
|
||||||
let layout = Layout::struct_no_name_order(fields);
|
let layout = Layout::struct_no_name_order(fields);
|
||||||
let basic_type = basic_type_from_layout(env, &layout);
|
let basic_type = basic_type_from_layout(env, layout_interner, &layout);
|
||||||
|
|
||||||
let (width, _) =
|
let (width, _) = union_layout.data_size_and_alignment(layout_interner, env.target_info);
|
||||||
union_layout.data_size_and_alignment(env.layout_interner, env.target_info);
|
|
||||||
|
|
||||||
let cursors = Cursors {
|
let cursors = Cursors {
|
||||||
offset: extra_offset,
|
offset: extra_offset,
|
||||||
|
@ -738,10 +768,19 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
let data = load_tag_data(env, union_layout, tag_value, basic_type);
|
let data = load_tag_data(env, layout_interner, union_layout, tag_value, basic_type);
|
||||||
|
|
||||||
let when_recursive = WhenRecursive::Loop(union_layout);
|
let when_recursive = WhenRecursive::Loop(union_layout);
|
||||||
let answer = build_clone(env, layout_ids, ptr, cursors, data, layout, when_recursive);
|
let answer = build_clone(
|
||||||
|
env,
|
||||||
|
layout_interner,
|
||||||
|
layout_ids,
|
||||||
|
ptr,
|
||||||
|
cursors,
|
||||||
|
data,
|
||||||
|
layout,
|
||||||
|
when_recursive,
|
||||||
|
);
|
||||||
|
|
||||||
env.builder.build_return(Some(&answer));
|
env.builder.build_return(Some(&answer));
|
||||||
}
|
}
|
||||||
|
@ -752,7 +791,7 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
||||||
let switch_block = env.context.append_basic_block(parent, "switch_block");
|
let switch_block = env.context.append_basic_block(parent, "switch_block");
|
||||||
let null_block = env.context.append_basic_block(parent, "null_block");
|
let null_block = env.context.append_basic_block(parent, "null_block");
|
||||||
|
|
||||||
let id = get_tag_id(env, parent, &union_layout, tag_value);
|
let id = get_tag_id(env, layout_interner, parent, &union_layout, tag_value);
|
||||||
|
|
||||||
let comparison = env
|
let comparison = env
|
||||||
.builder
|
.builder
|
||||||
|
@ -782,10 +821,10 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
||||||
};
|
};
|
||||||
|
|
||||||
let layout = Layout::struct_no_name_order(fields);
|
let layout = Layout::struct_no_name_order(fields);
|
||||||
let basic_type = basic_type_from_layout(env, &layout);
|
let basic_type = basic_type_from_layout(env, layout_interner, &layout);
|
||||||
|
|
||||||
let (width, _) =
|
let (width, _) =
|
||||||
union_layout.data_size_and_alignment(env.layout_interner, env.target_info);
|
union_layout.data_size_and_alignment(layout_interner, env.target_info);
|
||||||
|
|
||||||
let cursors = Cursors {
|
let cursors = Cursors {
|
||||||
offset: extra_offset,
|
offset: extra_offset,
|
||||||
|
@ -797,11 +836,20 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
||||||
};
|
};
|
||||||
|
|
||||||
let tag_value = tag_pointer_clear_tag_id(env, tag_value.into_pointer_value());
|
let tag_value = tag_pointer_clear_tag_id(env, tag_value.into_pointer_value());
|
||||||
let data = load_tag_data(env, union_layout, tag_value, basic_type);
|
let data =
|
||||||
|
load_tag_data(env, layout_interner, union_layout, tag_value, basic_type);
|
||||||
|
|
||||||
let when_recursive = WhenRecursive::Loop(union_layout);
|
let when_recursive = WhenRecursive::Loop(union_layout);
|
||||||
let answer =
|
let answer = build_clone(
|
||||||
build_clone(env, layout_ids, ptr, cursors, data, layout, when_recursive);
|
env,
|
||||||
|
layout_interner,
|
||||||
|
layout_ids,
|
||||||
|
ptr,
|
||||||
|
cursors,
|
||||||
|
data,
|
||||||
|
layout,
|
||||||
|
when_recursive,
|
||||||
|
);
|
||||||
|
|
||||||
env.builder.build_return(Some(&answer));
|
env.builder.build_return(Some(&answer));
|
||||||
|
|
||||||
|
@ -857,14 +905,14 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
||||||
build_copy(env, ptr, offset, extra_offset.into());
|
build_copy(env, ptr, offset, extra_offset.into());
|
||||||
|
|
||||||
let layout = Layout::struct_no_name_order(other_fields);
|
let layout = Layout::struct_no_name_order(other_fields);
|
||||||
let basic_type = basic_type_from_layout(env, &layout);
|
let basic_type = basic_type_from_layout(env, layout_interner, &layout);
|
||||||
|
|
||||||
let cursors = Cursors {
|
let cursors = Cursors {
|
||||||
offset: extra_offset,
|
offset: extra_offset,
|
||||||
extra_offset: env.builder.build_int_add(
|
extra_offset: env.builder.build_int_add(
|
||||||
extra_offset,
|
extra_offset,
|
||||||
env.ptr_int().const_int(
|
env.ptr_int().const_int(
|
||||||
layout.stack_size(env.layout_interner, env.target_info) as _,
|
layout.stack_size(layout_interner, env.target_info) as _,
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
"new_offset",
|
"new_offset",
|
||||||
|
@ -873,14 +921,23 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let data = load_tag_data(
|
let data = load_tag_data(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
union_layout,
|
union_layout,
|
||||||
tag_value.into_pointer_value(),
|
tag_value.into_pointer_value(),
|
||||||
basic_type,
|
basic_type,
|
||||||
);
|
);
|
||||||
|
|
||||||
let when_recursive = WhenRecursive::Loop(union_layout);
|
let when_recursive = WhenRecursive::Loop(union_layout);
|
||||||
let answer =
|
let answer = build_clone(
|
||||||
build_clone(env, layout_ids, ptr, cursors, data, layout, when_recursive);
|
env,
|
||||||
|
layout_interner,
|
||||||
|
layout_ids,
|
||||||
|
ptr,
|
||||||
|
cursors,
|
||||||
|
data,
|
||||||
|
layout,
|
||||||
|
when_recursive,
|
||||||
|
);
|
||||||
|
|
||||||
env.builder.build_return(Some(&answer));
|
env.builder.build_return(Some(&answer));
|
||||||
}
|
}
|
||||||
|
@ -945,6 +1002,7 @@ fn build_copy<'a, 'ctx, 'env>(
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn build_clone_builtin<'a, 'ctx, 'env>(
|
fn build_clone_builtin<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
ptr: PointerValue<'ctx>,
|
ptr: PointerValue<'ctx>,
|
||||||
cursors: Cursors<'ctx>,
|
cursors: Cursors<'ctx>,
|
||||||
|
@ -990,14 +1048,14 @@ fn build_clone_builtin<'a, 'ctx, 'env>(
|
||||||
offset = build_copy(env, ptr, offset, len.into());
|
offset = build_copy(env, ptr, offset, len.into());
|
||||||
offset = build_copy(env, ptr, offset, len.into());
|
offset = build_copy(env, ptr, offset, len.into());
|
||||||
|
|
||||||
let elem = env.layout_interner.get(elem);
|
let elem = layout_interner.get(elem);
|
||||||
let (element_width, _element_align) =
|
let (element_width, _element_align) =
|
||||||
elem.stack_size_and_alignment(env.layout_interner, env.target_info);
|
elem.stack_size_and_alignment(layout_interner, env.target_info);
|
||||||
let element_width = env.ptr_int().const_int(element_width as _, false);
|
let element_width = env.ptr_int().const_int(element_width as _, false);
|
||||||
|
|
||||||
let elements_width = bd.build_int_mul(element_width, len, "elements_width");
|
let elements_width = bd.build_int_mul(element_width, len, "elements_width");
|
||||||
|
|
||||||
if elem.safe_to_memcpy(env.layout_interner) {
|
if elem.safe_to_memcpy(layout_interner) {
|
||||||
// NOTE we are not actually sure the dest is properly aligned
|
// NOTE we are not actually sure the dest is properly aligned
|
||||||
let dest = pointer_at_offset(bd, env.context.i8_type(), ptr, offset);
|
let dest = pointer_at_offset(bd, env.context.i8_type(), ptr, offset);
|
||||||
let src = bd.build_pointer_cast(
|
let src = bd.build_pointer_cast(
|
||||||
|
@ -1012,7 +1070,7 @@ fn build_clone_builtin<'a, 'ctx, 'env>(
|
||||||
// We cloned the elements into the extra_offset address.
|
// We cloned the elements into the extra_offset address.
|
||||||
let elements_start_offset = cursors.extra_offset;
|
let elements_start_offset = cursors.extra_offset;
|
||||||
|
|
||||||
let element_type = basic_type_from_layout(env, elem);
|
let element_type = basic_type_from_layout(env, layout_interner, elem);
|
||||||
let elements = bd.build_pointer_cast(
|
let elements = bd.build_pointer_cast(
|
||||||
elements,
|
elements,
|
||||||
element_type.ptr_type(AddressSpace::Generic),
|
element_type.ptr_type(AddressSpace::Generic),
|
||||||
|
@ -1023,7 +1081,7 @@ fn build_clone_builtin<'a, 'ctx, 'env>(
|
||||||
let rest_offset = bd.build_alloca(env.ptr_int(), "rest_offset");
|
let rest_offset = bd.build_alloca(env.ptr_int(), "rest_offset");
|
||||||
|
|
||||||
let element_stack_size = env.ptr_int().const_int(
|
let element_stack_size = env.ptr_int().const_int(
|
||||||
elem.stack_size(env.layout_interner, env.target_info) as u64,
|
elem.stack_size(layout_interner, env.target_info) as u64,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
let rest_start_offset = bd.build_int_add(
|
let rest_start_offset = bd.build_int_add(
|
||||||
|
@ -1033,7 +1091,7 @@ fn build_clone_builtin<'a, 'ctx, 'env>(
|
||||||
);
|
);
|
||||||
bd.build_store(rest_offset, rest_start_offset);
|
bd.build_store(rest_offset, rest_start_offset);
|
||||||
|
|
||||||
let body = |index, element| {
|
let body = |layout_interner, index, element| {
|
||||||
let current_offset =
|
let current_offset =
|
||||||
bd.build_int_mul(element_stack_size, index, "current_offset");
|
bd.build_int_mul(element_stack_size, index, "current_offset");
|
||||||
let current_offset =
|
let current_offset =
|
||||||
|
@ -1051,6 +1109,7 @@ fn build_clone_builtin<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let new_offset = build_clone(
|
let new_offset = build_clone(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
ptr,
|
ptr,
|
||||||
cursors,
|
cursors,
|
||||||
|
@ -1068,7 +1127,16 @@ fn build_clone_builtin<'a, 'ctx, 'env>(
|
||||||
.and_then(|b| b.get_parent())
|
.and_then(|b| b.get_parent())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
incrementing_elem_loop(env, parent, *elem, elements, len, "index", body);
|
incrementing_elem_loop(
|
||||||
|
env,
|
||||||
|
layout_interner,
|
||||||
|
parent,
|
||||||
|
*elem,
|
||||||
|
elements,
|
||||||
|
len,
|
||||||
|
"index",
|
||||||
|
body,
|
||||||
|
);
|
||||||
|
|
||||||
bd.new_build_load(env.ptr_int(), rest_offset, "rest_start_offset")
|
bd.new_build_load(env.ptr_int(), rest_offset, "rest_start_offset")
|
||||||
.into_int_value()
|
.into_int_value()
|
||||||
|
|
|
@ -13,7 +13,7 @@ use roc_intern::Interner;
|
||||||
use roc_module::{low_level::LowLevel, symbol::Symbol};
|
use roc_module::{low_level::LowLevel, symbol::Symbol};
|
||||||
use roc_mono::{
|
use roc_mono::{
|
||||||
ir::HigherOrderLowLevel,
|
ir::HigherOrderLowLevel,
|
||||||
layout::{Builtin, LambdaSet, Layout, LayoutIds},
|
layout::{Builtin, LambdaSet, Layout, LayoutIds, STLayoutInterner},
|
||||||
};
|
};
|
||||||
use roc_target::PtrWidth;
|
use roc_target::PtrWidth;
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ macro_rules! list_element_layout {
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
scope: &Scope<'a, 'ctx>,
|
scope: &Scope<'a, 'ctx>,
|
||||||
parent: FunctionValue<'ctx>,
|
parent: FunctionValue<'ctx>,
|
||||||
|
@ -256,7 +257,8 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||||
);
|
);
|
||||||
|
|
||||||
let roc_return_type =
|
let roc_return_type =
|
||||||
basic_type_from_layout(env, layout).ptr_type(AddressSpace::Generic);
|
basic_type_from_layout(env, layout_interner, layout)
|
||||||
|
.ptr_type(AddressSpace::Generic);
|
||||||
|
|
||||||
let roc_return_alloca = env.builder.build_pointer_cast(
|
let roc_return_alloca = env.builder.build_pointer_cast(
|
||||||
zig_return_alloca,
|
zig_return_alloca,
|
||||||
|
@ -264,7 +266,13 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||||
"cast_to_roc",
|
"cast_to_roc",
|
||||||
);
|
);
|
||||||
|
|
||||||
load_roc_value(env, *layout, roc_return_alloca, "str_to_num_result")
|
load_roc_value(
|
||||||
|
env,
|
||||||
|
layout_interner,
|
||||||
|
*layout,
|
||||||
|
roc_return_alloca,
|
||||||
|
"str_to_num_result",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -286,6 +294,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
call_bitcode_fn_fixing_for_convention(
|
call_bitcode_fn_fixing_for_convention(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
bitcode_return_type,
|
bitcode_return_type,
|
||||||
&[string],
|
&[string],
|
||||||
layout,
|
layout,
|
||||||
|
@ -298,7 +307,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||||
};
|
};
|
||||||
|
|
||||||
// zig passes the result as a packed integer sometimes, instead of a struct. So we cast
|
// zig passes the result as a packed integer sometimes, instead of a struct. So we cast
|
||||||
let expected_type = basic_type_from_layout(env, layout);
|
let expected_type = basic_type_from_layout(env, layout_interner, layout);
|
||||||
let actual_type = result.get_type();
|
let actual_type = result.get_type();
|
||||||
|
|
||||||
if expected_type != actual_type {
|
if expected_type != actual_type {
|
||||||
|
@ -487,7 +496,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||||
bitcode::STR_GET_SCALAR_UNSAFE,
|
bitcode::STR_GET_SCALAR_UNSAFE,
|
||||||
);
|
);
|
||||||
|
|
||||||
let return_type = basic_type_from_layout(env, layout);
|
let return_type = basic_type_from_layout(env, layout_interner, layout);
|
||||||
let cast_result = env.builder.build_pointer_cast(
|
let cast_result = env.builder.build_pointer_cast(
|
||||||
result,
|
result,
|
||||||
return_type.ptr_type(AddressSpace::Generic),
|
return_type.ptr_type(AddressSpace::Generic),
|
||||||
|
@ -510,7 +519,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||||
match env.target_info.ptr_width() {
|
match env.target_info.ptr_width() {
|
||||||
PtrWidth::Bytes8 => result,
|
PtrWidth::Bytes8 => result,
|
||||||
PtrWidth::Bytes4 => {
|
PtrWidth::Bytes4 => {
|
||||||
let to = basic_type_from_layout(env, layout);
|
let to = basic_type_from_layout(env, layout_interner, layout);
|
||||||
complex_bitcast_check_size(env, result, to, "to_roc_record")
|
complex_bitcast_check_size(env, result, to, "to_roc_record")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -645,6 +654,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||||
let result_layout = *layout;
|
let result_layout = *layout;
|
||||||
list_with_capacity(
|
list_with_capacity(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
list_len.into_int_value(),
|
list_len.into_int_value(),
|
||||||
list_element_layout!(result_layout),
|
list_element_layout!(result_layout),
|
||||||
)
|
)
|
||||||
|
@ -658,7 +668,13 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let element_layout = list_element_layout!(list_layout);
|
let element_layout = list_element_layout!(list_layout);
|
||||||
|
|
||||||
list_concat(env, first_list, second_list, *element_layout)
|
list_concat(
|
||||||
|
env,
|
||||||
|
layout_interner,
|
||||||
|
first_list,
|
||||||
|
second_list,
|
||||||
|
*element_layout,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
ListAppendUnsafe => {
|
ListAppendUnsafe => {
|
||||||
// List.appendUnsafe : List elem, elem -> List elem
|
// List.appendUnsafe : List elem, elem -> List elem
|
||||||
|
@ -667,7 +683,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||||
let original_wrapper = load_symbol(scope, &args[0]).into_struct_value();
|
let original_wrapper = load_symbol(scope, &args[0]).into_struct_value();
|
||||||
let (elem, elem_layout) = load_symbol_and_layout(scope, &args[1]);
|
let (elem, elem_layout) = load_symbol_and_layout(scope, &args[1]);
|
||||||
|
|
||||||
list_append_unsafe(env, original_wrapper, elem, elem_layout)
|
list_append_unsafe(env, layout_interner, original_wrapper, elem, elem_layout)
|
||||||
}
|
}
|
||||||
ListPrepend => {
|
ListPrepend => {
|
||||||
// List.prepend : List elem, elem -> List elem
|
// List.prepend : List elem, elem -> List elem
|
||||||
|
@ -676,7 +692,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||||
let original_wrapper = load_symbol(scope, &args[0]).into_struct_value();
|
let original_wrapper = load_symbol(scope, &args[0]).into_struct_value();
|
||||||
let (elem, elem_layout) = load_symbol_and_layout(scope, &args[1]);
|
let (elem, elem_layout) = load_symbol_and_layout(scope, &args[1]);
|
||||||
|
|
||||||
list_prepend(env, original_wrapper, elem, elem_layout)
|
list_prepend(env, layout_interner, original_wrapper, elem, elem_layout)
|
||||||
}
|
}
|
||||||
ListReserve => {
|
ListReserve => {
|
||||||
// List.reserve : List elem, Nat -> List elem
|
// List.reserve : List elem, Nat -> List elem
|
||||||
|
@ -686,7 +702,14 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||||
let element_layout = list_element_layout!(list_layout);
|
let element_layout = list_element_layout!(list_layout);
|
||||||
let spare = load_symbol(scope, &args[1]);
|
let spare = load_symbol(scope, &args[1]);
|
||||||
|
|
||||||
list_reserve(env, list, spare, *element_layout, update_mode)
|
list_reserve(
|
||||||
|
env,
|
||||||
|
layout_interner,
|
||||||
|
list,
|
||||||
|
spare,
|
||||||
|
*element_layout,
|
||||||
|
update_mode,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
ListSwap => {
|
ListSwap => {
|
||||||
// List.swap : List elem, Nat, Nat -> List elem
|
// List.swap : List elem, Nat, Nat -> List elem
|
||||||
|
@ -701,6 +724,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||||
let element_layout = list_element_layout!(list_layout);
|
let element_layout = list_element_layout!(list_layout);
|
||||||
list_swap(
|
list_swap(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
original_wrapper,
|
original_wrapper,
|
||||||
index_1.into_int_value(),
|
index_1.into_int_value(),
|
||||||
index_2.into_int_value(),
|
index_2.into_int_value(),
|
||||||
|
@ -720,6 +744,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||||
let element_layout = list_element_layout!(list_layout);
|
let element_layout = list_element_layout!(list_layout);
|
||||||
list_sublist(
|
list_sublist(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
original_wrapper,
|
original_wrapper,
|
||||||
start.into_int_value(),
|
start.into_int_value(),
|
||||||
|
@ -739,6 +764,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||||
let element_layout = list_element_layout!(list_layout);
|
let element_layout = list_element_layout!(list_layout);
|
||||||
list_drop_at(
|
list_drop_at(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
original_wrapper,
|
original_wrapper,
|
||||||
count.into_int_value(),
|
count.into_int_value(),
|
||||||
|
@ -763,6 +789,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
list_get_unsafe(
|
list_get_unsafe(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
*list_element_layout!(list_layout),
|
*list_element_layout!(list_layout),
|
||||||
element_index.into_int_value(),
|
element_index.into_int_value(),
|
||||||
|
@ -774,6 +801,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
list_replace_unsafe(
|
list_replace_unsafe(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
list,
|
list,
|
||||||
index.into_int_value(),
|
index.into_int_value(),
|
||||||
|
@ -844,6 +872,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||||
let int_type = convert::int_type_from_int_width(env, *int_width);
|
let int_type = convert::int_type_from_int_width(env, *int_width);
|
||||||
build_int_unary_op(
|
build_int_unary_op(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
parent,
|
parent,
|
||||||
arg.into_int_value(),
|
arg.into_int_value(),
|
||||||
*int_width,
|
*int_width,
|
||||||
|
@ -1033,7 +1062,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||||
NumIntCast => {
|
NumIntCast => {
|
||||||
arguments!(arg);
|
arguments!(arg);
|
||||||
|
|
||||||
let to = basic_type_from_layout(env, layout).into_int_type();
|
let to = basic_type_from_layout(env, layout_interner, layout).into_int_type();
|
||||||
let to_signed = intwidth_from_layout(*layout).is_signed();
|
let to_signed = intwidth_from_layout(*layout).is_signed();
|
||||||
|
|
||||||
env.builder
|
env.builder
|
||||||
|
@ -1047,7 +1076,8 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||||
Layout::Builtin(Builtin::Int(width)) => {
|
Layout::Builtin(Builtin::Int(width)) => {
|
||||||
// Converting from int to float
|
// Converting from int to float
|
||||||
let int_val = arg.into_int_value();
|
let int_val = arg.into_int_value();
|
||||||
let dest = basic_type_from_layout(env, layout).into_float_type();
|
let dest =
|
||||||
|
basic_type_from_layout(env, layout_interner, layout).into_float_type();
|
||||||
|
|
||||||
if width.is_signed() {
|
if width.is_signed() {
|
||||||
env.builder
|
env.builder
|
||||||
|
@ -1061,7 +1091,8 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
Layout::Builtin(Builtin::Float(_)) => {
|
Layout::Builtin(Builtin::Float(_)) => {
|
||||||
// Converting from float to float - e.g. F64 to F32, or vice versa
|
// Converting from float to float - e.g. F64 to F32, or vice versa
|
||||||
let dest = basic_type_from_layout(env, layout).into_float_type();
|
let dest =
|
||||||
|
basic_type_from_layout(env, layout_interner, layout).into_float_type();
|
||||||
|
|
||||||
env.builder
|
env.builder
|
||||||
.build_float_cast(arg.into_float_value(), dest, "cast_float_to_float")
|
.build_float_cast(arg.into_float_value(), dest, "cast_float_to_float")
|
||||||
|
@ -1083,12 +1114,28 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||||
Eq => {
|
Eq => {
|
||||||
arguments_with_layouts!((lhs_arg, lhs_layout), (rhs_arg, rhs_layout));
|
arguments_with_layouts!((lhs_arg, lhs_layout), (rhs_arg, rhs_layout));
|
||||||
|
|
||||||
generic_eq(env, layout_ids, lhs_arg, rhs_arg, lhs_layout, rhs_layout)
|
generic_eq(
|
||||||
|
env,
|
||||||
|
layout_interner,
|
||||||
|
layout_ids,
|
||||||
|
lhs_arg,
|
||||||
|
rhs_arg,
|
||||||
|
lhs_layout,
|
||||||
|
rhs_layout,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
NotEq => {
|
NotEq => {
|
||||||
arguments_with_layouts!((lhs_arg, lhs_layout), (rhs_arg, rhs_layout));
|
arguments_with_layouts!((lhs_arg, lhs_layout), (rhs_arg, rhs_layout));
|
||||||
|
|
||||||
generic_neq(env, layout_ids, lhs_arg, rhs_arg, lhs_layout, rhs_layout)
|
generic_neq(
|
||||||
|
env,
|
||||||
|
layout_interner,
|
||||||
|
layout_ids,
|
||||||
|
lhs_arg,
|
||||||
|
rhs_arg,
|
||||||
|
lhs_layout,
|
||||||
|
rhs_layout,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
And => {
|
And => {
|
||||||
// The (&&) operator
|
// The (&&) operator
|
||||||
|
@ -1137,13 +1184,13 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||||
unreachable!("Not used in LLVM backend: {:?}", op);
|
unreachable!("Not used in LLVM backend: {:?}", op);
|
||||||
}
|
}
|
||||||
|
|
||||||
Unreachable => match RocReturn::from_layout(env, layout) {
|
Unreachable => match RocReturn::from_layout(env, layout_interner, layout) {
|
||||||
RocReturn::Return => {
|
RocReturn::Return => {
|
||||||
let basic_type = basic_type_from_layout(env, layout);
|
let basic_type = basic_type_from_layout(env, layout_interner, layout);
|
||||||
basic_type.const_zero()
|
basic_type.const_zero()
|
||||||
}
|
}
|
||||||
RocReturn::ByPointer => {
|
RocReturn::ByPointer => {
|
||||||
let basic_type = basic_type_from_layout(env, layout);
|
let basic_type = basic_type_from_layout(env, layout_interner, layout);
|
||||||
let ptr = env.builder.build_alloca(basic_type, "unreachable_alloca");
|
let ptr = env.builder.build_alloca(basic_type, "unreachable_alloca");
|
||||||
env.builder.build_store(ptr, basic_type.const_zero());
|
env.builder.build_store(ptr, basic_type.const_zero());
|
||||||
|
|
||||||
|
@ -1817,6 +1864,7 @@ fn int_type_signed_min(int_type: IntType) -> IntValue {
|
||||||
|
|
||||||
fn build_int_unary_op<'a, 'ctx, 'env>(
|
fn build_int_unary_op<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
parent: FunctionValue<'ctx>,
|
parent: FunctionValue<'ctx>,
|
||||||
arg: IntValue<'ctx>,
|
arg: IntValue<'ctx>,
|
||||||
arg_width: IntWidth,
|
arg_width: IntWidth,
|
||||||
|
@ -1887,8 +1935,8 @@ fn build_int_unary_op<'a, 'ctx, 'env>(
|
||||||
|| // Or if the two types are the same, they trivially fit.
|
|| // Or if the two types are the same, they trivially fit.
|
||||||
arg_width == target_int_width;
|
arg_width == target_int_width;
|
||||||
|
|
||||||
let return_type =
|
let return_type = convert::basic_type_from_layout(env, layout_interner, return_layout)
|
||||||
convert::basic_type_from_layout(env, return_layout).into_struct_type();
|
.into_struct_type();
|
||||||
|
|
||||||
if arg_always_fits_in_target {
|
if arg_always_fits_in_target {
|
||||||
// This is guaranteed to succeed so we can just make it an int cast and let LLVM
|
// This is guaranteed to succeed so we can just make it an int cast and let LLVM
|
||||||
|
@ -1958,8 +2006,9 @@ fn build_int_unary_op<'a, 'ctx, 'env>(
|
||||||
intrinsic,
|
intrinsic,
|
||||||
);
|
);
|
||||||
|
|
||||||
let roc_return_type = basic_type_from_layout(env, return_layout)
|
let roc_return_type =
|
||||||
.ptr_type(AddressSpace::Generic);
|
basic_type_from_layout(env, layout_interner, return_layout)
|
||||||
|
.ptr_type(AddressSpace::Generic);
|
||||||
|
|
||||||
let roc_return_alloca = env.builder.build_pointer_cast(
|
let roc_return_alloca = env.builder.build_pointer_cast(
|
||||||
zig_return_alloca,
|
zig_return_alloca,
|
||||||
|
@ -1967,7 +2016,13 @@ fn build_int_unary_op<'a, 'ctx, 'env>(
|
||||||
"cast_to_roc",
|
"cast_to_roc",
|
||||||
);
|
);
|
||||||
|
|
||||||
load_roc_value(env, *return_layout, roc_return_alloca, "num_to_int")
|
load_roc_value(
|
||||||
|
env,
|
||||||
|
layout_interner,
|
||||||
|
*return_layout,
|
||||||
|
roc_return_alloca,
|
||||||
|
"num_to_int",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1978,6 +2033,7 @@ fn build_int_unary_op<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
call_bitcode_fn_fixing_for_convention(
|
call_bitcode_fn_fixing_for_convention(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
bitcode_return_type,
|
bitcode_return_type,
|
||||||
&[arg.into()],
|
&[arg.into()],
|
||||||
return_layout,
|
return_layout,
|
||||||
|
@ -2221,6 +2277,7 @@ fn build_float_unary_op<'a, 'ctx, 'env>(
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
scope: &Scope<'a, 'ctx>,
|
scope: &Scope<'a, 'ctx>,
|
||||||
return_layout: &Layout<'a>,
|
return_layout: &Layout<'a>,
|
||||||
|
@ -2276,13 +2333,14 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
Layout::Builtin(Builtin::List(element_layout)),
|
Layout::Builtin(Builtin::List(element_layout)),
|
||||||
Layout::Builtin(Builtin::List(result_layout)),
|
Layout::Builtin(Builtin::List(result_layout)),
|
||||||
) => {
|
) => {
|
||||||
let element_layout = env.layout_interner.get(*element_layout);
|
let element_layout = layout_interner.get(*element_layout);
|
||||||
let result_layout = env.layout_interner.get(*result_layout);
|
let result_layout = layout_interner.get(*result_layout);
|
||||||
|
|
||||||
let argument_layouts = &[*element_layout];
|
let argument_layouts = &[*element_layout];
|
||||||
|
|
||||||
let roc_function_call = roc_function_call(
|
let roc_function_call = roc_function_call(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
function,
|
function,
|
||||||
closure,
|
closure,
|
||||||
|
@ -2292,7 +2350,14 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
*result_layout,
|
*result_layout,
|
||||||
);
|
);
|
||||||
|
|
||||||
list_map(env, roc_function_call, list, element_layout, result_layout)
|
list_map(
|
||||||
|
env,
|
||||||
|
layout_interner,
|
||||||
|
roc_function_call,
|
||||||
|
list,
|
||||||
|
element_layout,
|
||||||
|
result_layout,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
_ => unreachable!("invalid list layout"),
|
_ => unreachable!("invalid list layout"),
|
||||||
}
|
}
|
||||||
|
@ -2309,14 +2374,15 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
Layout::Builtin(Builtin::List(element2_layout)),
|
Layout::Builtin(Builtin::List(element2_layout)),
|
||||||
Layout::Builtin(Builtin::List(result_layout)),
|
Layout::Builtin(Builtin::List(result_layout)),
|
||||||
) => {
|
) => {
|
||||||
let element1_layout = env.layout_interner.get(*element1_layout);
|
let element1_layout = layout_interner.get(*element1_layout);
|
||||||
let element2_layout = env.layout_interner.get(*element2_layout);
|
let element2_layout = layout_interner.get(*element2_layout);
|
||||||
let result_layout = env.layout_interner.get(*result_layout);
|
let result_layout = layout_interner.get(*result_layout);
|
||||||
|
|
||||||
let argument_layouts = &[*element1_layout, *element2_layout];
|
let argument_layouts = &[*element1_layout, *element2_layout];
|
||||||
|
|
||||||
let roc_function_call = roc_function_call(
|
let roc_function_call = roc_function_call(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
function,
|
function,
|
||||||
closure,
|
closure,
|
||||||
|
@ -2328,6 +2394,7 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
list_map2(
|
list_map2(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
roc_function_call,
|
roc_function_call,
|
||||||
list1,
|
list1,
|
||||||
|
@ -2354,15 +2421,16 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
Layout::Builtin(Builtin::List(element3_layout)),
|
Layout::Builtin(Builtin::List(element3_layout)),
|
||||||
Layout::Builtin(Builtin::List(result_layout)),
|
Layout::Builtin(Builtin::List(result_layout)),
|
||||||
) => {
|
) => {
|
||||||
let element1_layout = env.layout_interner.get(*element1_layout);
|
let element1_layout = layout_interner.get(*element1_layout);
|
||||||
let element2_layout = env.layout_interner.get(*element2_layout);
|
let element2_layout = layout_interner.get(*element2_layout);
|
||||||
let element3_layout = env.layout_interner.get(*element3_layout);
|
let element3_layout = layout_interner.get(*element3_layout);
|
||||||
let result_layout = env.layout_interner.get(*result_layout);
|
let result_layout = layout_interner.get(*result_layout);
|
||||||
|
|
||||||
let argument_layouts = &[*element1_layout, *element2_layout, *element3_layout];
|
let argument_layouts = &[*element1_layout, *element2_layout, *element3_layout];
|
||||||
|
|
||||||
let roc_function_call = roc_function_call(
|
let roc_function_call = roc_function_call(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
function,
|
function,
|
||||||
closure,
|
closure,
|
||||||
|
@ -2374,6 +2442,7 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
list_map3(
|
list_map3(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
roc_function_call,
|
roc_function_call,
|
||||||
list1,
|
list1,
|
||||||
|
@ -2410,11 +2479,11 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
Layout::Builtin(Builtin::List(element4_layout)),
|
Layout::Builtin(Builtin::List(element4_layout)),
|
||||||
Layout::Builtin(Builtin::List(result_layout)),
|
Layout::Builtin(Builtin::List(result_layout)),
|
||||||
) => {
|
) => {
|
||||||
let element1_layout = env.layout_interner.get(*element1_layout);
|
let element1_layout = layout_interner.get(*element1_layout);
|
||||||
let element2_layout = env.layout_interner.get(*element2_layout);
|
let element2_layout = layout_interner.get(*element2_layout);
|
||||||
let element3_layout = env.layout_interner.get(*element3_layout);
|
let element3_layout = layout_interner.get(*element3_layout);
|
||||||
let element4_layout = env.layout_interner.get(*element4_layout);
|
let element4_layout = layout_interner.get(*element4_layout);
|
||||||
let result_layout = env.layout_interner.get(*result_layout);
|
let result_layout = layout_interner.get(*result_layout);
|
||||||
|
|
||||||
let argument_layouts = &[
|
let argument_layouts = &[
|
||||||
*element1_layout,
|
*element1_layout,
|
||||||
|
@ -2425,6 +2494,7 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let roc_function_call = roc_function_call(
|
let roc_function_call = roc_function_call(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
function,
|
function,
|
||||||
closure,
|
closure,
|
||||||
|
@ -2436,6 +2506,7 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
list_map4(
|
list_map4(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
roc_function_call,
|
roc_function_call,
|
||||||
list1,
|
list1,
|
||||||
|
@ -2462,17 +2533,23 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
Layout::Builtin(Builtin::List(element_layout)) => {
|
Layout::Builtin(Builtin::List(element_layout)) => {
|
||||||
use crate::llvm::bitcode::build_compare_wrapper;
|
use crate::llvm::bitcode::build_compare_wrapper;
|
||||||
|
|
||||||
let element_layout = env.layout_interner.get(*element_layout);
|
let element_layout = layout_interner.get(*element_layout);
|
||||||
|
|
||||||
let argument_layouts = &[*element_layout, *element_layout];
|
let argument_layouts = &[*element_layout, *element_layout];
|
||||||
|
|
||||||
let compare_wrapper =
|
let compare_wrapper = build_compare_wrapper(
|
||||||
build_compare_wrapper(env, function, closure_layout, element_layout)
|
env,
|
||||||
.as_global_value()
|
layout_interner,
|
||||||
.as_pointer_value();
|
function,
|
||||||
|
closure_layout,
|
||||||
|
element_layout,
|
||||||
|
)
|
||||||
|
.as_global_value()
|
||||||
|
.as_pointer_value();
|
||||||
|
|
||||||
let roc_function_call = roc_function_call(
|
let roc_function_call = roc_function_call(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
function,
|
function,
|
||||||
closure,
|
closure,
|
||||||
|
@ -2484,6 +2561,7 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
list_sort_with(
|
list_sort_with(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
roc_function_call,
|
roc_function_call,
|
||||||
compare_wrapper,
|
compare_wrapper,
|
||||||
list,
|
list,
|
||||||
|
|
|
@ -114,10 +114,11 @@ impl<'ctx> PointerToRefcount<'ctx> {
|
||||||
mode: CallMode<'ctx>,
|
mode: CallMode<'ctx>,
|
||||||
layout: &Layout<'a>,
|
layout: &Layout<'a>,
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
) {
|
) {
|
||||||
match mode {
|
match mode {
|
||||||
CallMode::Inc(inc_amount) => self.increment(inc_amount, env),
|
CallMode::Inc(inc_amount) => self.increment(inc_amount, env),
|
||||||
CallMode::Dec => self.decrement(env, layout),
|
CallMode::Dec => self.decrement(env, layout_interner, layout),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,9 +126,14 @@ impl<'ctx> PointerToRefcount<'ctx> {
|
||||||
incref_pointer(env, self.value, amount);
|
incref_pointer(env, self.value, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decrement<'a, 'env>(&self, env: &Env<'a, 'ctx, 'env>, layout: &Layout<'a>) {
|
pub fn decrement<'a, 'env>(
|
||||||
|
&self,
|
||||||
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
|
layout: &Layout<'a>,
|
||||||
|
) {
|
||||||
let alignment = layout
|
let alignment = layout
|
||||||
.allocation_alignment_bytes(env.layout_interner, env.target_info)
|
.allocation_alignment_bytes(layout_interner, env.target_info)
|
||||||
.max(env.target_info.ptr_width() as u32);
|
.max(env.target_info.ptr_width() as u32);
|
||||||
|
|
||||||
let context = env.context;
|
let context = env.context;
|
||||||
|
@ -266,6 +272,7 @@ pub fn decref_pointer_check_null<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
fn modify_refcount_struct<'a, 'ctx, 'env>(
|
fn modify_refcount_struct<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
layouts: &'a [Layout<'a>],
|
layouts: &'a [Layout<'a>],
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
|
@ -288,11 +295,12 @@ fn modify_refcount_struct<'a, 'ctx, 'env>(
|
||||||
let function = match env.module.get_function(fn_name.as_str()) {
|
let function = match env.module.get_function(fn_name.as_str()) {
|
||||||
Some(function_value) => function_value,
|
Some(function_value) => function_value,
|
||||||
None => {
|
None => {
|
||||||
let basic_type = basic_type_from_layout(env, &layout);
|
let basic_type = basic_type_from_layout(env, layout_interner, &layout);
|
||||||
let function_value = build_header(env, basic_type, mode, &fn_name);
|
let function_value = build_header(env, basic_type, mode, &fn_name);
|
||||||
|
|
||||||
modify_refcount_struct_help(
|
modify_refcount_struct_help(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
mode,
|
mode,
|
||||||
when_recursive,
|
when_recursive,
|
||||||
|
@ -314,6 +322,7 @@ fn modify_refcount_struct<'a, 'ctx, 'env>(
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn modify_refcount_struct_help<'a, 'ctx, 'env>(
|
fn modify_refcount_struct_help<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
when_recursive: &WhenRecursive<'a>,
|
when_recursive: &WhenRecursive<'a>,
|
||||||
|
@ -339,7 +348,7 @@ fn modify_refcount_struct_help<'a, 'ctx, 'env>(
|
||||||
let wrapper_struct = arg_val.into_struct_value();
|
let wrapper_struct = arg_val.into_struct_value();
|
||||||
|
|
||||||
for (i, field_layout) in layouts.iter().enumerate() {
|
for (i, field_layout) in layouts.iter().enumerate() {
|
||||||
if field_layout.contains_refcounted(env.layout_interner) {
|
if field_layout.contains_refcounted(layout_interner) {
|
||||||
let raw_value = env
|
let raw_value = env
|
||||||
.builder
|
.builder
|
||||||
.build_extract_value(wrapper_struct, i as u32, "decrement_struct_field")
|
.build_extract_value(wrapper_struct, i as u32, "decrement_struct_field")
|
||||||
|
@ -347,6 +356,7 @@ fn modify_refcount_struct_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let field_value = use_roc_value(
|
let field_value = use_roc_value(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
*field_layout,
|
*field_layout,
|
||||||
raw_value,
|
raw_value,
|
||||||
"load_struct_tag_field_for_decrement",
|
"load_struct_tag_field_for_decrement",
|
||||||
|
@ -354,6 +364,7 @@ fn modify_refcount_struct_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
modify_refcount_layout_help(
|
modify_refcount_layout_help(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
mode.to_call_mode(fn_val),
|
mode.to_call_mode(fn_val),
|
||||||
when_recursive,
|
when_recursive,
|
||||||
|
@ -368,36 +379,54 @@ fn modify_refcount_struct_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
pub fn increment_refcount_layout<'a, 'ctx, 'env>(
|
pub fn increment_refcount_layout<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
inc_amount: u64,
|
inc_amount: u64,
|
||||||
value: BasicValueEnum<'ctx>,
|
value: BasicValueEnum<'ctx>,
|
||||||
layout: &Layout<'a>,
|
layout: &Layout<'a>,
|
||||||
) {
|
) {
|
||||||
let amount = env.ptr_int().const_int(inc_amount, false);
|
let amount = env.ptr_int().const_int(inc_amount, false);
|
||||||
increment_n_refcount_layout(env, layout_ids, amount, value, layout);
|
increment_n_refcount_layout(env, layout_interner, layout_ids, amount, value, layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn increment_n_refcount_layout<'a, 'ctx, 'env>(
|
pub fn increment_n_refcount_layout<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
amount: IntValue<'ctx>,
|
amount: IntValue<'ctx>,
|
||||||
value: BasicValueEnum<'ctx>,
|
value: BasicValueEnum<'ctx>,
|
||||||
layout: &Layout<'a>,
|
layout: &Layout<'a>,
|
||||||
) {
|
) {
|
||||||
modify_refcount_layout(env, layout_ids, CallMode::Inc(amount), value, layout);
|
modify_refcount_layout(
|
||||||
|
env,
|
||||||
|
layout_interner,
|
||||||
|
layout_ids,
|
||||||
|
CallMode::Inc(amount),
|
||||||
|
value,
|
||||||
|
layout,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decrement_refcount_layout<'a, 'ctx, 'env>(
|
pub fn decrement_refcount_layout<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
value: BasicValueEnum<'ctx>,
|
value: BasicValueEnum<'ctx>,
|
||||||
layout: &Layout<'a>,
|
layout: &Layout<'a>,
|
||||||
) {
|
) {
|
||||||
modify_refcount_layout(env, layout_ids, CallMode::Dec, value, layout);
|
modify_refcount_layout(
|
||||||
|
env,
|
||||||
|
layout_interner,
|
||||||
|
layout_ids,
|
||||||
|
CallMode::Dec,
|
||||||
|
value,
|
||||||
|
layout,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn modify_refcount_builtin<'a, 'ctx, 'env>(
|
fn modify_refcount_builtin<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
when_recursive: &WhenRecursive<'a>,
|
when_recursive: &WhenRecursive<'a>,
|
||||||
|
@ -408,13 +437,25 @@ fn modify_refcount_builtin<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
match builtin {
|
match builtin {
|
||||||
List(element_layout) => {
|
List(element_layout) => {
|
||||||
let function =
|
let function = modify_refcount_list(
|
||||||
modify_refcount_list(env, layout_ids, mode, when_recursive, *element_layout);
|
env,
|
||||||
|
layout_interner,
|
||||||
|
layout_ids,
|
||||||
|
mode,
|
||||||
|
when_recursive,
|
||||||
|
*element_layout,
|
||||||
|
);
|
||||||
|
|
||||||
Some(function)
|
Some(function)
|
||||||
}
|
}
|
||||||
|
|
||||||
Str => Some(modify_refcount_str(env, layout_ids, mode, layout)),
|
Str => Some(modify_refcount_str(
|
||||||
|
env,
|
||||||
|
layout_interner,
|
||||||
|
layout_ids,
|
||||||
|
mode,
|
||||||
|
layout,
|
||||||
|
)),
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
debug_assert!(!builtin.is_refcounted());
|
debug_assert!(!builtin.is_refcounted());
|
||||||
|
@ -425,6 +466,7 @@ fn modify_refcount_builtin<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
fn modify_refcount_layout<'a, 'ctx, 'env>(
|
fn modify_refcount_layout<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
call_mode: CallMode<'ctx>,
|
call_mode: CallMode<'ctx>,
|
||||||
value: BasicValueEnum<'ctx>,
|
value: BasicValueEnum<'ctx>,
|
||||||
|
@ -432,6 +474,7 @@ fn modify_refcount_layout<'a, 'ctx, 'env>(
|
||||||
) {
|
) {
|
||||||
modify_refcount_layout_help(
|
modify_refcount_layout_help(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
call_mode,
|
call_mode,
|
||||||
&WhenRecursive::Unreachable,
|
&WhenRecursive::Unreachable,
|
||||||
|
@ -442,6 +485,7 @@ fn modify_refcount_layout<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
fn modify_refcount_layout_help<'a, 'ctx, 'env>(
|
fn modify_refcount_layout_help<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
call_mode: CallMode<'ctx>,
|
call_mode: CallMode<'ctx>,
|
||||||
when_recursive: &WhenRecursive<'a>,
|
when_recursive: &WhenRecursive<'a>,
|
||||||
|
@ -455,6 +499,7 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let function = match modify_refcount_layout_build_function(
|
let function = match modify_refcount_layout_build_function(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
mode,
|
mode,
|
||||||
when_recursive,
|
when_recursive,
|
||||||
|
@ -472,7 +517,7 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>(
|
||||||
WhenRecursive::Loop(union_layout) => {
|
WhenRecursive::Loop(union_layout) => {
|
||||||
let layout = Layout::Union(*union_layout);
|
let layout = Layout::Union(*union_layout);
|
||||||
|
|
||||||
let bt = basic_type_from_layout(env, &layout);
|
let bt = basic_type_from_layout(env, layout_interner, &layout);
|
||||||
|
|
||||||
// cast the i64 pointer to a pointer to block of memory
|
// cast the i64 pointer to a pointer to block of memory
|
||||||
let field_cast = env.builder.build_pointer_cast(
|
let field_cast = env.builder.build_pointer_cast(
|
||||||
|
@ -519,6 +564,7 @@ fn call_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
fn modify_refcount_layout_build_function<'a, 'ctx, 'env>(
|
fn modify_refcount_layout_build_function<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
when_recursive: &WhenRecursive<'a>,
|
when_recursive: &WhenRecursive<'a>,
|
||||||
|
@ -527,12 +573,18 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>(
|
||||||
use Layout::*;
|
use Layout::*;
|
||||||
|
|
||||||
match layout {
|
match layout {
|
||||||
Builtin(builtin) => {
|
Builtin(builtin) => modify_refcount_builtin(
|
||||||
modify_refcount_builtin(env, layout_ids, mode, when_recursive, layout, builtin)
|
env,
|
||||||
}
|
layout_interner,
|
||||||
|
layout_ids,
|
||||||
|
mode,
|
||||||
|
when_recursive,
|
||||||
|
layout,
|
||||||
|
builtin,
|
||||||
|
),
|
||||||
|
|
||||||
Boxed(inner) => {
|
Boxed(inner) => {
|
||||||
let function = modify_refcount_boxed(env, layout_ids, mode, *inner);
|
let function = modify_refcount_boxed(env, layout_interner, layout_ids, mode, *inner);
|
||||||
|
|
||||||
Some(function)
|
Some(function)
|
||||||
}
|
}
|
||||||
|
@ -547,8 +599,14 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
|
|
||||||
NonRecursive(tags) => {
|
NonRecursive(tags) => {
|
||||||
let function =
|
let function = modify_refcount_nonrecursive(
|
||||||
modify_refcount_nonrecursive(env, layout_ids, mode, when_recursive, tags);
|
env,
|
||||||
|
layout_interner,
|
||||||
|
layout_ids,
|
||||||
|
mode,
|
||||||
|
when_recursive,
|
||||||
|
tags,
|
||||||
|
);
|
||||||
|
|
||||||
Some(function)
|
Some(function)
|
||||||
}
|
}
|
||||||
|
@ -556,6 +614,7 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>(
|
||||||
_ => {
|
_ => {
|
||||||
let function = build_rec_union(
|
let function = build_rec_union(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
mode,
|
mode,
|
||||||
&WhenRecursive::Loop(*variant),
|
&WhenRecursive::Loop(*variant),
|
||||||
|
@ -568,8 +627,14 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
|
|
||||||
Struct { field_layouts, .. } => {
|
Struct { field_layouts, .. } => {
|
||||||
let function =
|
let function = modify_refcount_struct(
|
||||||
modify_refcount_struct(env, layout_ids, field_layouts, mode, when_recursive);
|
env,
|
||||||
|
layout_interner,
|
||||||
|
layout_ids,
|
||||||
|
field_layouts,
|
||||||
|
mode,
|
||||||
|
when_recursive,
|
||||||
|
);
|
||||||
|
|
||||||
Some(function)
|
Some(function)
|
||||||
}
|
}
|
||||||
|
@ -583,6 +648,7 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let function = modify_refcount_layout_build_function(
|
let function = modify_refcount_layout_build_function(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
mode,
|
mode,
|
||||||
when_recursive,
|
when_recursive,
|
||||||
|
@ -594,16 +660,18 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>(
|
||||||
},
|
},
|
||||||
LambdaSet(lambda_set) => modify_refcount_layout_build_function(
|
LambdaSet(lambda_set) => modify_refcount_layout_build_function(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
mode,
|
mode,
|
||||||
when_recursive,
|
when_recursive,
|
||||||
&lambda_set.runtime_representation(env.layout_interner),
|
&lambda_set.runtime_representation(layout_interner),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn modify_refcount_list<'a, 'ctx, 'env>(
|
fn modify_refcount_list<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
when_recursive: &WhenRecursive<'a>,
|
when_recursive: &WhenRecursive<'a>,
|
||||||
|
@ -612,9 +680,9 @@ fn modify_refcount_list<'a, 'ctx, 'env>(
|
||||||
let block = env.builder.get_insert_block().expect("to be in a function");
|
let block = env.builder.get_insert_block().expect("to be in a function");
|
||||||
let di_location = env.builder.get_current_debug_location().unwrap();
|
let di_location = env.builder.get_current_debug_location().unwrap();
|
||||||
|
|
||||||
let element_layout = env.layout_interner.get(element_layout);
|
let element_layout = layout_interner.get(element_layout);
|
||||||
let element_layout = when_recursive.unwrap_recursive_pointer(*element_layout);
|
let element_layout = when_recursive.unwrap_recursive_pointer(*element_layout);
|
||||||
let element_layout = env.layout_interner.insert(env.arena.alloc(element_layout));
|
let element_layout = layout_interner.insert(env.arena.alloc(element_layout));
|
||||||
let list_layout = &Layout::Builtin(Builtin::List(element_layout));
|
let list_layout = &Layout::Builtin(Builtin::List(element_layout));
|
||||||
let (_, fn_name) = function_name_from_mode(
|
let (_, fn_name) = function_name_from_mode(
|
||||||
layout_ids,
|
layout_ids,
|
||||||
|
@ -628,11 +696,12 @@ fn modify_refcount_list<'a, 'ctx, 'env>(
|
||||||
let function = match env.module.get_function(fn_name.as_str()) {
|
let function = match env.module.get_function(fn_name.as_str()) {
|
||||||
Some(function_value) => function_value,
|
Some(function_value) => function_value,
|
||||||
None => {
|
None => {
|
||||||
let basic_type = argument_type_from_layout(env, list_layout);
|
let basic_type = argument_type_from_layout(env, layout_interner, list_layout);
|
||||||
let function_value = build_header(env, basic_type, mode, &fn_name);
|
let function_value = build_header(env, basic_type, mode, &fn_name);
|
||||||
|
|
||||||
modify_refcount_list_help(
|
modify_refcount_list_help(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
mode,
|
mode,
|
||||||
when_recursive,
|
when_recursive,
|
||||||
|
@ -661,6 +730,7 @@ fn mode_to_call_mode(function: FunctionValue<'_>, mode: Mode) -> CallMode<'_> {
|
||||||
|
|
||||||
fn modify_refcount_list_help<'a, 'ctx, 'env>(
|
fn modify_refcount_list_help<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
when_recursive: &WhenRecursive<'a>,
|
when_recursive: &WhenRecursive<'a>,
|
||||||
|
@ -704,15 +774,17 @@ fn modify_refcount_list_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
builder.position_at_end(modification_block);
|
builder.position_at_end(modification_block);
|
||||||
|
|
||||||
let element_layout = env.layout_interner.get(element_layout);
|
let element_layout = layout_interner.get(element_layout);
|
||||||
if element_layout.contains_refcounted(env.layout_interner) {
|
if element_layout.contains_refcounted(layout_interner) {
|
||||||
let ptr_type = basic_type_from_layout(env, element_layout).ptr_type(AddressSpace::Generic);
|
let ptr_type = basic_type_from_layout(env, layout_interner, element_layout)
|
||||||
|
.ptr_type(AddressSpace::Generic);
|
||||||
|
|
||||||
let (len, ptr) = load_list(env.builder, original_wrapper, ptr_type);
|
let (len, ptr) = load_list(env.builder, original_wrapper, ptr_type);
|
||||||
|
|
||||||
let loop_fn = |_index, element| {
|
let loop_fn = |layout_interner, _index, element| {
|
||||||
modify_refcount_layout_help(
|
modify_refcount_layout_help(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
mode.to_call_mode(fn_val),
|
mode.to_call_mode(fn_val),
|
||||||
when_recursive,
|
when_recursive,
|
||||||
|
@ -723,6 +795,7 @@ fn modify_refcount_list_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
incrementing_elem_loop(
|
incrementing_elem_loop(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
parent,
|
parent,
|
||||||
*element_layout,
|
*element_layout,
|
||||||
ptr,
|
ptr,
|
||||||
|
@ -734,7 +807,7 @@ fn modify_refcount_list_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let refcount_ptr = PointerToRefcount::from_list_wrapper(env, original_wrapper);
|
let refcount_ptr = PointerToRefcount::from_list_wrapper(env, original_wrapper);
|
||||||
let call_mode = mode_to_call_mode(fn_val, mode);
|
let call_mode = mode_to_call_mode(fn_val, mode);
|
||||||
refcount_ptr.modify(call_mode, layout, env);
|
refcount_ptr.modify(call_mode, layout, env, layout_interner);
|
||||||
|
|
||||||
builder.build_unconditional_branch(cont_block);
|
builder.build_unconditional_branch(cont_block);
|
||||||
|
|
||||||
|
@ -746,6 +819,7 @@ fn modify_refcount_list_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
fn modify_refcount_str<'a, 'ctx, 'env>(
|
fn modify_refcount_str<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
layout: &Layout<'a>,
|
layout: &Layout<'a>,
|
||||||
|
@ -765,10 +839,10 @@ fn modify_refcount_str<'a, 'ctx, 'env>(
|
||||||
let function = match env.module.get_function(fn_name.as_str()) {
|
let function = match env.module.get_function(fn_name.as_str()) {
|
||||||
Some(function_value) => function_value,
|
Some(function_value) => function_value,
|
||||||
None => {
|
None => {
|
||||||
let basic_type = argument_type_from_layout(env, layout);
|
let basic_type = argument_type_from_layout(env, layout_interner, layout);
|
||||||
let function_value = build_header(env, basic_type, mode, &fn_name);
|
let function_value = build_header(env, basic_type, mode, &fn_name);
|
||||||
|
|
||||||
modify_refcount_str_help(env, mode, layout, function_value);
|
modify_refcount_str_help(env, layout_interner, mode, layout, function_value);
|
||||||
|
|
||||||
function_value
|
function_value
|
||||||
}
|
}
|
||||||
|
@ -783,6 +857,7 @@ fn modify_refcount_str<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
fn modify_refcount_str_help<'a, 'ctx, 'env>(
|
fn modify_refcount_str_help<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
layout: &Layout<'a>,
|
layout: &Layout<'a>,
|
||||||
fn_val: FunctionValue<'ctx>,
|
fn_val: FunctionValue<'ctx>,
|
||||||
|
@ -805,17 +880,16 @@ fn modify_refcount_str_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let parent = fn_val;
|
let parent = fn_val;
|
||||||
|
|
||||||
let arg_val = if Layout::Builtin(Builtin::Str)
|
let arg_val =
|
||||||
.is_passed_by_reference(env.layout_interner, env.target_info)
|
if Layout::Builtin(Builtin::Str).is_passed_by_reference(layout_interner, env.target_info) {
|
||||||
{
|
let str_type = zig_str_type(env);
|
||||||
let str_type = zig_str_type(env);
|
env.builder
|
||||||
env.builder
|
.new_build_load(str_type, arg_val.into_pointer_value(), "load_str_to_stack")
|
||||||
.new_build_load(str_type, arg_val.into_pointer_value(), "load_str_to_stack")
|
} else {
|
||||||
} else {
|
// it's already a struct, just do nothing
|
||||||
// it's already a struct, just do nothing
|
debug_assert!(arg_val.is_struct_value());
|
||||||
debug_assert!(arg_val.is_struct_value());
|
arg_val
|
||||||
arg_val
|
};
|
||||||
};
|
|
||||||
let str_wrapper = arg_val.into_struct_value();
|
let str_wrapper = arg_val.into_struct_value();
|
||||||
|
|
||||||
let capacity = builder
|
let capacity = builder
|
||||||
|
@ -841,7 +915,7 @@ fn modify_refcount_str_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let refcount_ptr = PointerToRefcount::from_list_wrapper(env, str_wrapper);
|
let refcount_ptr = PointerToRefcount::from_list_wrapper(env, str_wrapper);
|
||||||
let call_mode = mode_to_call_mode(fn_val, mode);
|
let call_mode = mode_to_call_mode(fn_val, mode);
|
||||||
refcount_ptr.modify(call_mode, layout, env);
|
refcount_ptr.modify(call_mode, layout, env, layout_interner);
|
||||||
|
|
||||||
builder.build_unconditional_branch(cont_block);
|
builder.build_unconditional_branch(cont_block);
|
||||||
|
|
||||||
|
@ -853,6 +927,7 @@ fn modify_refcount_str_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
fn modify_refcount_boxed<'a, 'ctx, 'env>(
|
fn modify_refcount_boxed<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
inner_layout: InLayout<'a>,
|
inner_layout: InLayout<'a>,
|
||||||
|
@ -874,10 +949,10 @@ fn modify_refcount_boxed<'a, 'ctx, 'env>(
|
||||||
let function = match env.module.get_function(fn_name.as_str()) {
|
let function = match env.module.get_function(fn_name.as_str()) {
|
||||||
Some(function_value) => function_value,
|
Some(function_value) => function_value,
|
||||||
None => {
|
None => {
|
||||||
let basic_type = basic_type_from_layout(env, boxed_layout);
|
let basic_type = basic_type_from_layout(env, layout_interner, boxed_layout);
|
||||||
let function_value = build_header(env, basic_type, mode, &fn_name);
|
let function_value = build_header(env, basic_type, mode, &fn_name);
|
||||||
|
|
||||||
modify_refcount_box_help(env, mode, inner_layout, function_value);
|
modify_refcount_box_help(env, layout_interner, mode, inner_layout, function_value);
|
||||||
|
|
||||||
function_value
|
function_value
|
||||||
}
|
}
|
||||||
|
@ -892,6 +967,7 @@ fn modify_refcount_boxed<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
fn modify_refcount_box_help<'a, 'ctx, 'env>(
|
fn modify_refcount_box_help<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
inner_layout: InLayout<'a>,
|
inner_layout: InLayout<'a>,
|
||||||
fn_val: FunctionValue<'ctx>,
|
fn_val: FunctionValue<'ctx>,
|
||||||
|
@ -915,7 +991,7 @@ fn modify_refcount_box_help<'a, 'ctx, 'env>(
|
||||||
let refcount_ptr = PointerToRefcount::from_ptr_to_data(env, boxed);
|
let refcount_ptr = PointerToRefcount::from_ptr_to_data(env, boxed);
|
||||||
let call_mode = mode_to_call_mode(fn_val, mode);
|
let call_mode = mode_to_call_mode(fn_val, mode);
|
||||||
let boxed_layout = Layout::Boxed(inner_layout);
|
let boxed_layout = Layout::Boxed(inner_layout);
|
||||||
refcount_ptr.modify(call_mode, &boxed_layout, env);
|
refcount_ptr.modify(call_mode, &boxed_layout, env, layout_interner);
|
||||||
|
|
||||||
// this function returns void
|
// this function returns void
|
||||||
builder.build_return(None);
|
builder.build_return(None);
|
||||||
|
@ -1014,6 +1090,7 @@ enum CallMode<'ctx> {
|
||||||
|
|
||||||
fn build_rec_union<'a, 'ctx, 'env>(
|
fn build_rec_union<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
when_recursive: &WhenRecursive<'a>,
|
when_recursive: &WhenRecursive<'a>,
|
||||||
|
@ -1036,11 +1113,12 @@ fn build_rec_union<'a, 'ctx, 'env>(
|
||||||
let block = env.builder.get_insert_block().expect("to be in a function");
|
let block = env.builder.get_insert_block().expect("to be in a function");
|
||||||
let di_location = env.builder.get_current_debug_location().unwrap();
|
let di_location = env.builder.get_current_debug_location().unwrap();
|
||||||
|
|
||||||
let basic_type = basic_type_from_layout(env, &layout);
|
let basic_type = basic_type_from_layout(env, layout_interner, &layout);
|
||||||
let function_value = build_header(env, basic_type, mode, &fn_name);
|
let function_value = build_header(env, basic_type, mode, &fn_name);
|
||||||
|
|
||||||
build_rec_union_help(
|
build_rec_union_help(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
mode,
|
mode,
|
||||||
when_recursive,
|
when_recursive,
|
||||||
|
@ -1062,6 +1140,7 @@ fn build_rec_union<'a, 'ctx, 'env>(
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn build_rec_union_help<'a, 'ctx, 'env>(
|
fn build_rec_union_help<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
when_recursive: &WhenRecursive<'a>,
|
when_recursive: &WhenRecursive<'a>,
|
||||||
|
@ -1091,7 +1170,7 @@ fn build_rec_union_help<'a, 'ctx, 'env>(
|
||||||
let parent = fn_val;
|
let parent = fn_val;
|
||||||
|
|
||||||
debug_assert!(arg_val.is_pointer_value());
|
debug_assert!(arg_val.is_pointer_value());
|
||||||
let current_tag_id = get_tag_id(env, fn_val, &union_layout, arg_val);
|
let current_tag_id = get_tag_id(env, layout_interner, fn_val, &union_layout, arg_val);
|
||||||
let value_ptr = if union_layout.stores_tag_id_in_pointer(env.target_info) {
|
let value_ptr = if union_layout.stores_tag_id_in_pointer(env.target_info) {
|
||||||
tag_pointer_clear_tag_id(env, arg_val.into_pointer_value())
|
tag_pointer_clear_tag_id(env, arg_val.into_pointer_value())
|
||||||
} else {
|
} else {
|
||||||
|
@ -1128,7 +1207,7 @@ fn build_rec_union_help<'a, 'ctx, 'env>(
|
||||||
match mode {
|
match mode {
|
||||||
Mode::Inc => {
|
Mode::Inc => {
|
||||||
// inc is cheap; we never recurse
|
// inc is cheap; we never recurse
|
||||||
refcount_ptr.modify(call_mode, &layout, env);
|
refcount_ptr.modify(call_mode, &layout, env, layout_interner);
|
||||||
env.builder.build_return(None);
|
env.builder.build_return(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1145,7 +1224,7 @@ fn build_rec_union_help<'a, 'ctx, 'env>(
|
||||||
{
|
{
|
||||||
env.builder.position_at_end(no_recurse_block);
|
env.builder.position_at_end(no_recurse_block);
|
||||||
|
|
||||||
refcount_ptr.modify(call_mode, &layout, env);
|
refcount_ptr.modify(call_mode, &layout, env, layout_interner);
|
||||||
env.builder.build_return(None);
|
env.builder.build_return(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1154,6 +1233,7 @@ fn build_rec_union_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
build_rec_union_recursive_decrement(
|
build_rec_union_recursive_decrement(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
when_recursive,
|
when_recursive,
|
||||||
parent,
|
parent,
|
||||||
|
@ -1185,6 +1265,7 @@ fn fields_need_no_refcounting(interner: &STLayoutInterner, field_layouts: &[Layo
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>(
|
fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
when_recursive: &WhenRecursive<'a>,
|
when_recursive: &WhenRecursive<'a>,
|
||||||
parent: FunctionValue<'ctx>,
|
parent: FunctionValue<'ctx>,
|
||||||
|
@ -1205,11 +1286,11 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>(
|
||||||
let mut cases = Vec::with_capacity_in(tags.len(), env.arena);
|
let mut cases = Vec::with_capacity_in(tags.len(), env.arena);
|
||||||
|
|
||||||
let tag_id_int_type =
|
let tag_id_int_type =
|
||||||
basic_type_from_layout(env, &union_layout.tag_id_layout()).into_int_type();
|
basic_type_from_layout(env, layout_interner, &union_layout.tag_id_layout()).into_int_type();
|
||||||
|
|
||||||
for (tag_id, field_layouts) in tags.iter().enumerate() {
|
for (tag_id, field_layouts) in tags.iter().enumerate() {
|
||||||
// if none of the fields are or contain anything refcounted, just move on
|
// if none of the fields are or contain anything refcounted, just move on
|
||||||
if fields_need_no_refcounting(env.layout_interner, field_layouts) {
|
if fields_need_no_refcounting(layout_interner, field_layouts) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1217,8 +1298,11 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
env.builder.position_at_end(block);
|
env.builder.position_at_end(block);
|
||||||
|
|
||||||
let wrapper_type =
|
let wrapper_type = basic_type_from_layout(
|
||||||
basic_type_from_layout(env, &Layout::struct_no_name_order(field_layouts));
|
env,
|
||||||
|
layout_interner,
|
||||||
|
&Layout::struct_no_name_order(field_layouts),
|
||||||
|
);
|
||||||
|
|
||||||
// cast the opaque pointer to a pointer of the correct shape
|
// cast the opaque pointer to a pointer of the correct shape
|
||||||
let struct_ptr = env.builder.build_pointer_cast(
|
let struct_ptr = env.builder.build_pointer_cast(
|
||||||
|
@ -1254,11 +1338,12 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>(
|
||||||
debug_assert!(ptr_as_i64_ptr.is_pointer_value());
|
debug_assert!(ptr_as_i64_ptr.is_pointer_value());
|
||||||
|
|
||||||
// therefore we must cast it to our desired type
|
// therefore we must cast it to our desired type
|
||||||
let union_type = basic_type_from_layout(env, &Layout::Union(union_layout));
|
let union_type =
|
||||||
|
basic_type_from_layout(env, layout_interner, &Layout::Union(union_layout));
|
||||||
let recursive_field_ptr = cast_basic_basic(env.builder, ptr_as_i64_ptr, union_type);
|
let recursive_field_ptr = cast_basic_basic(env.builder, ptr_as_i64_ptr, union_type);
|
||||||
|
|
||||||
deferred_rec.push(recursive_field_ptr);
|
deferred_rec.push(recursive_field_ptr);
|
||||||
} else if field_layout.contains_refcounted(env.layout_interner) {
|
} else if field_layout.contains_refcounted(layout_interner) {
|
||||||
let elem_pointer = env
|
let elem_pointer = env
|
||||||
.builder
|
.builder
|
||||||
.new_build_struct_gep(
|
.new_build_struct_gep(
|
||||||
|
@ -1269,8 +1354,13 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>(
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let field =
|
let field = load_roc_value(
|
||||||
load_roc_value(env, *field_layout, elem_pointer, "decrement_struct_field");
|
env,
|
||||||
|
layout_interner,
|
||||||
|
*field_layout,
|
||||||
|
elem_pointer,
|
||||||
|
"decrement_struct_field",
|
||||||
|
);
|
||||||
|
|
||||||
deferred_nonrec.push((field, field_layout));
|
deferred_nonrec.push((field, field_layout));
|
||||||
}
|
}
|
||||||
|
@ -1286,13 +1376,19 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>(
|
||||||
match decrement_or_reuse {
|
match decrement_or_reuse {
|
||||||
DecOrReuse::Reuse => {}
|
DecOrReuse::Reuse => {}
|
||||||
DecOrReuse::Dec => {
|
DecOrReuse::Dec => {
|
||||||
refcount_ptr.modify(call_mode, &Layout::Union(union_layout), env);
|
refcount_ptr.modify(
|
||||||
|
call_mode,
|
||||||
|
&Layout::Union(union_layout),
|
||||||
|
env,
|
||||||
|
layout_interner,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (field, field_layout) in deferred_nonrec {
|
for (field, field_layout) in deferred_nonrec {
|
||||||
modify_refcount_layout_help(
|
modify_refcount_layout_help(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
mode.to_call_mode(decrement_fn),
|
mode.to_call_mode(decrement_fn),
|
||||||
when_recursive,
|
when_recursive,
|
||||||
|
@ -1338,7 +1434,12 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
// increment/decrement the cons-cell itself
|
// increment/decrement the cons-cell itself
|
||||||
if let DecOrReuse::Dec = decrement_or_reuse {
|
if let DecOrReuse::Dec = decrement_or_reuse {
|
||||||
refcount_ptr.modify(call_mode, &Layout::Union(union_layout), env);
|
refcount_ptr.modify(
|
||||||
|
call_mode,
|
||||||
|
&Layout::Union(union_layout),
|
||||||
|
env,
|
||||||
|
layout_interner,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1366,6 +1467,7 @@ fn union_layout_tags<'a>(
|
||||||
|
|
||||||
pub fn build_reset<'a, 'ctx, 'env>(
|
pub fn build_reset<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
union_layout: UnionLayout<'a>,
|
union_layout: UnionLayout<'a>,
|
||||||
) -> FunctionValue<'ctx> {
|
) -> FunctionValue<'ctx> {
|
||||||
|
@ -1376,7 +1478,14 @@ pub fn build_reset<'a, 'ctx, 'env>(
|
||||||
let fn_name = format!("{}_reset", fn_name);
|
let fn_name = format!("{}_reset", fn_name);
|
||||||
|
|
||||||
let when_recursive = WhenRecursive::Loop(union_layout);
|
let when_recursive = WhenRecursive::Loop(union_layout);
|
||||||
let dec_function = build_rec_union(env, layout_ids, Mode::Dec, &when_recursive, union_layout);
|
let dec_function = build_rec_union(
|
||||||
|
env,
|
||||||
|
layout_interner,
|
||||||
|
layout_ids,
|
||||||
|
Mode::Dec,
|
||||||
|
&when_recursive,
|
||||||
|
union_layout,
|
||||||
|
);
|
||||||
|
|
||||||
let function = match env.module.get_function(fn_name.as_str()) {
|
let function = match env.module.get_function(fn_name.as_str()) {
|
||||||
Some(function_value) => function_value,
|
Some(function_value) => function_value,
|
||||||
|
@ -1384,11 +1493,13 @@ pub fn build_reset<'a, 'ctx, 'env>(
|
||||||
let block = env.builder.get_insert_block().expect("to be in a function");
|
let block = env.builder.get_insert_block().expect("to be in a function");
|
||||||
let di_location = env.builder.get_current_debug_location().unwrap();
|
let di_location = env.builder.get_current_debug_location().unwrap();
|
||||||
|
|
||||||
let basic_type = basic_type_from_layout(env, &Layout::Union(union_layout));
|
let basic_type =
|
||||||
|
basic_type_from_layout(env, layout_interner, &Layout::Union(union_layout));
|
||||||
let function_value = build_header(env, basic_type, mode, &fn_name);
|
let function_value = build_header(env, basic_type, mode, &fn_name);
|
||||||
|
|
||||||
build_reuse_rec_union_help(
|
build_reuse_rec_union_help(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
&when_recursive,
|
&when_recursive,
|
||||||
union_layout,
|
union_layout,
|
||||||
|
@ -1410,6 +1521,7 @@ pub fn build_reset<'a, 'ctx, 'env>(
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn build_reuse_rec_union_help<'a, 'ctx, 'env>(
|
fn build_reuse_rec_union_help<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
when_recursive: &WhenRecursive<'a>,
|
when_recursive: &WhenRecursive<'a>,
|
||||||
union_layout: UnionLayout<'a>,
|
union_layout: UnionLayout<'a>,
|
||||||
|
@ -1440,7 +1552,7 @@ fn build_reuse_rec_union_help<'a, 'ctx, 'env>(
|
||||||
let parent = reset_function;
|
let parent = reset_function;
|
||||||
|
|
||||||
debug_assert!(arg_val.is_pointer_value());
|
debug_assert!(arg_val.is_pointer_value());
|
||||||
let current_tag_id = get_tag_id(env, reset_function, &union_layout, arg_val);
|
let current_tag_id = get_tag_id(env, layout_interner, reset_function, &union_layout, arg_val);
|
||||||
let value_ptr = tag_pointer_clear_tag_id(env, arg_val.into_pointer_value());
|
let value_ptr = tag_pointer_clear_tag_id(env, arg_val.into_pointer_value());
|
||||||
|
|
||||||
// to increment/decrement the cons-cell itself
|
// to increment/decrement the cons-cell itself
|
||||||
|
@ -1478,7 +1590,7 @@ fn build_reuse_rec_union_help<'a, 'ctx, 'env>(
|
||||||
{
|
{
|
||||||
env.builder.position_at_end(no_recurse_block);
|
env.builder.position_at_end(no_recurse_block);
|
||||||
|
|
||||||
refcount_ptr.modify(call_mode, &layout, env);
|
refcount_ptr.modify(call_mode, &layout, env, layout_interner);
|
||||||
env.builder.build_return(None);
|
env.builder.build_return(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1487,6 +1599,7 @@ fn build_reuse_rec_union_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
build_rec_union_recursive_decrement(
|
build_rec_union_recursive_decrement(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
when_recursive,
|
when_recursive,
|
||||||
parent,
|
parent,
|
||||||
|
@ -1524,6 +1637,7 @@ fn function_name_from_mode<'a>(
|
||||||
|
|
||||||
fn modify_refcount_nonrecursive<'a, 'ctx, 'env>(
|
fn modify_refcount_nonrecursive<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
when_recursive: &WhenRecursive<'a>,
|
when_recursive: &WhenRecursive<'a>,
|
||||||
|
@ -1547,11 +1661,12 @@ fn modify_refcount_nonrecursive<'a, 'ctx, 'env>(
|
||||||
let function = match env.module.get_function(fn_name.as_str()) {
|
let function = match env.module.get_function(fn_name.as_str()) {
|
||||||
Some(function_value) => function_value,
|
Some(function_value) => function_value,
|
||||||
None => {
|
None => {
|
||||||
let basic_type = argument_type_from_union_layout(env, &union_layout);
|
let basic_type = argument_type_from_union_layout(env, layout_interner, &union_layout);
|
||||||
let function_value = build_header(env, basic_type, mode, &fn_name);
|
let function_value = build_header(env, basic_type, mode, &fn_name);
|
||||||
|
|
||||||
modify_refcount_nonrecursive_help(
|
modify_refcount_nonrecursive_help(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
mode,
|
mode,
|
||||||
when_recursive,
|
when_recursive,
|
||||||
|
@ -1572,6 +1687,7 @@ fn modify_refcount_nonrecursive<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
fn modify_refcount_nonrecursive_help<'a, 'ctx, 'env>(
|
fn modify_refcount_nonrecursive_help<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
|
layout_interner: &mut STLayoutInterner<'a>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
when_recursive: &WhenRecursive<'a>,
|
when_recursive: &WhenRecursive<'a>,
|
||||||
|
@ -1602,7 +1718,8 @@ fn modify_refcount_nonrecursive_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let union_layout = UnionLayout::NonRecursive(tags);
|
let union_layout = UnionLayout::NonRecursive(tags);
|
||||||
let layout = Layout::Union(union_layout);
|
let layout = Layout::Union(union_layout);
|
||||||
let union_struct_type = basic_type_from_layout(env, &layout).into_struct_type();
|
let union_struct_type =
|
||||||
|
basic_type_from_layout(env, layout_interner, &layout).into_struct_type();
|
||||||
|
|
||||||
// read the tag_id
|
// read the tag_id
|
||||||
let tag_id_ptr = env
|
let tag_id_ptr = env
|
||||||
|
@ -1618,7 +1735,7 @@ fn modify_refcount_nonrecursive_help<'a, 'ctx, 'env>(
|
||||||
let tag_id = env
|
let tag_id = env
|
||||||
.builder
|
.builder
|
||||||
.new_build_load(
|
.new_build_load(
|
||||||
basic_type_from_layout(env, &union_layout.tag_id_layout()),
|
basic_type_from_layout(env, layout_interner, &union_layout.tag_id_layout()),
|
||||||
tag_id_ptr,
|
tag_id_ptr,
|
||||||
"load_tag_id",
|
"load_tag_id",
|
||||||
)
|
)
|
||||||
|
@ -1639,7 +1756,7 @@ fn modify_refcount_nonrecursive_help<'a, 'ctx, 'env>(
|
||||||
// if none of the fields are or contain anything refcounted, just move on
|
// if none of the fields are or contain anything refcounted, just move on
|
||||||
if !field_layouts
|
if !field_layouts
|
||||||
.iter()
|
.iter()
|
||||||
.any(|x| x.is_refcounted() || x.contains_refcounted(env.layout_interner))
|
.any(|x| x.is_refcounted() || x.contains_refcounted(layout_interner))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1647,8 +1764,11 @@ fn modify_refcount_nonrecursive_help<'a, 'ctx, 'env>(
|
||||||
let block = env.context.append_basic_block(parent, "tag_id_modify");
|
let block = env.context.append_basic_block(parent, "tag_id_modify");
|
||||||
env.builder.position_at_end(block);
|
env.builder.position_at_end(block);
|
||||||
|
|
||||||
let data_struct_type =
|
let data_struct_type = basic_type_from_layout(
|
||||||
basic_type_from_layout(env, &Layout::struct_no_name_order(field_layouts));
|
env,
|
||||||
|
layout_interner,
|
||||||
|
&Layout::struct_no_name_order(field_layouts),
|
||||||
|
);
|
||||||
|
|
||||||
debug_assert!(data_struct_type.is_struct_type());
|
debug_assert!(data_struct_type.is_struct_type());
|
||||||
let data_struct_type = data_struct_type.into_struct_type();
|
let data_struct_type = data_struct_type.into_struct_type();
|
||||||
|
@ -1698,20 +1818,24 @@ fn modify_refcount_nonrecursive_help<'a, 'ctx, 'env>(
|
||||||
debug_assert!(field_value.is_pointer_value());
|
debug_assert!(field_value.is_pointer_value());
|
||||||
|
|
||||||
// therefore we must cast it to our desired type
|
// therefore we must cast it to our desired type
|
||||||
let union_type =
|
let union_type = basic_type_from_layout(
|
||||||
basic_type_from_layout(env, &Layout::Union(*recursive_union_layout));
|
env,
|
||||||
|
layout_interner,
|
||||||
|
&Layout::Union(*recursive_union_layout),
|
||||||
|
);
|
||||||
let recursive_ptr_field_value =
|
let recursive_ptr_field_value =
|
||||||
cast_basic_basic(env.builder, field_value, union_type);
|
cast_basic_basic(env.builder, field_value, union_type);
|
||||||
|
|
||||||
modify_refcount_layout_help(
|
modify_refcount_layout_help(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
mode.to_call_mode(fn_val),
|
mode.to_call_mode(fn_val),
|
||||||
when_recursive,
|
when_recursive,
|
||||||
recursive_ptr_field_value,
|
recursive_ptr_field_value,
|
||||||
&Layout::RecursivePointer,
|
&Layout::RecursivePointer,
|
||||||
)
|
)
|
||||||
} else if field_layout.contains_refcounted(env.layout_interner) {
|
} else if field_layout.contains_refcounted(layout_interner) {
|
||||||
let field_ptr = env
|
let field_ptr = env
|
||||||
.builder
|
.builder
|
||||||
.new_build_struct_gep(
|
.new_build_struct_gep(
|
||||||
|
@ -1723,11 +1847,11 @@ fn modify_refcount_nonrecursive_help<'a, 'ctx, 'env>(
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let field_value =
|
let field_value =
|
||||||
if field_layout.is_passed_by_reference(env.layout_interner, env.target_info) {
|
if field_layout.is_passed_by_reference(layout_interner, env.target_info) {
|
||||||
field_ptr.into()
|
field_ptr.into()
|
||||||
} else {
|
} else {
|
||||||
env.builder.new_build_load(
|
env.builder.new_build_load(
|
||||||
basic_type_from_layout(env, field_layout),
|
basic_type_from_layout(env, layout_interner, field_layout),
|
||||||
field_ptr,
|
field_ptr,
|
||||||
"field_value",
|
"field_value",
|
||||||
)
|
)
|
||||||
|
@ -1735,6 +1859,7 @@ fn modify_refcount_nonrecursive_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
modify_refcount_layout_help(
|
modify_refcount_layout_help(
|
||||||
env,
|
env,
|
||||||
|
layout_interner,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
mode.to_call_mode(fn_val),
|
mode.to_call_mode(fn_val),
|
||||||
when_recursive,
|
when_recursive,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue