mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 22:34:45 +00:00
Merge pull request #1916 from rtfeldman/tag-union-imitate-rust
Tag union imitate rust
This commit is contained in:
commit
1c6fab7043
12 changed files with 799 additions and 325 deletions
|
@ -247,7 +247,7 @@ pub fn build_file<'a>(
|
||||||
link(
|
link(
|
||||||
target,
|
target,
|
||||||
binary_path.clone(),
|
binary_path.clone(),
|
||||||
&inputs,
|
&inputs,
|
||||||
link_type
|
link_type
|
||||||
)
|
)
|
||||||
.map_err(|_| {
|
.map_err(|_| {
|
||||||
|
|
|
@ -218,8 +218,8 @@ pub fn gen_and_eval<'a>(
|
||||||
// Verify the module
|
// Verify the module
|
||||||
if let Err(errors) = env.module.verify() {
|
if let Err(errors) = env.module.verify() {
|
||||||
panic!(
|
panic!(
|
||||||
"Errors defining module: {}\n\nUncomment things nearby to see more details.",
|
"Errors defining module:\n{}\n\nUncomment things nearby to see more details.",
|
||||||
errors
|
errors.to_string()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -128,20 +128,19 @@ fn build_has_tag_id_help<'a, 'ctx, 'env>(
|
||||||
[tag_id, tag_value_ptr] => {
|
[tag_id, tag_value_ptr] => {
|
||||||
let tag_type = basic_type_from_layout(env, &Layout::Union(union_layout));
|
let tag_type = basic_type_from_layout(env, &Layout::Union(union_layout));
|
||||||
|
|
||||||
let argument_cast = env
|
let tag_value = env.builder.build_pointer_cast(
|
||||||
.builder
|
tag_value_ptr.into_pointer_value(),
|
||||||
.build_bitcast(
|
tag_type.ptr_type(AddressSpace::Generic),
|
||||||
*tag_value_ptr,
|
"load_opaque_get_tag_id",
|
||||||
tag_type.ptr_type(AddressSpace::Generic),
|
);
|
||||||
"load_opaque",
|
|
||||||
)
|
|
||||||
.into_pointer_value();
|
|
||||||
|
|
||||||
let tag_value = env.builder.build_load(argument_cast, "get_value");
|
|
||||||
|
|
||||||
let actual_tag_id = {
|
let actual_tag_id = {
|
||||||
let tag_id_i64 =
|
let tag_id_i64 = crate::llvm::build::get_tag_id(
|
||||||
crate::llvm::build::get_tag_id(env, function_value, &union_layout, tag_value);
|
env,
|
||||||
|
function_value,
|
||||||
|
&union_layout,
|
||||||
|
tag_value.into(),
|
||||||
|
);
|
||||||
|
|
||||||
env.builder
|
env.builder
|
||||||
.build_int_cast(tag_id_i64, env.context.i16_type(), "to_i16")
|
.build_int_cast(tag_id_i64, env.context.i16_type(), "to_i16")
|
||||||
|
@ -155,18 +154,11 @@ fn build_has_tag_id_help<'a, 'ctx, 'env>(
|
||||||
);
|
);
|
||||||
|
|
||||||
let tag_data_ptr = {
|
let tag_data_ptr = {
|
||||||
let data_index = env
|
let ptr = env
|
||||||
.context
|
.builder
|
||||||
.i64_type()
|
.build_struct_gep(tag_value, TAG_DATA_INDEX, "get_data_ptr")
|
||||||
.const_int(TAG_DATA_INDEX as u64, false);
|
.unwrap();
|
||||||
|
|
||||||
let ptr = unsafe {
|
|
||||||
env.builder.build_gep(
|
|
||||||
tag_value_ptr.into_pointer_value(),
|
|
||||||
&[data_index],
|
|
||||||
"get_data_ptr",
|
|
||||||
)
|
|
||||||
};
|
|
||||||
env.builder.build_bitcast(ptr, i8_ptr_type, "to_opaque")
|
env.builder.build_bitcast(ptr, i8_ptr_type, "to_opaque")
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -191,6 +183,7 @@ pub fn build_transform_caller<'a, 'ctx, 'env>(
|
||||||
function: FunctionValue<'ctx>,
|
function: FunctionValue<'ctx>,
|
||||||
closure_data_layout: LambdaSet<'a>,
|
closure_data_layout: LambdaSet<'a>,
|
||||||
argument_layouts: &[Layout<'a>],
|
argument_layouts: &[Layout<'a>],
|
||||||
|
result_layout: Layout<'a>,
|
||||||
) -> FunctionValue<'ctx> {
|
) -> FunctionValue<'ctx> {
|
||||||
let fn_name: &str = &format!(
|
let fn_name: &str = &format!(
|
||||||
"{}_zig_function_caller",
|
"{}_zig_function_caller",
|
||||||
|
@ -204,6 +197,7 @@ pub fn build_transform_caller<'a, 'ctx, 'env>(
|
||||||
function,
|
function,
|
||||||
closure_data_layout,
|
closure_data_layout,
|
||||||
argument_layouts,
|
argument_layouts,
|
||||||
|
result_layout,
|
||||||
fn_name,
|
fn_name,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
@ -214,6 +208,7 @@ fn build_transform_caller_help<'a, 'ctx, 'env>(
|
||||||
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>],
|
||||||
|
result_layout: Layout<'a>,
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
) -> FunctionValue<'ctx> {
|
) -> FunctionValue<'ctx> {
|
||||||
debug_assert!(argument_layouts.len() <= 7);
|
debug_assert!(argument_layouts.len() <= 7);
|
||||||
|
@ -260,12 +255,22 @@ fn build_transform_caller_help<'a, 'ctx, 'env>(
|
||||||
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).ptr_type(AddressSpace::Generic);
|
||||||
|
|
||||||
let argument_cast = env
|
let argument = if layout.is_passed_by_reference() {
|
||||||
.builder
|
env.builder
|
||||||
.build_bitcast(*argument_ptr, basic_type, "load_opaque")
|
.build_pointer_cast(
|
||||||
.into_pointer_value();
|
argument_ptr.into_pointer_value(),
|
||||||
|
basic_type,
|
||||||
|
"cast_ptr_to_tag_build_transform_caller_help",
|
||||||
|
)
|
||||||
|
.into()
|
||||||
|
} else {
|
||||||
|
let argument_cast = env
|
||||||
|
.builder
|
||||||
|
.build_bitcast(*argument_ptr, basic_type, "load_opaque_1")
|
||||||
|
.into_pointer_value();
|
||||||
|
|
||||||
let argument = env.builder.build_load(argument_cast, "load_opaque");
|
env.builder.build_load(argument_cast, "load_opaque_2")
|
||||||
|
};
|
||||||
|
|
||||||
arguments_cast.push(argument);
|
arguments_cast.push(argument);
|
||||||
}
|
}
|
||||||
|
@ -288,31 +293,19 @@ fn build_transform_caller_help<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let call = {
|
let result = crate::llvm::build::call_roc_function(
|
||||||
env.builder
|
env,
|
||||||
.build_call(roc_function, arguments_cast.as_slice(), "tmp")
|
roc_function,
|
||||||
};
|
&result_layout,
|
||||||
|
arguments_cast.as_slice(),
|
||||||
call.set_call_convention(FAST_CALL_CONV);
|
);
|
||||||
|
|
||||||
let result = call
|
|
||||||
.try_as_basic_value()
|
|
||||||
.left()
|
|
||||||
.unwrap_or_else(|| panic!("LLVM error: Invalid call by pointer."));
|
|
||||||
|
|
||||||
let result_u8_ptr = function_value
|
let result_u8_ptr = function_value
|
||||||
.get_nth_param(argument_layouts.len() as u32 + 1)
|
.get_nth_param(argument_layouts.len() as u32 + 1)
|
||||||
.unwrap();
|
.unwrap()
|
||||||
let result_ptr = env
|
|
||||||
.builder
|
|
||||||
.build_bitcast(
|
|
||||||
result_u8_ptr,
|
|
||||||
result.get_type().ptr_type(AddressSpace::Generic),
|
|
||||||
"write_result",
|
|
||||||
)
|
|
||||||
.into_pointer_value();
|
.into_pointer_value();
|
||||||
|
|
||||||
env.builder.build_store(result_ptr, result);
|
crate::llvm::build::store_roc_value_opaque(env, 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);
|
||||||
|
@ -414,12 +407,18 @@ fn build_rc_wrapper<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
let value_type = basic_type_from_layout(env, layout).ptr_type(AddressSpace::Generic);
|
let value_type = basic_type_from_layout(env, layout).ptr_type(AddressSpace::Generic);
|
||||||
|
|
||||||
let value_cast = env
|
let value = if layout.is_passed_by_reference() {
|
||||||
.builder
|
env.builder
|
||||||
.build_bitcast(value_ptr, value_type, "load_opaque")
|
.build_pointer_cast(value_ptr, value_type, "cast_ptr_to_tag_build_rc_wrapper")
|
||||||
.into_pointer_value();
|
.into()
|
||||||
|
} else {
|
||||||
|
let value_cast = env
|
||||||
|
.builder
|
||||||
|
.build_bitcast(value_ptr, value_type, "load_opaque")
|
||||||
|
.into_pointer_value();
|
||||||
|
|
||||||
let value = env.builder.build_load(value_cast, "load_opaque");
|
env.builder.build_load(value_cast, "load_opaque")
|
||||||
|
};
|
||||||
|
|
||||||
match rc_operation {
|
match rc_operation {
|
||||||
Mode::Inc => {
|
Mode::Inc => {
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2,9 +2,9 @@ use crate::debug_info_init;
|
||||||
use crate::llvm::bitcode::call_bitcode_fn;
|
use crate::llvm::bitcode::call_bitcode_fn;
|
||||||
use crate::llvm::build::tag_pointer_clear_tag_id;
|
use crate::llvm::build::tag_pointer_clear_tag_id;
|
||||||
use crate::llvm::build::Env;
|
use crate::llvm::build::Env;
|
||||||
use crate::llvm::build::{cast_block_of_memory_to_tag, get_tag_id, FAST_CALL_CONV, TAG_DATA_INDEX};
|
use crate::llvm::build::{get_tag_id, FAST_CALL_CONV, TAG_DATA_INDEX};
|
||||||
use crate::llvm::build_str;
|
use crate::llvm::build_str;
|
||||||
use crate::llvm::convert::basic_type_from_layout;
|
use crate::llvm::convert::{basic_type_from_layout, basic_type_from_layout_1};
|
||||||
use bumpalo::collections::Vec;
|
use bumpalo::collections::Vec;
|
||||||
use inkwell::values::{
|
use inkwell::values::{
|
||||||
BasicValue, BasicValueEnum, FunctionValue, IntValue, PointerValue, StructValue,
|
BasicValue, BasicValueEnum, FunctionValue, IntValue, PointerValue, StructValue,
|
||||||
|
@ -339,7 +339,8 @@ fn build_hash_tag<'a, 'ctx, 'env>(
|
||||||
None => {
|
None => {
|
||||||
let seed_type = env.context.i64_type();
|
let seed_type = env.context.i64_type();
|
||||||
|
|
||||||
let arg_type = basic_type_from_layout(env, layout);
|
let arg_type = basic_type_from_layout_1(env, layout);
|
||||||
|
dbg!(layout, arg_type);
|
||||||
|
|
||||||
let function_value = crate::llvm::refcounting::build_header_help(
|
let function_value = crate::llvm::refcounting::build_header_help(
|
||||||
env,
|
env,
|
||||||
|
@ -423,14 +424,6 @@ fn hash_tag<'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 struct_layout = Layout::Struct(field_layouts);
|
|
||||||
|
|
||||||
let wrapper_type = basic_type_from_layout(env, &struct_layout);
|
|
||||||
debug_assert!(wrapper_type.is_struct_type());
|
|
||||||
|
|
||||||
let as_struct =
|
|
||||||
cast_block_of_memory_to_tag(env.builder, tag.into_struct_value(), wrapper_type);
|
|
||||||
|
|
||||||
// hash the tag id
|
// hash the tag id
|
||||||
let hash_bytes = store_and_use_as_u8_ptr(
|
let hash_bytes = store_and_use_as_u8_ptr(
|
||||||
env,
|
env,
|
||||||
|
@ -440,7 +433,6 @@ fn hash_tag<'a, 'ctx, 'env>(
|
||||||
.into(),
|
.into(),
|
||||||
&tag_id_layout,
|
&tag_id_layout,
|
||||||
);
|
);
|
||||||
|
|
||||||
let seed = hash_bitcode_fn(
|
let seed = hash_bitcode_fn(
|
||||||
env,
|
env,
|
||||||
seed,
|
seed,
|
||||||
|
@ -449,14 +441,9 @@ fn hash_tag<'a, 'ctx, 'env>(
|
||||||
);
|
);
|
||||||
|
|
||||||
// hash the tag data
|
// hash the tag data
|
||||||
let answer = build_hash_struct(
|
let tag = tag.into_pointer_value();
|
||||||
env,
|
let answer =
|
||||||
layout_ids,
|
hash_ptr_to_struct(env, layout_ids, union_layout, field_layouts, seed, tag);
|
||||||
field_layouts,
|
|
||||||
WhenRecursive::Unreachable,
|
|
||||||
seed,
|
|
||||||
as_struct,
|
|
||||||
);
|
|
||||||
|
|
||||||
merge_phi.add_incoming(&[(&answer, block)]);
|
merge_phi.add_incoming(&[(&answer, block)]);
|
||||||
env.builder.build_unconditional_branch(merge_block);
|
env.builder.build_unconditional_branch(merge_block);
|
||||||
|
@ -793,7 +780,15 @@ fn hash_list<'a, 'ctx, 'env>(
|
||||||
env.builder.build_store(result, answer);
|
env.builder.build_store(result, answer);
|
||||||
};
|
};
|
||||||
|
|
||||||
incrementing_elem_loop(env, parent, ptr, length, "current_index", loop_fn);
|
incrementing_elem_loop(
|
||||||
|
env,
|
||||||
|
parent,
|
||||||
|
*element_layout,
|
||||||
|
ptr,
|
||||||
|
length,
|
||||||
|
"current_index",
|
||||||
|
loop_fn,
|
||||||
|
);
|
||||||
|
|
||||||
env.builder.build_unconditional_branch(done_block);
|
env.builder.build_unconditional_branch(done_block);
|
||||||
|
|
||||||
|
@ -822,12 +817,12 @@ fn hash_ptr_to_struct<'a, 'ctx, 'env>(
|
||||||
) -> IntValue<'ctx> {
|
) -> IntValue<'ctx> {
|
||||||
use inkwell::types::BasicType;
|
use inkwell::types::BasicType;
|
||||||
|
|
||||||
let wrapper_type = basic_type_from_layout(env, &Layout::Union(*union_layout));
|
let wrapper_type = basic_type_from_layout_1(env, &Layout::Union(*union_layout));
|
||||||
|
|
||||||
// cast the opaque pointer to a pointer of the correct shape
|
// cast the opaque pointer to a pointer of the correct shape
|
||||||
let wrapper_ptr = env
|
let wrapper_ptr = env
|
||||||
.builder
|
.builder
|
||||||
.build_bitcast(tag, wrapper_type, "opaque_to_correct")
|
.build_bitcast(tag, wrapper_type, "hash_ptr_to_struct_opaque_to_correct")
|
||||||
.into_pointer_value();
|
.into_pointer_value();
|
||||||
|
|
||||||
let struct_ptr = env
|
let struct_ptr = env
|
||||||
|
|
|
@ -17,6 +17,8 @@ use morphic_lib::UpdateMode;
|
||||||
use roc_builtins::bitcode;
|
use roc_builtins::bitcode;
|
||||||
use roc_mono::layout::{Builtin, Layout, LayoutIds};
|
use roc_mono::layout::{Builtin, Layout, LayoutIds};
|
||||||
|
|
||||||
|
use super::build::{load_roc_value, store_roc_value};
|
||||||
|
|
||||||
pub fn pass_update_mode<'a, 'ctx, 'env>(
|
pub fn pass_update_mode<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
update_mode: UpdateMode,
|
update_mode: UpdateMode,
|
||||||
|
@ -53,9 +55,13 @@ pub fn call_bitcode_fn_returns_list<'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>,
|
||||||
element: BasicValueEnum<'ctx>,
|
element: BasicValueEnum<'ctx>,
|
||||||
|
layout: Layout<'a>,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
let element_ptr = env.builder.build_alloca(element.get_type(), "element");
|
let element_type = basic_type_from_layout(env, &layout);
|
||||||
env.builder.build_store(element_ptr, element);
|
let element_ptr = env
|
||||||
|
.builder
|
||||||
|
.build_alloca(element_type, "element_to_pass_as_opaque");
|
||||||
|
store_roc_value(env, layout, element_ptr, element);
|
||||||
|
|
||||||
env.builder.build_bitcast(
|
env.builder.build_bitcast(
|
||||||
element_ptr,
|
element_ptr,
|
||||||
|
@ -106,7 +112,7 @@ pub fn list_single<'a, 'ctx, 'env>(
|
||||||
env,
|
env,
|
||||||
&[
|
&[
|
||||||
env.alignment_intvalue(element_layout),
|
env.alignment_intvalue(element_layout),
|
||||||
pass_element_as_opaque(env, element),
|
pass_element_as_opaque(env, element, *element_layout),
|
||||||
layout_width(env, element_layout),
|
layout_width(env, element_layout),
|
||||||
],
|
],
|
||||||
bitcode::LIST_SINGLE,
|
bitcode::LIST_SINGLE,
|
||||||
|
@ -128,7 +134,7 @@ pub fn list_repeat<'a, 'ctx, 'env>(
|
||||||
&[
|
&[
|
||||||
list_len.into(),
|
list_len.into(),
|
||||||
env.alignment_intvalue(element_layout),
|
env.alignment_intvalue(element_layout),
|
||||||
pass_element_as_opaque(env, element),
|
pass_element_as_opaque(env, element, *element_layout),
|
||||||
layout_width(env, element_layout),
|
layout_width(env, element_layout),
|
||||||
inc_element_fn.as_global_value().as_pointer_value().into(),
|
inc_element_fn.as_global_value().as_pointer_value().into(),
|
||||||
],
|
],
|
||||||
|
@ -216,10 +222,11 @@ pub fn list_get_unsafe<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
// Assume the bounds have already been checked earlier
|
// Assume the bounds have already been checked earlier
|
||||||
// (e.g. by List.get or List.first, which wrap List.#getUnsafe)
|
// (e.g. by List.get or List.first, which wrap List.#getUnsafe)
|
||||||
let elem_ptr =
|
let elem_ptr = unsafe {
|
||||||
unsafe { builder.build_in_bounds_gep(array_data_ptr, &[elem_index], "elem") };
|
builder.build_in_bounds_gep(array_data_ptr, &[elem_index], "list_get_element")
|
||||||
|
};
|
||||||
|
|
||||||
let result = builder.build_load(elem_ptr, "List.get");
|
let result = load_roc_value(env, **elem_layout, elem_ptr, "list_get_load_element");
|
||||||
|
|
||||||
increment_refcount_layout(env, parent, layout_ids, 1, result, elem_layout);
|
increment_refcount_layout(env, parent, layout_ids, 1, result, elem_layout);
|
||||||
|
|
||||||
|
@ -247,7 +254,7 @@ pub fn list_append<'a, 'ctx, 'env>(
|
||||||
&[
|
&[
|
||||||
pass_list_cc(env, original_wrapper.into()),
|
pass_list_cc(env, original_wrapper.into()),
|
||||||
env.alignment_intvalue(element_layout),
|
env.alignment_intvalue(element_layout),
|
||||||
pass_element_as_opaque(env, element),
|
pass_element_as_opaque(env, element, *element_layout),
|
||||||
layout_width(env, element_layout),
|
layout_width(env, element_layout),
|
||||||
pass_update_mode(env, update_mode),
|
pass_update_mode(env, update_mode),
|
||||||
],
|
],
|
||||||
|
@ -267,7 +274,7 @@ pub fn list_prepend<'a, 'ctx, 'env>(
|
||||||
&[
|
&[
|
||||||
pass_list_cc(env, original_wrapper.into()),
|
pass_list_cc(env, original_wrapper.into()),
|
||||||
env.alignment_intvalue(element_layout),
|
env.alignment_intvalue(element_layout),
|
||||||
pass_element_as_opaque(env, element),
|
pass_element_as_opaque(env, element, *element_layout),
|
||||||
layout_width(env, element_layout),
|
layout_width(env, element_layout),
|
||||||
],
|
],
|
||||||
bitcode::LIST_PREPEND,
|
bitcode::LIST_PREPEND,
|
||||||
|
@ -389,7 +396,7 @@ pub fn list_set<'a, 'ctx, 'env>(
|
||||||
&[
|
&[
|
||||||
bytes.into(),
|
bytes.into(),
|
||||||
index.into(),
|
index.into(),
|
||||||
pass_element_as_opaque(env, element),
|
pass_element_as_opaque(env, element, *element_layout),
|
||||||
layout_width(env, element_layout),
|
layout_width(env, element_layout),
|
||||||
dec_element_fn.as_global_value().as_pointer_value().into(),
|
dec_element_fn.as_global_value().as_pointer_value().into(),
|
||||||
],
|
],
|
||||||
|
@ -402,7 +409,7 @@ pub fn list_set<'a, 'ctx, 'env>(
|
||||||
length.into(),
|
length.into(),
|
||||||
env.alignment_intvalue(element_layout),
|
env.alignment_intvalue(element_layout),
|
||||||
index.into(),
|
index.into(),
|
||||||
pass_element_as_opaque(env, element),
|
pass_element_as_opaque(env, element, *element_layout),
|
||||||
layout_width(env, element_layout),
|
layout_width(env, element_layout),
|
||||||
dec_element_fn.as_global_value().as_pointer_value().into(),
|
dec_element_fn.as_global_value().as_pointer_value().into(),
|
||||||
],
|
],
|
||||||
|
@ -578,7 +585,7 @@ pub fn list_contains<'a, 'ctx, 'env>(
|
||||||
env,
|
env,
|
||||||
&[
|
&[
|
||||||
pass_list_cc(env, list),
|
pass_list_cc(env, list),
|
||||||
pass_element_as_opaque(env, element),
|
pass_element_as_opaque(env, element, *element_layout),
|
||||||
layout_width(env, element_layout),
|
layout_width(env, element_layout),
|
||||||
eq_fn,
|
eq_fn,
|
||||||
],
|
],
|
||||||
|
@ -1137,6 +1144,7 @@ where
|
||||||
pub fn incrementing_elem_loop<'a, 'ctx, 'env, LoopFn>(
|
pub fn incrementing_elem_loop<'a, 'ctx, 'env, LoopFn>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
parent: FunctionValue<'ctx>,
|
parent: FunctionValue<'ctx>,
|
||||||
|
element_layout: Layout<'a>,
|
||||||
ptr: PointerValue<'ctx>,
|
ptr: PointerValue<'ctx>,
|
||||||
len: IntValue<'ctx>,
|
len: IntValue<'ctx>,
|
||||||
index_name: &str,
|
index_name: &str,
|
||||||
|
@ -1149,9 +1157,14 @@ where
|
||||||
|
|
||||||
incrementing_index_loop(env, parent, len, index_name, |index| {
|
incrementing_index_loop(env, parent, len, index_name, |index| {
|
||||||
// The pointer to the element in the list
|
// The pointer to the element in the list
|
||||||
let elem_ptr = unsafe { builder.build_in_bounds_gep(ptr, &[index], "load_index") };
|
let element_ptr = unsafe { builder.build_in_bounds_gep(ptr, &[index], "load_index") };
|
||||||
|
|
||||||
let elem = builder.build_load(elem_ptr, "get_elem");
|
let elem = load_roc_value(
|
||||||
|
env,
|
||||||
|
element_layout,
|
||||||
|
element_ptr,
|
||||||
|
"incrementing_element_loop_load",
|
||||||
|
);
|
||||||
|
|
||||||
loop_fn(index, elem);
|
loop_fn(index, elem);
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
use crate::llvm::bitcode::call_bitcode_fn;
|
use crate::llvm::bitcode::call_bitcode_fn;
|
||||||
use crate::llvm::build::{
|
use crate::llvm::build::{get_tag_id, tag_pointer_clear_tag_id, Env, FAST_CALL_CONV};
|
||||||
cast_block_of_memory_to_tag, get_tag_id, tag_pointer_clear_tag_id, Env, FAST_CALL_CONV,
|
|
||||||
};
|
|
||||||
use crate::llvm::build_list::{list_len, load_list_ptr};
|
use crate::llvm::build_list::{list_len, load_list_ptr};
|
||||||
use crate::llvm::build_str::str_equal;
|
use crate::llvm::build_str::str_equal;
|
||||||
use crate::llvm::convert::basic_type_from_layout;
|
use crate::llvm::convert::{basic_type_from_layout, basic_type_from_layout_1};
|
||||||
use bumpalo::collections::Vec;
|
use bumpalo::collections::Vec;
|
||||||
use inkwell::types::BasicType;
|
use inkwell::types::BasicType;
|
||||||
use inkwell::values::{
|
use inkwell::values::{
|
||||||
|
@ -751,7 +749,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 = basic_type_from_layout(env, tag_layout);
|
let arg_type = basic_type_from_layout_1(env, tag_layout);
|
||||||
|
|
||||||
let function_value = crate::llvm::refcounting::build_header_help(
|
let function_value = crate::llvm::refcounting::build_header_help(
|
||||||
env,
|
env,
|
||||||
|
@ -844,9 +842,29 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
match union_layout {
|
match union_layout {
|
||||||
NonRecursive(tags) => {
|
NonRecursive(tags) => {
|
||||||
|
let ptr_equal = env.builder.build_int_compare(
|
||||||
|
IntPredicate::EQ,
|
||||||
|
env.builder
|
||||||
|
.build_ptr_to_int(tag1.into_pointer_value(), env.ptr_int(), "pti"),
|
||||||
|
env.builder
|
||||||
|
.build_ptr_to_int(tag2.into_pointer_value(), env.ptr_int(), "pti"),
|
||||||
|
"compare_pointers",
|
||||||
|
);
|
||||||
|
|
||||||
|
let compare_tag_ids = ctx.append_basic_block(parent, "compare_tag_ids");
|
||||||
|
|
||||||
|
env.builder
|
||||||
|
.build_conditional_branch(ptr_equal, return_true, 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, parent, union_layout, tag1);
|
||||||
let id2 = get_tag_id(env, parent, union_layout, tag2);
|
let id2 = get_tag_id(env, parent, union_layout, tag2);
|
||||||
|
|
||||||
|
// clear the tag_id so we get a pointer to the actual data
|
||||||
|
let tag1 = tag1.into_pointer_value();
|
||||||
|
let tag2 = tag2.into_pointer_value();
|
||||||
|
|
||||||
let compare_tag_fields = ctx.append_basic_block(parent, "compare_tag_fields");
|
let compare_tag_fields = ctx.append_basic_block(parent, "compare_tag_fields");
|
||||||
|
|
||||||
let same_tag =
|
let same_tag =
|
||||||
|
@ -866,30 +884,14 @@ fn build_tag_eq_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);
|
||||||
|
|
||||||
// TODO drop tag id?
|
let answer = eq_ptr_to_struct(
|
||||||
let struct_layout = Layout::Struct(field_layouts);
|
|
||||||
|
|
||||||
let wrapper_type = basic_type_from_layout(env, &struct_layout);
|
|
||||||
debug_assert!(wrapper_type.is_struct_type());
|
|
||||||
|
|
||||||
let struct1 = cast_block_of_memory_to_tag(
|
|
||||||
env.builder,
|
|
||||||
tag1.into_struct_value(),
|
|
||||||
wrapper_type,
|
|
||||||
);
|
|
||||||
let struct2 = cast_block_of_memory_to_tag(
|
|
||||||
env.builder,
|
|
||||||
tag2.into_struct_value(),
|
|
||||||
wrapper_type,
|
|
||||||
);
|
|
||||||
|
|
||||||
let answer = build_struct_eq(
|
|
||||||
env,
|
env,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
|
union_layout,
|
||||||
|
Some(when_recursive.clone()),
|
||||||
field_layouts,
|
field_layouts,
|
||||||
when_recursive.clone(),
|
tag1,
|
||||||
struct1,
|
tag2,
|
||||||
struct2,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
env.builder.build_return(Some(&answer));
|
env.builder.build_return(Some(&answer));
|
||||||
|
@ -946,8 +948,15 @@ fn build_tag_eq_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 answer =
|
let answer = eq_ptr_to_struct(
|
||||||
eq_ptr_to_struct(env, layout_ids, union_layout, field_layouts, tag1, tag2);
|
env,
|
||||||
|
layout_ids,
|
||||||
|
union_layout,
|
||||||
|
None,
|
||||||
|
field_layouts,
|
||||||
|
tag1,
|
||||||
|
tag2,
|
||||||
|
);
|
||||||
|
|
||||||
env.builder.build_return(Some(&answer));
|
env.builder.build_return(Some(&answer));
|
||||||
|
|
||||||
|
@ -1003,6 +1012,7 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
|
||||||
env,
|
env,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
union_layout,
|
union_layout,
|
||||||
|
None,
|
||||||
other_fields,
|
other_fields,
|
||||||
tag1.into_pointer_value(),
|
tag1.into_pointer_value(),
|
||||||
tag2.into_pointer_value(),
|
tag2.into_pointer_value(),
|
||||||
|
@ -1093,8 +1103,15 @@ fn build_tag_eq_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 answer =
|
let answer = eq_ptr_to_struct(
|
||||||
eq_ptr_to_struct(env, layout_ids, union_layout, field_layouts, tag1, tag2);
|
env,
|
||||||
|
layout_ids,
|
||||||
|
union_layout,
|
||||||
|
None,
|
||||||
|
field_layouts,
|
||||||
|
tag1,
|
||||||
|
tag2,
|
||||||
|
);
|
||||||
|
|
||||||
env.builder.build_return(Some(&answer));
|
env.builder.build_return(Some(&answer));
|
||||||
|
|
||||||
|
@ -1128,6 +1145,7 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
|
||||||
env,
|
env,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
union_layout,
|
union_layout,
|
||||||
|
None,
|
||||||
field_layouts,
|
field_layouts,
|
||||||
tag1.into_pointer_value(),
|
tag1.into_pointer_value(),
|
||||||
tag2.into_pointer_value(),
|
tag2.into_pointer_value(),
|
||||||
|
@ -1142,6 +1160,7 @@ fn eq_ptr_to_struct<'a, 'ctx, 'env>(
|
||||||
env: &Env<'a, 'ctx, 'env>,
|
env: &Env<'a, 'ctx, 'env>,
|
||||||
layout_ids: &mut LayoutIds<'a>,
|
layout_ids: &mut LayoutIds<'a>,
|
||||||
union_layout: &UnionLayout<'a>,
|
union_layout: &UnionLayout<'a>,
|
||||||
|
opt_when_recursive: Option<WhenRecursive<'a>>,
|
||||||
field_layouts: &'a [Layout<'a>],
|
field_layouts: &'a [Layout<'a>],
|
||||||
tag1: PointerValue<'ctx>,
|
tag1: PointerValue<'ctx>,
|
||||||
tag2: PointerValue<'ctx>,
|
tag2: PointerValue<'ctx>,
|
||||||
|
@ -1184,7 +1203,7 @@ fn eq_ptr_to_struct<'a, 'ctx, 'env>(
|
||||||
env,
|
env,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
field_layouts,
|
field_layouts,
|
||||||
WhenRecursive::Loop(*union_layout),
|
opt_when_recursive.unwrap_or(WhenRecursive::Loop(*union_layout)),
|
||||||
struct1,
|
struct1,
|
||||||
struct2,
|
struct2,
|
||||||
)
|
)
|
||||||
|
|
|
@ -76,6 +76,66 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn basic_type_from_layout_1<'a, 'ctx, 'env>(
|
||||||
|
env: &crate::llvm::build::Env<'a, 'ctx, 'env>,
|
||||||
|
layout: &Layout<'_>,
|
||||||
|
) -> BasicTypeEnum<'ctx> {
|
||||||
|
use Layout::*;
|
||||||
|
|
||||||
|
match layout {
|
||||||
|
Struct(sorted_fields) => basic_type_from_record(env, sorted_fields),
|
||||||
|
LambdaSet(lambda_set) => {
|
||||||
|
basic_type_from_layout_1(env, &lambda_set.runtime_representation())
|
||||||
|
}
|
||||||
|
Union(union_layout) => {
|
||||||
|
use UnionLayout::*;
|
||||||
|
|
||||||
|
let tag_id_type = basic_type_from_layout(env, &union_layout.tag_id_layout());
|
||||||
|
|
||||||
|
match union_layout {
|
||||||
|
NonRecursive(tags) => {
|
||||||
|
let data = block_of_memory_slices(env.context, tags, env.ptr_bytes);
|
||||||
|
let struct_type = env.context.struct_type(&[data, tag_id_type], false);
|
||||||
|
|
||||||
|
struct_type.ptr_type(AddressSpace::Generic).into()
|
||||||
|
}
|
||||||
|
Recursive(tags)
|
||||||
|
| NullableWrapped {
|
||||||
|
other_tags: tags, ..
|
||||||
|
} => {
|
||||||
|
let data = block_of_memory_slices(env.context, tags, env.ptr_bytes);
|
||||||
|
|
||||||
|
if union_layout.stores_tag_id_as_data(env.ptr_bytes) {
|
||||||
|
env.context
|
||||||
|
.struct_type(&[data, tag_id_type], false)
|
||||||
|
.ptr_type(AddressSpace::Generic)
|
||||||
|
.into()
|
||||||
|
} else {
|
||||||
|
data.ptr_type(AddressSpace::Generic).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NullableUnwrapped { other_fields, .. } => {
|
||||||
|
let block = block_of_memory_slices(env.context, &[other_fields], env.ptr_bytes);
|
||||||
|
block.ptr_type(AddressSpace::Generic).into()
|
||||||
|
}
|
||||||
|
NonNullableUnwrapped(fields) => {
|
||||||
|
let block = block_of_memory_slices(env.context, &[fields], env.ptr_bytes);
|
||||||
|
block.ptr_type(AddressSpace::Generic).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RecursivePointer => {
|
||||||
|
// TODO make this dynamic
|
||||||
|
env.context
|
||||||
|
.i64_type()
|
||||||
|
.ptr_type(AddressSpace::Generic)
|
||||||
|
.as_basic_type_enum()
|
||||||
|
}
|
||||||
|
|
||||||
|
Builtin(builtin) => basic_type_from_builtin(env, builtin),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn basic_type_from_builtin<'a, 'ctx, 'env>(
|
pub fn basic_type_from_builtin<'a, 'ctx, 'env>(
|
||||||
env: &crate::llvm::build::Env<'a, 'ctx, 'env>,
|
env: &crate::llvm::build::Env<'a, 'ctx, 'env>,
|
||||||
builtin: &Builtin<'_>,
|
builtin: &Builtin<'_>,
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use crate::debug_info_init;
|
use crate::debug_info_init;
|
||||||
use crate::llvm::bitcode::call_void_bitcode_fn;
|
use crate::llvm::bitcode::call_void_bitcode_fn;
|
||||||
use crate::llvm::build::{
|
use crate::llvm::build::{
|
||||||
add_func, cast_basic_basic, cast_block_of_memory_to_tag, get_tag_id, get_tag_id_non_recursive,
|
add_func, cast_basic_basic, get_tag_id, tag_pointer_clear_tag_id, use_roc_value, Env,
|
||||||
tag_pointer_clear_tag_id, Env, FAST_CALL_CONV, TAG_DATA_INDEX,
|
FAST_CALL_CONV, TAG_DATA_INDEX, TAG_ID_INDEX,
|
||||||
};
|
};
|
||||||
use crate::llvm::build_list::{incrementing_elem_loop, list_len, load_list};
|
use crate::llvm::build_list::{incrementing_elem_loop, list_len, load_list};
|
||||||
use crate::llvm::convert::{basic_type_from_layout, ptr_int};
|
use crate::llvm::convert::{basic_type_from_layout, basic_type_from_layout_1, ptr_int};
|
||||||
use bumpalo::collections::Vec;
|
use bumpalo::collections::Vec;
|
||||||
use inkwell::basic_block::BasicBlock;
|
use inkwell::basic_block::BasicBlock;
|
||||||
use inkwell::context::Context;
|
use inkwell::context::Context;
|
||||||
|
@ -139,8 +139,10 @@ impl<'ctx> PointerToRefcount<'ctx> {
|
||||||
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 parent = block.get_parent().unwrap();
|
let parent = block.get_parent().unwrap();
|
||||||
|
|
||||||
let modify_block = env.context.append_basic_block(parent, "inc_str_modify");
|
let modify_block = env
|
||||||
let cont_block = env.context.append_basic_block(parent, "inc_str_cont");
|
.context
|
||||||
|
.append_basic_block(parent, "inc_refcount_modify");
|
||||||
|
let cont_block = env.context.append_basic_block(parent, "inc_refcount_cont");
|
||||||
|
|
||||||
env.builder
|
env.builder
|
||||||
.build_conditional_branch(is_static_allocation, cont_block, modify_block);
|
.build_conditional_branch(is_static_allocation, cont_block, modify_block);
|
||||||
|
@ -349,18 +351,25 @@ fn modify_refcount_struct_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
for (i, field_layout) in layouts.iter().enumerate() {
|
for (i, field_layout) in layouts.iter().enumerate() {
|
||||||
if field_layout.contains_refcounted() {
|
if field_layout.contains_refcounted() {
|
||||||
let field_ptr = 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")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let field_value = use_roc_value(
|
||||||
|
env,
|
||||||
|
*field_layout,
|
||||||
|
raw_value,
|
||||||
|
"load_struct_tag_field_for_decrement",
|
||||||
|
);
|
||||||
|
|
||||||
modify_refcount_layout_help(
|
modify_refcount_layout_help(
|
||||||
env,
|
env,
|
||||||
parent,
|
parent,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
mode.to_call_mode(fn_val),
|
mode.to_call_mode(fn_val),
|
||||||
when_recursive,
|
when_recursive,
|
||||||
field_ptr,
|
field_value,
|
||||||
field_layout,
|
field_layout,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -753,7 +762,15 @@ fn modify_refcount_list_help<'a, 'ctx, 'env>(
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
incrementing_elem_loop(env, parent, ptr, len, "modify_rc_index", loop_fn);
|
incrementing_elem_loop(
|
||||||
|
env,
|
||||||
|
parent,
|
||||||
|
*element_layout,
|
||||||
|
ptr,
|
||||||
|
len,
|
||||||
|
"modify_rc_index",
|
||||||
|
loop_fn,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let refcount_ptr = PointerToRefcount::from_list_wrapper(env, original_wrapper);
|
let refcount_ptr = PointerToRefcount::from_list_wrapper(env, original_wrapper);
|
||||||
|
@ -1289,7 +1306,7 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>(
|
||||||
.build_bitcast(
|
.build_bitcast(
|
||||||
value_ptr,
|
value_ptr,
|
||||||
wrapper_type.ptr_type(AddressSpace::Generic),
|
wrapper_type.ptr_type(AddressSpace::Generic),
|
||||||
"opaque_to_correct",
|
"opaque_to_correct_recursive_decrement",
|
||||||
)
|
)
|
||||||
.into_pointer_value();
|
.into_pointer_value();
|
||||||
|
|
||||||
|
@ -1602,7 +1619,7 @@ fn modify_refcount_union<'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_1(env, &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_union_help(
|
modify_refcount_union_help(
|
||||||
|
@ -1647,18 +1664,24 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
// Add args to scope
|
// Add args to scope
|
||||||
let arg_symbol = Symbol::ARG_1;
|
let arg_symbol = Symbol::ARG_1;
|
||||||
let arg_val = fn_val.get_param_iter().next().unwrap();
|
let arg_ptr = fn_val.get_param_iter().next().unwrap().into_pointer_value();
|
||||||
|
|
||||||
arg_val.set_name(arg_symbol.as_str(&env.interns));
|
arg_ptr.set_name(arg_symbol.as_str(&env.interns));
|
||||||
|
|
||||||
let parent = fn_val;
|
let parent = fn_val;
|
||||||
|
|
||||||
let before_block = env.builder.get_insert_block().expect("to be in a function");
|
let before_block = env.builder.get_insert_block().expect("to be in a function");
|
||||||
|
|
||||||
let wrapper_struct = arg_val.into_struct_value();
|
|
||||||
|
|
||||||
// read the tag_id
|
// read the tag_id
|
||||||
let tag_id = get_tag_id_non_recursive(env, wrapper_struct);
|
let tag_id_ptr = env
|
||||||
|
.builder
|
||||||
|
.build_struct_gep(arg_ptr, TAG_ID_INDEX, "tag_id_ptr")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let tag_id = env
|
||||||
|
.builder
|
||||||
|
.build_load(tag_id_ptr, "load_tag_id")
|
||||||
|
.into_int_value();
|
||||||
|
|
||||||
let tag_id_u8 = env
|
let tag_id_u8 = env
|
||||||
.builder
|
.builder
|
||||||
|
@ -1686,12 +1709,16 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>(
|
||||||
let wrapper_type = basic_type_from_layout(env, &Layout::Struct(field_layouts));
|
let wrapper_type = basic_type_from_layout(env, &Layout::Struct(field_layouts));
|
||||||
|
|
||||||
debug_assert!(wrapper_type.is_struct_type());
|
debug_assert!(wrapper_type.is_struct_type());
|
||||||
let data_bytes = env
|
let opaque_tag_data_ptr = env
|
||||||
.builder
|
.builder
|
||||||
.build_extract_value(wrapper_struct, TAG_DATA_INDEX, "read_tag_id")
|
.build_struct_gep(arg_ptr, TAG_DATA_INDEX, "field_ptr")
|
||||||
.unwrap()
|
.unwrap();
|
||||||
.into_struct_value();
|
|
||||||
let wrapper_struct = cast_block_of_memory_to_tag(env.builder, data_bytes, wrapper_type);
|
let cast_tag_data_pointer = env.builder.build_pointer_cast(
|
||||||
|
opaque_tag_data_ptr,
|
||||||
|
wrapper_type.ptr_type(AddressSpace::Generic),
|
||||||
|
"cast_to_concrete_tag",
|
||||||
|
);
|
||||||
|
|
||||||
for (i, field_layout) in field_layouts.iter().enumerate() {
|
for (i, field_layout) in field_layouts.iter().enumerate() {
|
||||||
if let Layout::RecursivePointer = field_layout {
|
if let Layout::RecursivePointer = field_layout {
|
||||||
|
@ -1699,16 +1726,22 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>(
|
||||||
} else if field_layout.contains_refcounted() {
|
} else if field_layout.contains_refcounted() {
|
||||||
let field_ptr = env
|
let field_ptr = env
|
||||||
.builder
|
.builder
|
||||||
.build_extract_value(wrapper_struct, i as u32, "modify_tag_field")
|
.build_struct_gep(cast_tag_data_pointer, i as u32, "modify_tag_field")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let field_value = if field_layout.is_passed_by_reference() {
|
||||||
|
field_ptr.into()
|
||||||
|
} else {
|
||||||
|
env.builder.build_load(field_ptr, "field_value")
|
||||||
|
};
|
||||||
|
|
||||||
modify_refcount_layout_help(
|
modify_refcount_layout_help(
|
||||||
env,
|
env,
|
||||||
parent,
|
parent,
|
||||||
layout_ids,
|
layout_ids,
|
||||||
mode.to_call_mode(fn_val),
|
mode.to_call_mode(fn_val),
|
||||||
when_recursive,
|
when_recursive,
|
||||||
field_ptr,
|
field_value,
|
||||||
field_layout,
|
field_layout,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -863,6 +863,16 @@ impl<'a> Layout<'a> {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_passed_by_reference(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Layout::Union(UnionLayout::NonRecursive(_)) => true,
|
||||||
|
Layout::LambdaSet(lambda_set) => {
|
||||||
|
lambda_set.runtime_representation().is_passed_by_reference()
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn stack_size(&self, pointer_size: u32) -> u32 {
|
pub fn stack_size(&self, pointer_size: u32) -> u32 {
|
||||||
let width = self.stack_size_without_alignment(pointer_size);
|
let width = self.stack_size_without_alignment(pointer_size);
|
||||||
let alignment = self.alignment_bytes(pointer_size);
|
let alignment = self.alignment_bytes(pointer_size);
|
||||||
|
@ -941,16 +951,16 @@ impl<'a> Layout<'a> {
|
||||||
})
|
})
|
||||||
.max();
|
.max();
|
||||||
|
|
||||||
|
let tag_id_builtin = variant.tag_id_builtin();
|
||||||
match max_alignment {
|
match max_alignment {
|
||||||
Some(align) => {
|
Some(align) => round_up_to_alignment(
|
||||||
let tag_id_builtin = variant.tag_id_builtin();
|
align.max(tag_id_builtin.alignment_bytes(pointer_size)),
|
||||||
|
tag_id_builtin.alignment_bytes(pointer_size),
|
||||||
round_up_to_alignment(
|
),
|
||||||
align,
|
None => {
|
||||||
tag_id_builtin.alignment_bytes(pointer_size),
|
// none of the tags had any payload, but the tag id still contains information
|
||||||
)
|
tag_id_builtin.alignment_bytes(pointer_size)
|
||||||
}
|
}
|
||||||
None => 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Recursive(_)
|
Recursive(_)
|
||||||
|
@ -2674,3 +2684,27 @@ impl<'a> std::convert::TryFrom<&Layout<'a>> for ListLayout<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn width_and_alignment_union_empty_struct() {
|
||||||
|
let lambda_set = LambdaSet {
|
||||||
|
set: &[(Symbol::LIST_MAP, &[])],
|
||||||
|
representation: &Layout::Struct(&[]),
|
||||||
|
};
|
||||||
|
|
||||||
|
let a = &[Layout::Struct(&[])] as &[_];
|
||||||
|
let b = &[Layout::LambdaSet(lambda_set)] as &[_];
|
||||||
|
let tt = [a, b];
|
||||||
|
|
||||||
|
let layout = Layout::Union(UnionLayout::NonRecursive(&tt));
|
||||||
|
|
||||||
|
// at the moment, the tag id uses an I64, so
|
||||||
|
let ptr_width = 8;
|
||||||
|
assert_eq!(layout.stack_size(ptr_width), 8);
|
||||||
|
assert_eq!(layout.alignment_bytes(ptr_width), 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -453,7 +453,7 @@ fn result_with_guard_pattern() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
fn maybe_is_just() {
|
fn maybe_is_just_not_nested() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
|
|
|
@ -198,6 +198,10 @@ fn create_llvm_module<'a>(
|
||||||
if name.starts_with("roc_builtins.dict") {
|
if name.starts_with("roc_builtins.dict") {
|
||||||
function.add_attribute(AttributeLoc::Function, attr);
|
function.add_attribute(AttributeLoc::Function, attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if name.starts_with("roc_builtins.list") {
|
||||||
|
function.add_attribute(AttributeLoc::Function, attr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compile and add all the Procs before adding main
|
// Compile and add all the Procs before adding main
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue