Merge branch 'main' into Frame-Limited

This commit is contained in:
J.Teeuwissen 2023-03-30 20:38:05 +02:00
commit 9b410694fe
No known key found for this signature in database
GPG key ID: DB5F7A1ED8D478AD
591 changed files with 42667 additions and 28227 deletions

View file

@ -1,24 +1,26 @@
[package]
name = "roc_gen_llvm"
description = "The LLVM backend for the Roc compiler"
version = "0.0.1"
authors = ["The Roc Contributors"]
license = "UPL-1.0"
edition = "2021"
authors.workspace = true
edition.workspace = true
license.workspace = true
version.workspace = true
[dependencies]
roc_alias_analysis = { path = "../alias_analysis" }
roc_collections = { path = "../collections" }
roc_module = { path = "../module" }
roc_builtins = { path = "../builtins" }
roc_error_macros = { path = "../../error_macros" }
roc_mono = { path = "../mono" }
roc_target = { path = "../roc_target" }
roc_std = { path = "../../roc_std" }
roc_debug_flags = { path = "../debug_flags" }
roc_region = { path = "../region" }
morphic_lib = { path = "../../vendor/morphic_lib" }
roc_alias_analysis = { path = "../alias_analysis" }
roc_bitcode_bc = { path = "../builtins/bitcode/bc" }
roc_builtins = { path = "../builtins" }
roc_collections = { path = "../collections" }
roc_debug_flags = { path = "../debug_flags" }
roc_error_macros = { path = "../../error_macros" }
roc_module = { path = "../module" }
roc_mono = { path = "../mono" }
roc_region = { path = "../region" }
roc_std = { path = "../../roc_std" }
roc_target = { path = "../roc_target" }
bumpalo.workspace = true
inkwell.workspace = true
target-lexicon.workspace = true
inkwell.workspace = true

View file

@ -11,8 +11,8 @@ use crate::llvm::refcounting::{
use inkwell::attributes::{Attribute, AttributeLoc};
use inkwell::types::{BasicType, BasicTypeEnum, StructType};
use inkwell::values::{
BasicValue, BasicValueEnum, CallSiteValue, FunctionValue, InstructionValue, IntValue,
PointerValue, StructValue,
BasicValueEnum, CallSiteValue, FunctionValue, InstructionValue, IntValue, PointerValue,
StructValue,
};
use inkwell::AddressSpace;
use roc_error_macros::internal_error;
@ -206,7 +206,7 @@ fn build_transform_caller_help<'a, 'ctx, 'env>(
let block = env.builder.get_insert_block().expect("to be in a function");
let di_location = env.builder.get_current_debug_location().unwrap();
let arg_type = env.context.i8_type().ptr_type(AddressSpace::Generic);
let arg_type = env.context.i8_type().ptr_type(AddressSpace::default());
let function_value = crate::llvm::refcounting::build_header_help(
env,
@ -244,7 +244,7 @@ fn build_transform_caller_help<'a, 'ctx, 'env>(
for (argument_ptr, layout) in arguments.iter().zip(argument_layouts) {
let basic_type =
basic_type_from_layout(env, layout_interner, *layout).ptr_type(AddressSpace::Generic);
basic_type_from_layout(env, layout_interner, *layout).ptr_type(AddressSpace::default());
let cast_ptr = env.builder.build_pointer_cast(
argument_ptr.into_pointer_value(),
@ -274,7 +274,7 @@ fn build_transform_caller_help<'a, 'ctx, 'env>(
}
(true, layout) => {
let closure_type = basic_type_from_layout(env, layout_interner, layout)
.ptr_type(AddressSpace::Generic);
.ptr_type(AddressSpace::default());
let closure_cast =
env.builder
@ -310,8 +310,7 @@ fn build_transform_caller_help<'a, 'ctx, 'env>(
env.builder.build_return(None);
env.builder.position_at_end(block);
env.builder
.set_current_debug_location(env.context, di_location);
env.builder.set_current_debug_location(di_location);
function_value
}
@ -375,7 +374,7 @@ fn build_rc_wrapper<'a, 'ctx, 'env>(
let function_value = match env.module.get_function(fn_name.as_str()) {
Some(function_value) => function_value,
None => {
let arg_type = env.context.i8_type().ptr_type(AddressSpace::Generic);
let arg_type = env.context.i8_type().ptr_type(AddressSpace::default());
let function_value = match rc_operation {
Mode::Inc | Mode::Dec => crate::llvm::refcounting::build_header_help(
@ -411,7 +410,7 @@ fn build_rc_wrapper<'a, 'ctx, 'env>(
generic_value_ptr.set_name(Symbol::ARG_1.as_str(&env.interns));
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::default());
let value_ptr =
env.builder
.build_pointer_cast(generic_value_ptr, value_ptr_type, "load_opaque");
@ -449,8 +448,7 @@ fn build_rc_wrapper<'a, 'ctx, 'env>(
};
env.builder.position_at_end(block);
env.builder
.set_current_debug_location(env.context, di_location);
env.builder.set_current_debug_location(di_location);
function_value
}
@ -472,7 +470,7 @@ pub fn build_eq_wrapper<'a, 'ctx, 'env>(
let function_value = match env.module.get_function(fn_name.as_str()) {
Some(function_value) => function_value,
None => {
let arg_type = env.context.i8_type().ptr_type(AddressSpace::Generic);
let arg_type = env.context.i8_type().ptr_type(AddressSpace::default());
let function_value = crate::llvm::refcounting::build_header_help(
env,
@ -502,7 +500,7 @@ pub fn build_eq_wrapper<'a, 'ctx, 'env>(
value_ptr2.set_name(Symbol::ARG_2.as_str(&env.interns));
let value_type = basic_type_from_layout(env, layout_interner, layout)
.ptr_type(AddressSpace::Generic);
.ptr_type(AddressSpace::default());
let value_cast1 = env
.builder
@ -533,8 +531,7 @@ pub fn build_eq_wrapper<'a, 'ctx, 'env>(
};
env.builder.position_at_end(block);
env.builder
.set_current_debug_location(env.context, di_location);
env.builder.set_current_debug_location(di_location);
function_value
}
@ -558,7 +555,7 @@ pub fn build_compare_wrapper<'a, 'ctx, 'env>(
let function_value = match env.module.get_function(fn_name) {
Some(function_value) => function_value,
None => {
let arg_type = env.context.i8_type().ptr_type(AddressSpace::Generic);
let arg_type = env.context.i8_type().ptr_type(AddressSpace::default());
let function_value = crate::llvm::refcounting::build_header_help(
env,
@ -593,7 +590,7 @@ pub fn build_compare_wrapper<'a, 'ctx, 'env>(
value_ptr2.set_name(Symbol::ARG_3.as_str(&env.interns));
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::default());
let value_cast1 =
env.builder
@ -623,7 +620,7 @@ pub fn build_compare_wrapper<'a, 'ctx, 'env>(
_ => {
let closure_type =
basic_type_from_layout(env, layout_interner, closure_data_repr);
let closure_ptr_type = closure_type.ptr_type(AddressSpace::Generic);
let closure_ptr_type = closure_type.ptr_type(AddressSpace::default());
let closure_cast = env.builder.build_pointer_cast(
closure_ptr,
@ -659,8 +656,7 @@ pub fn build_compare_wrapper<'a, 'ctx, 'env>(
};
env.builder.position_at_end(block);
env.builder
.set_current_debug_location(env.context, di_location);
env.builder.set_current_debug_location(di_location);
function_value
}
@ -798,7 +794,7 @@ fn ptr_len_cap<'a, 'ctx, 'env>(
let ptr = env.builder.build_int_to_ptr(
lower_word,
env.context.i8_type().ptr_type(AddressSpace::Generic),
env.context.i8_type().ptr_type(AddressSpace::default()),
"list_ptr",
);

View file

@ -24,8 +24,8 @@ use inkwell::types::{
};
use inkwell::values::BasicValueEnum::{self, *};
use inkwell::values::{
BasicMetadataValueEnum, BasicValue, CallSiteValue, FunctionValue, InstructionValue, IntValue,
PhiValue, PointerValue, StructValue,
BasicMetadataValueEnum, CallSiteValue, FunctionValue, InstructionValue, IntValue, PhiValue,
PointerValue, StructValue,
};
use inkwell::OptimizationLevel;
use inkwell::{AddressSpace, IntPredicate};
@ -37,11 +37,10 @@ use roc_collections::all::{ImMap, MutMap, MutSet};
use roc_debug_flags::dbg_do;
#[cfg(debug_assertions)]
use roc_debug_flags::ROC_PRINT_LLVM_FN_VERIFICATION;
use roc_error_macros::internal_error;
use roc_module::symbol::{Interns, ModuleId, Symbol};
use roc_mono::ir::{
BranchInfo, CallType, CrashTag, EntryPoint, JoinPointId, ListLiteralElement, ModifyRc,
OptLevel, ProcLayout, SingleEntryPoint,
BranchInfo, CallType, CrashTag, EntryPoint, GlueLayouts, HostExposedLambdaSet, JoinPointId,
ListLiteralElement, ModifyRc, OptLevel, ProcLayout, SingleEntryPoint,
};
use roc_mono::layout::{
Builtin, InLayout, LambdaName, LambdaSet, Layout, LayoutIds, LayoutInterner, Niche,
@ -157,7 +156,7 @@ macro_rules! debug_info_init {
/* current_scope */ lexical_block.as_debug_info_scope(),
/* inlined_at */ None,
);
$env.builder.set_current_debug_location(&$env.context, loc);
$env.builder.set_current_debug_location(loc);
}};
}
@ -201,6 +200,7 @@ pub enum LlvmBackendMode {
BinaryDev,
/// Creates a test wrapper around the main roc function to catch and report panics.
/// Provides a testing implementation of primitives (roc_alloc, roc_panic, etc)
BinaryGlue,
GenTest,
WasmGenTest,
CliTest,
@ -211,6 +211,7 @@ impl LlvmBackendMode {
match self {
LlvmBackendMode::Binary => true,
LlvmBackendMode::BinaryDev => true,
LlvmBackendMode::BinaryGlue => false,
LlvmBackendMode::GenTest => false,
LlvmBackendMode::WasmGenTest => true,
LlvmBackendMode::CliTest => false,
@ -222,6 +223,7 @@ impl LlvmBackendMode {
match self {
LlvmBackendMode::Binary => false,
LlvmBackendMode::BinaryDev => false,
LlvmBackendMode::BinaryGlue => false,
LlvmBackendMode::GenTest => true,
LlvmBackendMode::WasmGenTest => true,
LlvmBackendMode::CliTest => true,
@ -232,6 +234,7 @@ impl LlvmBackendMode {
match self {
LlvmBackendMode::Binary => false,
LlvmBackendMode::BinaryDev => true,
LlvmBackendMode::BinaryGlue => false,
LlvmBackendMode::GenTest => false,
LlvmBackendMode::WasmGenTest => false,
LlvmBackendMode::CliTest => true,
@ -686,7 +689,7 @@ fn promote_to_wasm_test_wrapper<'a, 'ctx, 'env>(
let output_type = match roc_main_fn.get_type().get_return_type() {
Some(return_type) => {
let output_type = return_type.ptr_type(AddressSpace::Generic);
let output_type = return_type.ptr_type(AddressSpace::default());
output_type.into()
}
None => {
@ -880,7 +883,7 @@ fn small_str_ptr_width_8<'a, 'ctx, 'env>(
let len = env.ptr_int().const_int(word2, false);
let cap = env.ptr_int().const_int(word3, false);
let address_space = AddressSpace::Generic;
let address_space = AddressSpace::default();
let ptr_type = env.context.i8_type().ptr_type(address_space);
let ptr = env.builder.build_int_to_ptr(ptr, ptr_type, "to_u8_ptr");
@ -907,7 +910,7 @@ fn small_str_ptr_width_4<'a, 'ctx, 'env>(
let len = env.ptr_int().const_int(word2 as u64, false);
let cap = env.ptr_int().const_int(word3 as u64, false);
let address_space = AddressSpace::Generic;
let address_space = AddressSpace::default();
let ptr_type = env.context.i8_type().ptr_type(address_space);
let ptr = env.builder.build_int_to_ptr(ptr, ptr_type, "to_u8_ptr");
@ -1049,7 +1052,7 @@ fn struct_pointer_from_fields<'a, 'ctx, 'env, I>(
.builder
.build_bitcast(
input_pointer,
struct_type.ptr_type(AddressSpace::Generic),
struct_type.ptr_type(AddressSpace::default()),
"struct_ptr",
)
.into_pointer_value();
@ -1310,7 +1313,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
let data_ptr = env.builder.build_pointer_cast(
opaque_data_ptr,
struct_type.ptr_type(AddressSpace::Generic),
struct_type.ptr_type(AddressSpace::default()),
"to_data_pointer",
);
@ -1338,14 +1341,15 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
let field_layouts = tag_layouts[*tag_id as usize];
let ptr = tag_pointer_clear_tag_id(env, argument.into_pointer_value());
let target_loaded_type = basic_type_from_layout(env, layout_interner, layout);
lookup_at_index_ptr2(
env,
layout_interner,
union_layout,
field_layouts,
*index as usize,
ptr,
target_loaded_type,
)
}
UnionLayout::NonNullableUnwrapped(field_layouts) => {
@ -1353,15 +1357,16 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
layout_interner.insert(Layout::struct_no_name_order(field_layouts));
let struct_type = basic_type_from_layout(env, layout_interner, struct_layout);
let target_loaded_type = basic_type_from_layout(env, layout_interner, layout);
lookup_at_index_ptr(
env,
layout_interner,
union_layout,
field_layouts,
*index as usize,
argument.into_pointer_value(),
struct_type.into_struct_type(),
target_loaded_type,
)
}
UnionLayout::NullableWrapped {
@ -1380,13 +1385,15 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
let field_layouts = other_tags[tag_index as usize];
let ptr = tag_pointer_clear_tag_id(env, argument.into_pointer_value());
let target_loaded_type = basic_type_from_layout(env, layout_interner, layout);
lookup_at_index_ptr2(
env,
layout_interner,
union_layout,
field_layouts,
*index as usize,
ptr,
target_loaded_type,
)
}
UnionLayout::NullableUnwrapped {
@ -1401,16 +1408,17 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
layout_interner.insert(Layout::struct_no_name_order(field_layouts));
let struct_type = basic_type_from_layout(env, layout_interner, struct_layout);
let target_loaded_type = basic_type_from_layout(env, layout_interner, layout);
lookup_at_index_ptr(
env,
layout_interner,
union_layout,
field_layouts,
// the tag id is not stored
*index as usize,
argument.into_pointer_value(),
struct_type.into_struct_type(),
target_loaded_type,
)
}
}
@ -1535,7 +1543,7 @@ fn build_tag_field_value<'a, 'ctx, 'env>(
env.builder
.build_pointer_cast(
value.into_pointer_value(),
env.context.i64_type().ptr_type(AddressSpace::Generic),
env.context.i64_type().ptr_type(AddressSpace::default()),
"cast_recursive_pointer",
)
.into()
@ -1751,7 +1759,7 @@ fn build_tag<'a, 'ctx, 'env>(
);
if tag_id == *nullable_id as _ {
let output_type = roc_union.struct_type().ptr_type(AddressSpace::Generic);
let output_type = roc_union.struct_type().ptr_type(AddressSpace::default());
return output_type.const_null().into();
}
@ -1993,17 +2001,17 @@ pub fn get_tag_id<'a, 'ctx, 'env>(
fn lookup_at_index_ptr<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_interner: &mut STLayoutInterner<'a>,
union_layout: &UnionLayout<'a>,
field_layouts: &[InLayout<'a>],
index: usize,
value: PointerValue<'ctx>,
struct_type: StructType<'ctx>,
target_loaded_type: BasicTypeEnum<'ctx>,
) -> BasicValueEnum<'ctx> {
let builder = env.builder;
let ptr = env.builder.build_pointer_cast(
value,
struct_type.ptr_type(AddressSpace::Generic),
struct_type.ptr_type(AddressSpace::default()),
"cast_lookup_at_index_ptr",
);
@ -2020,35 +2028,18 @@ fn lookup_at_index_ptr<'a, 'ctx, 'env>(
"load_at_index_ptr_old",
);
if let Some(Layout::RecursivePointer(_)) = field_layouts
.get(index as usize)
.map(|l| layout_interner.get(*l))
{
// a recursive field is stored as a `i64*`, to use it we must cast it to
// a pointer to the block of memory representation
let union_layout = layout_interner.insert(Layout::Union(*union_layout));
let actual_type = basic_type_from_layout(env, layout_interner, union_layout);
debug_assert!(actual_type.is_pointer_type());
builder
.build_pointer_cast(
result.into_pointer_value(),
actual_type.into_pointer_type(),
"cast_rec_pointer_lookup_at_index_ptr_old",
)
.into()
} else {
result
}
// A recursive pointer in the loaded structure is stored as a `i64*`, but the loaded layout
// might want a more precise structure. As such, cast it to the refined type if needed.
cast_if_necessary_for_opaque_recursive_pointers(env.builder, result, target_loaded_type)
}
fn lookup_at_index_ptr2<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_interner: &mut STLayoutInterner<'a>,
union_layout: &UnionLayout<'a>,
field_layouts: &'a [InLayout<'a>],
index: usize,
value: PointerValue<'ctx>,
target_loaded_type: BasicTypeEnum<'ctx>,
) -> BasicValueEnum<'ctx> {
let builder = env.builder;
@ -2058,7 +2049,7 @@ fn lookup_at_index_ptr2<'a, 'ctx, 'env>(
let data_ptr = env.builder.build_pointer_cast(
value,
struct_type.ptr_type(AddressSpace::Generic),
struct_type.ptr_type(AddressSpace::default()),
"cast_lookup_at_index_ptr",
);
@ -2080,27 +2071,9 @@ fn lookup_at_index_ptr2<'a, 'ctx, 'env>(
"load_at_index_ptr",
);
if let Some(Layout::RecursivePointer(_)) = field_layouts
.get(index as usize)
.map(|l| layout_interner.get(*l))
{
// a recursive field is stored as a `i64*`, to use it we must cast it to
// a pointer to the block of memory representation
let union_layout = layout_interner.insert(Layout::Union(*union_layout));
let actual_type = basic_type_from_layout(env, layout_interner, union_layout);
debug_assert!(actual_type.is_pointer_type());
builder
.build_pointer_cast(
result.into_pointer_value(),
actual_type.into_pointer_type(),
"cast_rec_pointer_lookup_at_index_ptr_new",
)
.into()
} else {
result
}
// A recursive pointer in the loaded structure is stored as a `i64*`, but the loaded layout
// might want a more precise structure. As such, cast it to the refined type if needed.
cast_if_necessary_for_opaque_recursive_pointers(env.builder, result, target_loaded_type)
}
pub fn reserve_with_refcount<'a, 'ctx, 'env>(
@ -2181,7 +2154,7 @@ pub fn allocate_with_refcount_help<'a, 'ctx, 'env>(
)
.into_pointer_value();
let ptr_type = value_type.ptr_type(AddressSpace::Generic);
let ptr_type = value_type.ptr_type(AddressSpace::default());
env.builder
.build_pointer_cast(ptr, ptr_type, "alloc_cast_to_desired")
@ -2406,7 +2379,7 @@ pub fn store_roc_value_opaque<'a, 'ctx, 'env>(
value: BasicValueEnum<'ctx>,
) {
let target_type =
basic_type_from_layout(env, layout_interner, layout).ptr_type(AddressSpace::Generic);
basic_type_from_layout(env, layout_interner, layout).ptr_type(AddressSpace::default());
let destination =
env.builder
.build_pointer_cast(opaque_destination, target_type, "store_roc_value_opaque");
@ -2659,7 +2632,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
let basic_type = basic_type_from_layout(env, layout_interner, param.layout);
let phi_type = if layout_interner.is_passed_by_reference(param.layout) {
basic_type.ptr_type(AddressSpace::Generic).into()
basic_type.ptr_type(AddressSpace::default()).into()
} else {
basic_type
};
@ -3043,6 +3016,24 @@ pub(crate) fn load_symbol_and_layout<'a, 'ctx, 'b>(
}
}
fn equivalent_type_constructors(t1: &BasicTypeEnum, t2: &BasicTypeEnum) -> bool {
use BasicTypeEnum::*;
match (t1, t2) {
(ArrayType(_), ArrayType(_)) => true,
(ArrayType(_), _) => false,
(FloatType(_), FloatType(_)) => true,
(FloatType(_), _) => false,
(IntType(_), IntType(_)) => true,
(IntType(_), _) => false,
(PointerType(_), PointerType(_)) => true,
(PointerType(_), _) => false,
(StructType(_), StructType(_)) => true,
(StructType(_), _) => false,
(VectorType(_), VectorType(_)) => true,
(VectorType(_), _) => false,
}
}
/// Cast a value to another value of the same size, but only if their types are not equivalent.
/// This is needed to allow us to interoperate between recursive pointers in unions that are
/// opaque, and well-typed.
@ -3054,7 +3045,10 @@ pub fn cast_if_necessary_for_opaque_recursive_pointers<'ctx>(
from_value: BasicValueEnum<'ctx>,
to_type: BasicTypeEnum<'ctx>,
) -> BasicValueEnum<'ctx> {
if from_value.get_type() != to_type {
if from_value.get_type() != to_type
// Only perform the cast if the target types are transumatble.
&& equivalent_type_constructors(&from_value.get_type(), &to_type)
{
complex_bitcast(
builder,
from_value,
@ -3202,7 +3196,7 @@ fn complex_bitcast_from_bigger_than_to<'ctx>(
// then read it back as a different type
let to_type_pointer = builder.build_pointer_cast(
argument_pointer,
to_type.ptr_type(inkwell::AddressSpace::Generic),
to_type.ptr_type(inkwell::AddressSpace::default()),
name,
);
@ -3225,7 +3219,7 @@ fn complex_bitcast_to_bigger_than_from<'ctx>(
storage,
from_value
.get_type()
.ptr_type(inkwell::AddressSpace::Generic),
.ptr_type(inkwell::AddressSpace::default()),
name,
);
@ -3586,7 +3580,7 @@ fn expose_function_to_host_help_c_abi_generic<'a, 'ctx, 'env>(
argument_types.insert(0, output_type);
}
Some(return_type) => {
let output_type = return_type.ptr_type(AddressSpace::Generic);
let output_type = return_type.ptr_type(AddressSpace::default());
argument_types.insert(0, output_type.into());
}
}
@ -3638,7 +3632,7 @@ fn expose_function_to_host_help_c_abi_generic<'a, 'ctx, 'env>(
// bitcast the ptr
let fastcc_ptr = env.builder.build_pointer_cast(
arg.into_pointer_value(),
fastcc_type.ptr_type(AddressSpace::Generic),
fastcc_type.ptr_type(AddressSpace::default()),
"bitcast_arg",
);
@ -3733,7 +3727,7 @@ fn expose_function_to_host_help_c_abi_gen_test<'a, 'ctx, 'env>(
let return_type = wrapper_return_type;
let c_function_spec = {
let output_type = return_type.ptr_type(AddressSpace::Generic);
let output_type = return_type.ptr_type(AddressSpace::default());
argument_types.push(output_type.into());
FunctionSpec::cconv(env, CCReturn::Void, None, &argument_types)
};
@ -3842,6 +3836,7 @@ fn expose_function_to_host_help_c_abi_gen_test<'a, 'ctx, 'env>(
Some(env.context.i64_type().as_basic_type_enum()),
&[],
);
let size_function_name: String = format!("roc__{}_size", ident_string);
let size_function = add_func(
@ -3897,7 +3892,10 @@ fn expose_function_to_host_help_c_abi_v2<'a, 'ctx, 'env>(
let c_abi_roc_str_type = env.context.struct_type(
&[
env.context.i8_type().ptr_type(AddressSpace::Generic).into(),
env.context
.i8_type()
.ptr_type(AddressSpace::default())
.into(),
env.ptr_int().into(),
env.ptr_int().into(),
],
@ -3955,20 +3953,40 @@ fn expose_function_to_host_help_c_abi_v2<'a, 'ctx, 'env>(
(RocReturn::ByPointer, CCReturn::Return) => {
// Roc currently puts the return pointer at the end of the argument list.
// As such, we drop the last element here instead of the first.
(&params[..], &param_types[..param_types.len() - 1])
(
&params[..],
&param_types[..param_types.len().saturating_sub(1)],
)
}
// Drop the return pointer the other way, if the C function returns by pointer but Roc
// doesn't
(RocReturn::Return, CCReturn::ByPointer) => (&params[1..], &param_types[..]),
(RocReturn::ByPointer, CCReturn::ByPointer) => {
// Both return by pointer but Roc puts it at the end and C puts it at the beginning
(&params[1..], &param_types[..param_types.len() - 1])
(
&params[1..],
&param_types[..param_types.len().saturating_sub(1)],
)
}
(RocReturn::Return, CCReturn::Void) => {
// the roc function returns a unit value. like `{}` or `{ { {}, {} }, {} }`.
// In C, this is modelled as a function returning void
(&params[..], &param_types[..])
}
(RocReturn::ByPointer, CCReturn::Void) => {
// the roc function returns a unit value. like `{}` or `{ { {}, {} }, {} }`.
// In C, this is modelled as a function returning void
(
&params[..],
&param_types[..param_types.len().saturating_sub(1)],
)
}
_ => (&params[..], &param_types[..]),
};
debug_assert!(
params.len() == param_types.len(),
debug_assert_eq!(
params.len(),
param_types.len(),
"when exposing a function to the host, params.len() was {}, but param_types.len() was {}",
params.len(),
param_types.len()
@ -4016,7 +4034,7 @@ fn expose_function_to_host_help_c_abi_v2<'a, 'ctx, 'env>(
// bitcast the ptr
let fastcc_ptr = env.builder.build_pointer_cast(
arg.into_pointer_value(),
fastcc_type.ptr_type(AddressSpace::Generic),
fastcc_type.ptr_type(AddressSpace::default()),
"bitcast_arg",
);
@ -4102,7 +4120,7 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>(
)
}
LlvmBackendMode::Binary | LlvmBackendMode::BinaryDev => {}
LlvmBackendMode::Binary | LlvmBackendMode::BinaryDev | LlvmBackendMode::BinaryGlue => {}
}
// a generic version that writes the result into a passed *u8 pointer
@ -4131,7 +4149,7 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>(
Some(env.context.i64_type().as_basic_type_enum()),
&[],
);
let size_function_name: String = format!("roc__{}_size", ident_string);
let size_function_name: String = format!("{}_size", c_function_name);
let size_function = add_func(
env.context,
@ -4155,7 +4173,7 @@ fn expose_function_to_host_help_c_abi<'a, 'ctx, 'env>(
roc_call_result_type(env, roc_function.get_type().get_return_type().unwrap()).into()
}
LlvmBackendMode::Binary | LlvmBackendMode::BinaryDev => {
LlvmBackendMode::Binary | LlvmBackendMode::BinaryDev | LlvmBackendMode::BinaryGlue => {
basic_type_from_layout(env, layout_interner, return_layout)
}
};
@ -4193,7 +4211,7 @@ pub fn get_sjlj_buffer<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> PointerValu
env.builder.build_pointer_cast(
global.as_pointer_value(),
env.context.i32_type().ptr_type(AddressSpace::Generic),
env.context.i32_type().ptr_type(AddressSpace::default()),
"cast_sjlj_buffer",
)
}
@ -4210,12 +4228,12 @@ pub fn build_setjmp_call<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> BasicValu
let buf_type = env
.context
.i8_type()
.ptr_type(AddressSpace::Generic)
.ptr_type(AddressSpace::default())
.array_type(5);
let jmp_buf_i8p_arr = env.builder.build_pointer_cast(
jmp_buf,
buf_type.ptr_type(AddressSpace::Generic),
buf_type.ptr_type(AddressSpace::default()),
"jmp_buf [5 x i8*]",
);
@ -4256,7 +4274,7 @@ pub fn build_setjmp_call<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> BasicValu
.builder
.build_pointer_cast(
jmp_buf,
env.context.i8_type().ptr_type(AddressSpace::Generic),
env.context.i8_type().ptr_type(AddressSpace::default()),
"jmp_buf i8*",
)
.into();
@ -4413,7 +4431,7 @@ fn roc_call_result_type<'a, 'ctx, 'env>(
env.context.struct_type(
&[
env.context.i64_type().into(),
zig_str_type(env).ptr_type(AddressSpace::Generic).into(),
zig_str_type(env).ptr_type(AddressSpace::default()).into(),
return_type,
],
false,
@ -4489,7 +4507,7 @@ fn make_exception_catching_wrapper<'a, 'ctx, 'env>(
basic_type_from_layout(env, layout_interner, return_layout),
);
// argument_types.push(wrapper_return_type.ptr_type(AddressSpace::Generic).into());
// argument_types.push(wrapper_return_type.ptr_type(AddressSpace::default()).into());
// let wrapper_function_type = env.context.void_type().fn_type(&argument_types, false);
let wrapper_function_spec = FunctionSpec::cconv(
@ -4591,8 +4609,9 @@ pub fn build_procedures<'a, 'ctx, 'env>(
procedures: MutMap<(Symbol, ProcLayout<'a>), roc_mono::ir::Proc<'a>>,
entry_point: EntryPoint<'a>,
debug_output_file: Option<&Path>,
glue_layouts: &GlueLayouts<'a>,
) {
build_procedures_help(
let mod_solutions = build_procedures_help(
env,
layout_interner,
opt_level,
@ -4600,6 +4619,43 @@ pub fn build_procedures<'a, 'ctx, 'env>(
entry_point,
debug_output_file,
);
let niche = Niche::NONE;
for (symbol, top_level) in glue_layouts.getters.iter().copied() {
let it = top_level.arguments.iter().copied();
let bytes = roc_alias_analysis::func_name_bytes_help(symbol, it, niche, top_level.result);
let func_name = FuncName(&bytes);
let func_solutions = mod_solutions.func_solutions(func_name).unwrap();
let mut it = func_solutions.specs();
let Some(func_spec) = it.next() else {
// TODO this means a function was not considered host-exposed in mono
continue;
};
debug_assert!(
it.next().is_none(),
"we expect only one specialization of this symbol"
);
// NOTE fake layout; it is only used for debug prints
let getter_fn =
function_value_by_func_spec(env, *func_spec, symbol, &[], niche, Layout::UNIT);
let name = getter_fn.get_name().to_str().unwrap();
let getter_name = symbol.as_str(&env.interns);
// Add the getter function to the module.
let _ = expose_function_to_host_help_c_abi(
env,
layout_interner,
name,
getter_fn,
top_level.arguments,
top_level.result,
getter_name,
);
}
}
pub fn build_wasm_test_wrapper<'a, 'ctx, 'env>(
@ -4919,28 +4975,23 @@ fn expose_alias_to_host<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_interner: &mut STLayoutInterner<'a>,
mod_solutions: &'a ModSolutions,
proc_name: LambdaName,
fn_name: &str,
alias_symbol: Symbol,
exposed_function_symbol: Symbol,
top_level: ProcLayout<'a>,
layout: RawFunctionLayout<'a>,
hels: &HostExposedLambdaSet<'a>,
) {
let ident_string = proc_name.name().as_str(&env.interns);
let fn_name: String = format!("{}_1", ident_string);
match layout {
match hels.raw_function_layout {
RawFunctionLayout::Function(arguments, closure, result) => {
// define closure size and return value size, e.g.
//
// * roc__mainForHost_1_Update_size() -> i64
// * roc__mainForHost_1_Update_result_size() -> i64
let it = top_level.arguments.iter().copied();
let it = hels.proc_layout.arguments.iter().copied();
let bytes = roc_alias_analysis::func_name_bytes_help(
exposed_function_symbol,
hels.symbol,
it,
Niche::NONE,
top_level.result,
hels.proc_layout.result,
);
let func_name = FuncName(&bytes);
let func_solutions = mod_solutions.func_solutions(func_name).unwrap();
@ -4956,24 +5007,24 @@ fn expose_alias_to_host<'a, 'ctx, 'env>(
function_value_by_func_spec(
env,
*func_spec,
exposed_function_symbol,
top_level.arguments,
hels.symbol,
hels.proc_layout.arguments,
Niche::NONE,
top_level.result,
hels.proc_layout.result,
)
}
None => {
// morphic did not generate a specialization for this function,
// therefore it must actually be unused.
// An example is our closure callers
panic!("morphic did not specialize {:?}", exposed_function_symbol);
panic!("morphic did not specialize {:?}", hels.symbol);
}
};
build_closure_caller(
env,
layout_interner,
&fn_name,
fn_name,
evaluator,
alias_symbol,
arguments,
@ -4992,7 +5043,7 @@ fn expose_alias_to_host<'a, 'ctx, 'env>(
build_host_exposed_alias_size_help(
env,
&fn_name,
fn_name,
alias_symbol,
Some("result"),
result_type,
@ -5016,7 +5067,7 @@ fn build_closure_caller<'a, 'ctx, 'env>(
for layout in arguments {
let arg_type = basic_type_from_layout(env, layout_interner, *layout);
let arg_ptr_type = arg_type.ptr_type(AddressSpace::Generic);
let arg_ptr_type = arg_type.ptr_type(AddressSpace::default());
argument_types.push(arg_ptr_type.into());
}
@ -5025,7 +5076,7 @@ fn build_closure_caller<'a, 'ctx, 'env>(
let basic_type =
basic_type_from_layout(env, layout_interner, lambda_set.runtime_representation());
basic_type.ptr_type(AddressSpace::Generic)
basic_type.ptr_type(AddressSpace::default())
};
argument_types.push(closure_argument_type.into());
@ -5034,18 +5085,13 @@ fn build_closure_caller<'a, 'ctx, 'env>(
let result_type = basic_type_from_layout(env, layout_interner, result);
let output_type = { result_type.ptr_type(AddressSpace::Generic) };
let output_type = { result_type.ptr_type(AddressSpace::default()) };
argument_types.push(output_type.into());
// STEP 1: build function header
// e.g. `roc__main_1_Fx_caller`
let function_name = format!(
"roc__{}_{}_{}_caller",
def_name,
alias_symbol.module_string(&env.interns),
alias_symbol.as_str(&env.interns)
);
// e.g. `roc__mainForHost_0_caller` (def_name is `mainForHost_0`)
let function_name = format!("roc__{}_caller", def_name);
let function_spec = FunctionSpec::cconv(env, CCReturn::Void, None, &argument_types);
@ -5156,7 +5202,7 @@ fn build_host_exposed_alias_size<'a, 'r, 'ctx, 'env>(
fn build_host_exposed_alias_size_help<'a, 'ctx, 'env>(
env: &'a Env<'a, 'ctx, 'env>,
def_name: &str,
alias_symbol: Symbol,
_alias_symbol: Symbol,
opt_label: Option<&str>,
basic_type: BasicTypeEnum<'ctx>,
) {
@ -5166,20 +5212,9 @@ fn build_host_exposed_alias_size_help<'a, 'ctx, 'env>(
let i64 = env.context.i64_type().as_basic_type_enum();
let size_function_spec = FunctionSpec::cconv(env, CCReturn::Return, Some(i64), &[]);
let size_function_name: String = if let Some(label) = opt_label {
format!(
"roc__{}_{}_{}_{}_size",
def_name,
alias_symbol.module_string(&env.interns),
alias_symbol.as_str(&env.interns),
label
)
format!("roc__{}_{}_size", def_name, label)
} else {
format!(
"roc__{}_{}_{}_size",
def_name,
alias_symbol.module_string(&env.interns),
alias_symbol.as_str(&env.interns)
)
format!("roc__{}_size", def_name,)
};
let size_function = add_func(
@ -5198,7 +5233,7 @@ fn build_host_exposed_alias_size_help<'a, 'ctx, 'env>(
builder.build_return(Some(&size));
}
pub fn build_proc<'a, 'ctx, 'env>(
fn build_proc<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_interner: &mut STLayoutInterner<'a>,
mod_solutions: &'a ModSolutions,
@ -5219,17 +5254,18 @@ pub fn build_proc<'a, 'ctx, 'env>(
GenTest | WasmGenTest | CliTest => {
/* no host, or exposing types is not supported */
}
Binary | BinaryDev => {
for (alias_name, (generated_function, top_level, layout)) in aliases.iter() {
Binary | BinaryDev | BinaryGlue => {
for (alias_name, hels) in aliases.iter() {
let ident_string = proc.name.name().as_str(&env.interns);
let fn_name: String = format!("{}_{}", ident_string, hels.id.0);
expose_alias_to_host(
env,
layout_interner,
mod_solutions,
proc.name,
&fn_name,
*alias_name,
*generated_function,
*top_level,
*layout,
hels,
)
}
}
@ -5550,7 +5586,7 @@ fn to_cc_type_builtin<'a, 'ctx, 'env>(
basic_type_from_builtin(env, builtin)
}
Builtin::Str | Builtin::List(_) => {
let address_space = AddressSpace::Generic;
let address_space = AddressSpace::default();
let field_types: [BasicTypeEnum; 3] = [
env.context.i8_type().ptr_type(address_space).into(),
env.ptr_int().into(),
@ -5665,7 +5701,7 @@ impl<'ctx> FunctionSpec<'ctx> {
let (typ, opt_sret_parameter) = match cc_return {
CCReturn::ByPointer => {
// turn the output type into a pointer type. Make it the first argument to the function
let output_type = return_type.unwrap().ptr_type(AddressSpace::Generic);
let output_type = return_type.unwrap().ptr_type(AddressSpace::default());
let mut arguments: Vec<'_, BasicTypeEnum> =
bumpalo::vec![in env.arena; output_type.into()];
@ -5683,6 +5719,8 @@ impl<'ctx> FunctionSpec<'ctx> {
(return_type.unwrap().fn_type(&arguments, false), None)
}
CCReturn::Void => {
// NOTE: there may be a valid return type, but it is zero-sized.
// for instance just `{}` or something more complex like `{ { {}, {} }, {} }`
let arguments = function_arguments(env, argument_types);
(env.context.void_type().fn_type(&arguments, false), None)
}
@ -5707,7 +5745,7 @@ impl<'ctx> FunctionSpec<'ctx> {
return_type.fn_type(&function_arguments(env, &argument_types), false)
}
RocReturn::ByPointer => {
argument_types.push(return_type.ptr_type(AddressSpace::Generic).into());
argument_types.push(return_type.ptr_type(AddressSpace::default()).into());
env.context
.void_type()
.fn_type(&function_arguments(env, &argument_types), false)
@ -5955,7 +5993,7 @@ fn define_global_str_literal_ptr<'a, 'ctx, 'env>(
let ptr = env.builder.build_pointer_cast(
global.as_pointer_value(),
env.context.i8_type().ptr_type(AddressSpace::Generic),
env.context.i8_type().ptr_type(AddressSpace::default()),
"to_opaque",
);
@ -6090,7 +6128,7 @@ pub fn add_func<'ctx>(
) -> FunctionValue<'ctx> {
if cfg!(debug_assertions) {
if let Some(func) = module.get_function(name) {
panic!("Attempting to redefine LLVM function {}, which was already defined in this module as:\n\n{:?}", name, func);
panic!("Attempting to redefine LLVM function {}, which was already defined in this module as:\n\n{:#?}", name, func);
}
}
@ -6100,23 +6138,3 @@ pub fn add_func<'ctx>(
fn_val
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) enum WhenRecursive<'a> {
Unreachable,
Loop(UnionLayout<'a>),
}
impl<'a> WhenRecursive<'a> {
pub fn unwrap_recursive_pointer(&self, layout: Layout<'a>) -> Layout<'a> {
match layout {
Layout::RecursivePointer(_) => match self {
WhenRecursive::Loop(lay) => Layout::Union(*lay),
WhenRecursive::Unreachable => {
internal_error!("cannot compare recursive pointers outside of a structure")
}
},
_ => layout,
}
}
}

View file

@ -74,7 +74,7 @@ fn pass_element_as_opaque<'a, 'ctx, 'env>(
env.builder
.build_pointer_cast(
element_ptr,
env.context.i8_type().ptr_type(AddressSpace::Generic),
env.context.i8_type().ptr_type(AddressSpace::default()),
"pass_element_as_opaque",
)
.into()
@ -97,7 +97,7 @@ pub(crate) fn pass_as_opaque<'a, 'ctx, 'env>(
env.builder
.build_pointer_cast(
ptr,
env.context.i8_type().ptr_type(AddressSpace::Generic),
env.context.i8_type().ptr_type(AddressSpace::default()),
"pass_as_opaque",
)
.into()
@ -133,7 +133,7 @@ pub(crate) fn list_get_unsafe<'a, 'ctx, 'env>(
let builder = env.builder;
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::default());
// Load the pointer to the array data
let array_data_ptr = load_list_ptr(builder, wrapper_struct, ptr_type);
@ -183,6 +183,26 @@ pub(crate) fn list_reserve<'a, 'ctx, 'env>(
)
}
/// List.releaseExcessCapacity : List elem -> List elem
pub(crate) fn list_release_excess_capacity<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_interner: &mut STLayoutInterner<'a>,
list: BasicValueEnum<'ctx>,
element_layout: InLayout<'a>,
update_mode: UpdateMode,
) -> BasicValueEnum<'ctx> {
call_list_bitcode_fn_1(
env,
list.into_struct_value(),
&[
env.alignment_intvalue(layout_interner, element_layout),
layout_width(env, layout_interner, element_layout),
pass_update_mode(env, update_mode),
],
bitcode::LIST_RELEASE_EXCESS_CAPACITY,
)
}
/// List.appendUnsafe : List elem, elem -> List elem
pub(crate) fn list_append_unsafe<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
@ -393,17 +413,36 @@ pub(crate) fn list_len<'ctx>(
.into_int_value()
}
/// List.capacity : List * -> Nat
pub(crate) fn list_capacity<'ctx>(
pub(crate) fn list_capacity_or_ref_ptr<'ctx>(
builder: &Builder<'ctx>,
wrapper_struct: StructValue<'ctx>,
) -> IntValue<'ctx> {
builder
.build_extract_value(wrapper_struct, Builtin::WRAPPER_CAPACITY, "list_capacity")
.build_extract_value(
wrapper_struct,
Builtin::WRAPPER_CAPACITY,
"list_capacity_or_ref_ptr",
)
.unwrap()
.into_int_value()
}
// Gets a pointer to just after the refcount for a list or seamless slice.
// The value is just after the refcount so that normal lists and seamless slices can share code paths easily.
pub(crate) fn list_refcount_ptr<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
wrapper_struct: StructValue<'ctx>,
) -> PointerValue<'ctx> {
call_list_bitcode_fn(
env,
&[wrapper_struct],
&[],
BitcodeReturns::Basic,
bitcode::LIST_REFCOUNT_PTR,
)
.into_pointer_value()
}
pub(crate) fn destructure<'ctx>(
builder: &Builder<'ctx>,
wrapper_struct: StructValue<'ctx>,
@ -801,11 +840,7 @@ pub(crate) fn decref<'a, 'ctx, 'env>(
wrapper_struct: StructValue<'ctx>,
alignment: u32,
) {
let (_, pointer) = load_list(
env.builder,
wrapper_struct,
env.context.i8_type().ptr_type(AddressSpace::Generic),
);
let refcount_ptr = list_refcount_ptr(env, wrapper_struct);
crate::llvm::refcounting::decref_pointer_check_null(env, pointer, alignment);
crate::llvm::refcounting::decref_pointer_check_null(env, refcount_ptr, alignment);
}

View file

@ -32,7 +32,7 @@ pub(crate) fn decode_from_utf8_result<'a, 'ctx, 'env>(
PtrWidth::Bytes4 | PtrWidth::Bytes8 => {
let result_ptr_cast = env.builder.build_pointer_cast(
pointer,
record_type.ptr_type(AddressSpace::Generic),
record_type.ptr_type(AddressSpace::default()),
"to_unnamed",
);
@ -63,3 +63,19 @@ pub(crate) fn str_equal<'a, 'ctx, 'env>(
bitcode::STR_EQUAL,
)
}
// Gets a pointer to just after the refcount for a list or seamless slice.
// The value is just after the refcount so that normal lists and seamless slices can share code paths easily.
pub(crate) fn str_refcount_ptr<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
value: BasicValueEnum<'ctx>,
) -> PointerValue<'ctx> {
call_str_bitcode_fn(
env,
&[value],
&[],
BitcodeReturns::Basic,
bitcode::STR_REFCOUNT_PTR,
)
.into_pointer_value()
}

View file

@ -1,17 +1,14 @@
use crate::llvm::build::{
get_tag_id, tag_pointer_clear_tag_id, Env, WhenRecursive, FAST_CALL_CONV,
};
use crate::llvm::build::{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_str::str_equal;
use crate::llvm::convert::basic_type_from_layout;
use bumpalo::collections::Vec;
use inkwell::types::BasicType;
use inkwell::values::{
BasicValue, BasicValueEnum, FunctionValue, IntValue, PointerValue, StructValue,
};
use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue, StructValue};
use inkwell::{AddressSpace, FloatPredicate, IntPredicate};
use roc_builtins::bitcode;
use roc_builtins::bitcode::{FloatWidth, IntWidth};
use roc_error_macros::internal_error;
use roc_module::symbol::Symbol;
use roc_mono::layout::{
Builtin, InLayout, Layout, LayoutIds, LayoutInterner, STLayoutInterner, UnionLayout,
@ -38,7 +35,6 @@ pub fn generic_eq<'a, 'ctx, 'env>(
rhs_val,
lhs_layout,
rhs_layout,
WhenRecursive::Unreachable,
)
}
@ -59,7 +55,6 @@ pub fn generic_neq<'a, 'ctx, 'env>(
rhs_val,
lhs_layout,
rhs_layout,
WhenRecursive::Unreachable,
)
}
@ -69,8 +64,8 @@ fn build_eq_builtin<'a, 'ctx, 'env>(
layout_ids: &mut LayoutIds<'a>,
lhs_val: BasicValueEnum<'ctx>,
rhs_val: BasicValueEnum<'ctx>,
builtin_layout: InLayout<'a>,
builtin: &Builtin<'a>,
when_recursive: WhenRecursive<'a>,
) -> BasicValueEnum<'ctx> {
let int_cmp = |pred, label| {
let int_val = env.builder.build_int_compare(
@ -129,19 +124,15 @@ fn build_eq_builtin<'a, 'ctx, 'env>(
Builtin::Decimal => dec_binop_with_unchecked(env, bitcode::DEC_EQ, lhs_val, rhs_val),
Builtin::Str => str_equal(env, lhs_val, rhs_val),
Builtin::List(elem) => {
let list_layout = layout_interner.insert(Layout::Builtin(*builtin));
build_list_eq(
env,
layout_interner,
layout_ids,
list_layout,
*elem,
lhs_val.into_struct_value(),
rhs_val.into_struct_value(),
when_recursive,
)
}
Builtin::List(elem) => build_list_eq(
env,
layout_interner,
layout_ids,
builtin_layout,
*elem,
lhs_val.into_struct_value(),
rhs_val.into_struct_value(),
),
}
}
@ -153,7 +144,6 @@ fn build_eq<'a, 'ctx, 'env>(
rhs_val: BasicValueEnum<'ctx>,
lhs_layout: InLayout<'a>,
rhs_layout: InLayout<'a>,
when_recursive: WhenRecursive<'a>,
) -> BasicValueEnum<'ctx> {
let lhs_layout = &layout_interner.runtime_representation_in(lhs_layout);
let rhs_layout = &layout_interner.runtime_representation_in(rhs_layout);
@ -171,16 +161,16 @@ fn build_eq<'a, 'ctx, 'env>(
layout_ids,
lhs_val,
rhs_val,
*lhs_layout,
&builtin,
when_recursive,
),
Layout::Struct { field_layouts, .. } => build_struct_eq(
env,
layout_interner,
layout_ids,
*lhs_layout,
field_layouts,
when_recursive,
lhs_val.into_struct_value(),
rhs_val.into_struct_value(),
),
@ -191,7 +181,7 @@ fn build_eq<'a, 'ctx, 'env>(
env,
layout_interner,
layout_ids,
when_recursive,
*lhs_layout,
&union_layout,
lhs_val,
rhs_val,
@ -201,47 +191,48 @@ fn build_eq<'a, 'ctx, 'env>(
env,
layout_interner,
layout_ids,
when_recursive,
*lhs_layout,
inner_layout,
lhs_val,
rhs_val,
),
Layout::RecursivePointer(_) => match when_recursive {
WhenRecursive::Unreachable => {
unreachable!("recursion pointers should never be compared directly")
}
Layout::RecursivePointer(rec_layout) => {
let layout = rec_layout;
WhenRecursive::Loop(union_layout) => {
let layout = layout_interner.insert(Layout::Union(union_layout));
let bt = basic_type_from_layout(env, layout_interner, layout);
let bt = basic_type_from_layout(env, layout_interner, layout);
// cast the i64 pointer to a pointer to block of memory
let field1_cast = env.builder.build_pointer_cast(
lhs_val.into_pointer_value(),
bt.into_pointer_type(),
"i64_to_opaque",
);
// cast the i64 pointer to a pointer to block of memory
let field1_cast = env.builder.build_pointer_cast(
lhs_val.into_pointer_value(),
bt.into_pointer_type(),
"i64_to_opaque",
);
let field2_cast = env.builder.build_pointer_cast(
rhs_val.into_pointer_value(),
bt.into_pointer_type(),
"i64_to_opaque",
);
let field2_cast = env.builder.build_pointer_cast(
rhs_val.into_pointer_value(),
bt.into_pointer_type(),
"i64_to_opaque",
);
let union_layout = match layout_interner.get(rec_layout) {
Layout::Union(union_layout) => {
debug_assert!(!matches!(union_layout, UnionLayout::NonRecursive(..)));
union_layout
}
_ => internal_error!(),
};
build_tag_eq(
env,
layout_interner,
layout_ids,
WhenRecursive::Loop(union_layout),
&union_layout,
field1_cast.into(),
field2_cast.into(),
)
}
},
build_tag_eq(
env,
layout_interner,
layout_ids,
rec_layout,
&union_layout,
field1_cast.into(),
field2_cast.into(),
)
}
}
}
@ -251,8 +242,8 @@ fn build_neq_builtin<'a, 'ctx, 'env>(
layout_ids: &mut LayoutIds<'a>,
lhs_val: BasicValueEnum<'ctx>,
rhs_val: BasicValueEnum<'ctx>,
builtin_layout: InLayout<'a>,
builtin: &Builtin<'a>,
when_recursive: WhenRecursive<'a>,
) -> BasicValueEnum<'ctx> {
let int_cmp = |pred, label| {
let int_val = env.builder.build_int_compare(
@ -317,7 +308,6 @@ fn build_neq_builtin<'a, 'ctx, 'env>(
result.into()
}
Builtin::List(elem) => {
let builtin_layout = layout_interner.insert(Layout::Builtin(*builtin));
let is_equal = build_list_eq(
env,
layout_interner,
@ -326,7 +316,6 @@ fn build_neq_builtin<'a, 'ctx, 'env>(
*elem,
lhs_val.into_struct_value(),
rhs_val.into_struct_value(),
when_recursive,
)
.into_int_value();
@ -345,7 +334,6 @@ fn build_neq<'a, 'ctx, 'env>(
rhs_val: BasicValueEnum<'ctx>,
lhs_layout: InLayout<'a>,
rhs_layout: InLayout<'a>,
when_recursive: WhenRecursive<'a>,
) -> BasicValueEnum<'ctx> {
if lhs_layout != rhs_layout {
panic!(
@ -361,8 +349,8 @@ fn build_neq<'a, 'ctx, 'env>(
layout_ids,
lhs_val,
rhs_val,
lhs_layout,
&builtin,
when_recursive,
),
Layout::Struct { field_layouts, .. } => {
@ -370,8 +358,8 @@ fn build_neq<'a, 'ctx, 'env>(
env,
layout_interner,
layout_ids,
lhs_layout,
field_layouts,
when_recursive,
lhs_val.into_struct_value(),
rhs_val.into_struct_value(),
)
@ -387,7 +375,7 @@ fn build_neq<'a, 'ctx, 'env>(
env,
layout_interner,
layout_ids,
when_recursive,
lhs_layout,
&union_layout,
lhs_val,
rhs_val,
@ -404,7 +392,6 @@ fn build_neq<'a, 'ctx, 'env>(
env,
layout_interner,
layout_ids,
when_recursive,
lhs_layout,
inner_layout,
lhs_val,
@ -432,15 +419,17 @@ fn build_list_eq<'a, 'ctx, 'env>(
element_layout: InLayout<'a>,
list1: StructValue<'ctx>,
list2: StructValue<'ctx>,
when_recursive: WhenRecursive<'a>,
) -> BasicValueEnum<'ctx> {
let block = env.builder.get_insert_block().expect("to be in a function");
let di_location = env.builder.get_current_debug_location().unwrap();
let symbol = Symbol::LIST_EQ;
let element_layout = layout_interner.get(element_layout);
let element_layout = when_recursive.unwrap_recursive_pointer(element_layout);
let element_layout = layout_interner.insert(element_layout);
let element_layout = if let Layout::RecursivePointer(rec) = layout_interner.get(element_layout)
{
rec
} else {
element_layout
};
let fn_name = layout_ids
.get(symbol, &element_layout)
.to_symbol_string(symbol, &env.interns);
@ -461,7 +450,6 @@ fn build_list_eq<'a, 'ctx, 'env>(
env,
layout_interner,
layout_ids,
when_recursive,
function_value,
element_layout,
);
@ -471,8 +459,7 @@ fn build_list_eq<'a, 'ctx, 'env>(
};
env.builder.position_at_end(block);
env.builder
.set_current_debug_location(env.context, di_location);
env.builder.set_current_debug_location(di_location);
let call = env
.builder
.build_call(function, &[list1.into(), list2.into()], "list_eq");
@ -486,7 +473,6 @@ fn build_list_eq_help<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_interner: &mut STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
when_recursive: WhenRecursive<'a>,
parent: FunctionValue<'ctx>,
element_layout: InLayout<'a>,
) {
@ -511,7 +497,7 @@ fn build_list_eq_help<'a, 'ctx, 'env>(
/* current_scope */ lexical_block.as_debug_info_scope(),
/* inlined_at */ None,
);
builder.set_current_debug_location(ctx, loc);
builder.set_current_debug_location(loc);
}
// Add args to scope
@ -548,7 +534,7 @@ fn build_list_eq_help<'a, 'ctx, 'env>(
let builder = env.builder;
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::default());
let ptr1 = load_list_ptr(env.builder, list1, ptr_type);
let ptr2 = load_list_ptr(env.builder, list2, ptr_type);
@ -605,7 +591,6 @@ fn build_list_eq_help<'a, 'ctx, 'env>(
elem2,
element_layout,
element_layout,
when_recursive,
)
.into_int_value();
@ -646,16 +631,14 @@ fn build_struct_eq<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_interner: &mut STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
struct_layout: InLayout<'a>,
field_layouts: &'a [InLayout<'a>],
when_recursive: WhenRecursive<'a>,
struct1: StructValue<'ctx>,
struct2: StructValue<'ctx>,
) -> BasicValueEnum<'ctx> {
let block = env.builder.get_insert_block().expect("to be in a function");
let di_location = env.builder.get_current_debug_location().unwrap();
let struct_layout = layout_interner.insert(Layout::struct_no_name_order(field_layouts));
let symbol = Symbol::GENERIC_EQ;
let fn_name = layout_ids
.get(symbol, &struct_layout)
@ -678,7 +661,6 @@ fn build_struct_eq<'a, 'ctx, 'env>(
layout_interner,
layout_ids,
function_value,
when_recursive,
field_layouts,
);
@ -687,8 +669,7 @@ fn build_struct_eq<'a, 'ctx, 'env>(
};
env.builder.position_at_end(block);
env.builder
.set_current_debug_location(env.context, di_location);
env.builder.set_current_debug_location(di_location);
let call = env
.builder
.build_call(function, &[struct1.into(), struct2.into()], "struct_eq");
@ -703,7 +684,6 @@ fn build_struct_eq_help<'a, 'ctx, 'env>(
layout_interner: &mut STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
parent: FunctionValue<'ctx>,
when_recursive: WhenRecursive<'a>,
field_layouts: &[InLayout<'a>],
) {
let ctx = env.context;
@ -727,7 +707,7 @@ fn build_struct_eq_help<'a, 'ctx, 'env>(
/* current_scope */ lexical_block.as_debug_info_scope(),
/* inlined_at */ None,
);
builder.set_current_debug_location(ctx, loc);
builder.set_current_debug_location(loc);
}
// Add args to scope
@ -761,42 +741,40 @@ fn build_struct_eq_help<'a, 'ctx, 'env>(
.build_extract_value(struct2, index as u32, "eq_field")
.unwrap();
let are_equal = if let Layout::RecursivePointer(_) = layout_interner.get(*field_layout) {
match &when_recursive {
WhenRecursive::Unreachable => {
unreachable!("The current layout should not be recursive, but is")
}
WhenRecursive::Loop(union_layout) => {
let field_layout = layout_interner.insert(Layout::Union(*union_layout));
let are_equal = if let Layout::RecursivePointer(rec_layout) =
layout_interner.get(*field_layout)
{
debug_assert!(
matches!(layout_interner.get(rec_layout), Layout::Union(union_layout) if !matches!(union_layout, UnionLayout::NonRecursive(..)))
);
let bt = basic_type_from_layout(env, layout_interner, field_layout);
let field_layout = rec_layout;
// cast the i64 pointer to a pointer to block of memory
let field1_cast = env.builder.build_pointer_cast(
field1.into_pointer_value(),
bt.into_pointer_type(),
"i64_to_opaque",
);
let bt = basic_type_from_layout(env, layout_interner, field_layout);
let field2_cast = env.builder.build_pointer_cast(
field2.into_pointer_value(),
bt.into_pointer_type(),
"i64_to_opaque",
);
// cast the i64 pointer to a pointer to block of memory
let field1_cast = env.builder.build_pointer_cast(
field1.into_pointer_value(),
bt.into_pointer_type(),
"i64_to_opaque",
);
build_eq(
env,
layout_interner,
layout_ids,
field1_cast.into(),
field2_cast.into(),
field_layout,
field_layout,
WhenRecursive::Loop(*union_layout),
)
.into_int_value()
}
}
let field2_cast = env.builder.build_pointer_cast(
field2.into_pointer_value(),
bt.into_pointer_type(),
"i64_to_opaque",
);
build_eq(
env,
layout_interner,
layout_ids,
field1_cast.into(),
field2_cast.into(),
field_layout,
field_layout,
)
.into_int_value()
} 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");
@ -808,7 +786,6 @@ fn build_struct_eq_help<'a, 'ctx, 'env>(
rhs,
*field_layout,
*field_layout,
when_recursive,
)
.into_int_value()
};
@ -839,7 +816,7 @@ fn build_tag_eq<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_interner: &mut STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
when_recursive: WhenRecursive<'a>,
tag_layout: InLayout<'a>,
union_layout: &UnionLayout<'a>,
tag1: BasicValueEnum<'ctx>,
tag2: BasicValueEnum<'ctx>,
@ -847,7 +824,6 @@ fn build_tag_eq<'a, 'ctx, 'env>(
let block = env.builder.get_insert_block().expect("to be in a function");
let di_location = env.builder.get_current_debug_location().unwrap();
let tag_layout = layout_interner.insert(Layout::Union(*union_layout));
let symbol = Symbol::GENERIC_EQ;
let fn_name = layout_ids
.get(symbol, &tag_layout)
@ -869,7 +845,6 @@ fn build_tag_eq<'a, 'ctx, 'env>(
env,
layout_interner,
layout_ids,
when_recursive,
function_value,
union_layout,
);
@ -879,8 +854,7 @@ fn build_tag_eq<'a, 'ctx, 'env>(
};
env.builder.position_at_end(block);
env.builder
.set_current_debug_location(env.context, di_location);
env.builder.set_current_debug_location(di_location);
let call = env
.builder
.build_call(function, &[tag1.into(), tag2.into()], "tag_eq");
@ -894,7 +868,6 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_interner: &mut STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
when_recursive: WhenRecursive<'a>,
parent: FunctionValue<'ctx>,
union_layout: &UnionLayout<'a>,
) {
@ -919,7 +892,7 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
/* current_scope */ lexical_block.as_debug_info_scope(),
/* inlined_at */ None,
);
builder.set_current_debug_location(ctx, loc);
builder.set_current_debug_location(loc);
}
// Add args to scope
@ -999,12 +972,14 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
let block = env.context.append_basic_block(parent, "tag_id_modify");
env.builder.position_at_end(block);
let struct_layout =
layout_interner.insert(Layout::struct_no_name_order(field_layouts));
let answer = eq_ptr_to_struct(
env,
layout_interner,
layout_ids,
union_layout,
Some(when_recursive),
struct_layout,
field_layouts,
tag1,
tag2,
@ -1070,12 +1045,14 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
let block = env.context.append_basic_block(parent, "tag_id_modify");
env.builder.position_at_end(block);
let struct_layout =
layout_interner.insert(Layout::struct_no_name_order(field_layouts));
let answer = eq_ptr_to_struct(
env,
layout_interner,
layout_ids,
union_layout,
None,
struct_layout,
field_layouts,
tag1,
tag2,
@ -1131,12 +1108,13 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
env.builder.position_at_end(compare_other);
let struct_layout = layout_interner.insert(Layout::struct_no_name_order(other_fields));
let answer = eq_ptr_to_struct(
env,
layout_interner,
layout_ids,
union_layout,
None,
struct_layout,
other_fields,
tag1.into_pointer_value(),
tag2.into_pointer_value(),
@ -1229,12 +1207,14 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
let block = env.context.append_basic_block(parent, "tag_id_modify");
env.builder.position_at_end(block);
let struct_layout =
layout_interner.insert(Layout::struct_no_name_order(field_layouts));
let answer = eq_ptr_to_struct(
env,
layout_interner,
layout_ids,
union_layout,
None,
struct_layout,
field_layouts,
tag1,
tag2,
@ -1268,12 +1248,13 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
env.builder.position_at_end(compare_fields);
let struct_layout = layout_interner.insert(Layout::struct_no_name_order(field_layouts));
let answer = eq_ptr_to_struct(
env,
layout_interner,
layout_ids,
union_layout,
None,
struct_layout,
field_layouts,
tag1.into_pointer_value(),
tag2.into_pointer_value(),
@ -1288,27 +1269,24 @@ fn eq_ptr_to_struct<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_interner: &mut STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
union_layout: &UnionLayout<'a>,
opt_when_recursive: Option<WhenRecursive<'a>>,
struct_layout: InLayout<'a>,
field_layouts: &'a [InLayout<'a>],
tag1: PointerValue<'ctx>,
tag2: PointerValue<'ctx>,
) -> IntValue<'ctx> {
let struct_layout = layout_interner.insert(Layout::struct_no_name_order(field_layouts));
let wrapper_type = basic_type_from_layout(env, layout_interner, struct_layout);
debug_assert!(wrapper_type.is_struct_type());
// cast the opaque pointer to a pointer of the correct shape
let struct1_ptr = env.builder.build_pointer_cast(
tag1,
wrapper_type.ptr_type(AddressSpace::Generic),
wrapper_type.ptr_type(AddressSpace::default()),
"opaque_to_correct",
);
let struct2_ptr = env.builder.build_pointer_cast(
tag2,
wrapper_type.ptr_type(AddressSpace::Generic),
wrapper_type.ptr_type(AddressSpace::default()),
"opaque_to_correct",
);
@ -1326,8 +1304,8 @@ fn eq_ptr_to_struct<'a, 'ctx, 'env>(
env,
layout_interner,
layout_ids,
struct_layout,
field_layouts,
opt_when_recursive.unwrap_or(WhenRecursive::Loop(*union_layout)),
struct1,
struct2,
)
@ -1340,7 +1318,6 @@ fn build_box_eq<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_interner: &mut STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
when_recursive: WhenRecursive<'a>,
box_layout: InLayout<'a>,
inner_layout: InLayout<'a>,
tag1: BasicValueEnum<'ctx>,
@ -1370,7 +1347,6 @@ fn build_box_eq<'a, 'ctx, 'env>(
env,
layout_interner,
layout_ids,
when_recursive,
function_value,
inner_layout,
);
@ -1380,8 +1356,7 @@ fn build_box_eq<'a, 'ctx, 'env>(
};
env.builder.position_at_end(block);
env.builder
.set_current_debug_location(env.context, di_location);
env.builder.set_current_debug_location(di_location);
let call = env
.builder
.build_call(function, &[tag1.into(), tag2.into()], "tag_eq");
@ -1395,7 +1370,6 @@ fn build_box_eq_help<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_interner: &mut STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
when_recursive: WhenRecursive<'a>,
parent: FunctionValue<'ctx>,
inner_layout: InLayout<'a>,
) {
@ -1420,7 +1394,7 @@ fn build_box_eq_help<'a, 'ctx, 'env>(
/* current_scope */ lexical_block.as_debug_info_scope(),
/* inlined_at */ None,
);
builder.set_current_debug_location(ctx, loc);
builder.set_current_debug_location(loc);
}
// Add args to scope
@ -1472,7 +1446,6 @@ fn build_box_eq_help<'a, 'ctx, 'env>(
value2,
inner_layout,
inner_layout,
when_recursive,
);
env.builder.build_return(Some(&is_equal));

View file

@ -18,7 +18,9 @@ fn basic_type_from_record<'a, 'ctx, 'env>(
let mut field_types = Vec::with_capacity_in(fields.len(), env.arena);
for field_layout in fields.iter() {
field_types.push(basic_type_from_layout(env, layout_interner, *field_layout));
let typ = basic_type_from_layout(env, layout_interner, *field_layout);
field_types.push(typ);
}
env.context
@ -44,13 +46,13 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>(
Boxed(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::default()).into()
}
Union(union_layout) => basic_type_from_union_layout(env, layout_interner, &union_layout),
RecursivePointer(_) => env
.context
.i64_type()
.ptr_type(AddressSpace::Generic)
.ptr_type(AddressSpace::default())
.as_basic_type_enum(),
Builtin(builtin) => basic_type_from_builtin(env, &builtin),
@ -65,6 +67,7 @@ pub fn struct_type_from_union_layout<'a, 'ctx, 'env>(
use UnionLayout::*;
match union_layout {
NonRecursive([]) => env.context.struct_type(&[], false),
NonRecursive(tags) => {
RocUnion::tagged_from_slices(layout_interner, env.context, tags, env.target_info)
.struct_type()
@ -109,7 +112,7 @@ pub fn basic_type_from_union_layout<'a, 'ctx, 'env>(
Recursive(_)
| NonNullableUnwrapped(_)
| NullableWrapped { .. }
| NullableUnwrapped { .. } => struct_type.ptr_type(AddressSpace::Generic).into(),
| NullableUnwrapped { .. } => struct_type.ptr_type(AddressSpace::default()).into(),
}
}
@ -158,7 +161,7 @@ pub fn argument_type_from_layout<'a, 'ctx, 'env>(
let base = basic_type_from_layout(env, layout_interner, layout);
if layout_interner.is_passed_by_reference(layout) {
base.ptr_type(AddressSpace::Generic).into()
base.ptr_type(AddressSpace::default()).into()
} else {
base
}
@ -176,7 +179,7 @@ pub fn argument_type_from_union_layout<'a, 'ctx, 'env>(
let heap_type = basic_type_from_union_layout(env, layout_interner, union_layout);
if let UnionLayout::NonRecursive(_) = union_layout {
heap_type.ptr_type(AddressSpace::Generic).into()
heap_type.ptr_type(AddressSpace::default()).into()
} else {
heap_type
}
@ -300,7 +303,8 @@ impl<'ctx> RocUnion<'ctx> {
target_info: TargetInfo,
) -> Self {
let tag_type = match layouts.len() {
0..=255 => TagType::I8,
0 => unreachable!("zero-element tag union is not represented as a RocUnion"),
1..=255 => TagType::I8,
_ => TagType::I16,
};
@ -322,6 +326,10 @@ impl<'ctx> RocUnion<'ctx> {
Self::new(context, target_info, data_align, data_width, None)
}
pub fn data_width(&self) -> u32 {
self.data_width
}
pub fn tag_alignment(&self) -> u32 {
let tag_id_alignment = match self.tag_type {
None => 0,
@ -375,7 +383,7 @@ impl<'ctx> RocUnion<'ctx> {
let cast_pointer = env.builder.build_pointer_cast(
data_buffer,
data.get_type().ptr_type(AddressSpace::Generic),
data.get_type().ptr_type(AddressSpace::default()),
"to_data_ptr",
);
@ -436,7 +444,7 @@ pub fn zig_dec_type<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> StructType<'ct
}
pub fn zig_has_tag_id_type<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> StructType<'ctx> {
let u8_ptr_t = env.context.i8_type().ptr_type(AddressSpace::Generic);
let u8_ptr_t = env.context.i8_type().ptr_type(AddressSpace::default());
env.context
.struct_type(&[env.context.bool_type().into(), u8_ptr_t.into()], false)

View file

@ -9,6 +9,7 @@ use inkwell::types::{BasicMetadataTypeEnum, BasicType, BasicTypeEnum};
use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue};
use inkwell::AddressSpace;
use roc_builtins::bitcode;
use roc_error_macros::internal_error;
use roc_module::symbol::Symbol;
use roc_mono::ir::LookupType;
use roc_mono::layout::{
@ -19,7 +20,7 @@ use roc_region::all::Region;
use super::build::BuilderExt;
use super::build::{
add_func, load_roc_value, load_symbol_and_layout, use_roc_value, FunctionSpec, LlvmBackendMode,
Scope, WhenRecursive,
Scope,
};
use super::convert::struct_type_from_union_layout;
@ -98,7 +99,7 @@ fn read_state<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
ptr: PointerValue<'ctx>,
) -> (IntValue<'ctx>, IntValue<'ctx>) {
let ptr_type = env.ptr_int().ptr_type(AddressSpace::Generic);
let ptr_type = env.ptr_int().ptr_type(AddressSpace::default());
let ptr = env.builder.build_pointer_cast(ptr, ptr_type, "");
let one = env.ptr_int().const_int(1, false);
@ -118,7 +119,7 @@ fn write_state<'a, 'ctx, 'env>(
count: IntValue<'ctx>,
offset: IntValue<'ctx>,
) {
let ptr_type = env.ptr_int().ptr_type(AddressSpace::Generic);
let ptr_type = env.ptr_int().ptr_type(AddressSpace::default());
let ptr = env.builder.build_pointer_cast(ptr, ptr_type, "");
let one = env.ptr_int().const_int(1, false);
@ -128,6 +129,15 @@ fn write_state<'a, 'ctx, 'env>(
env.builder.build_store(offset_ptr, offset);
}
fn offset_add<'ctx>(
builder: &Builder<'ctx>,
current: IntValue<'ctx>,
extra: u32,
) -> IntValue<'ctx> {
let intval = current.get_type().const_int(extra as _, false);
builder.build_int_add(current, intval, "offset_add")
}
pub(crate) fn notify_parent_expect(env: &Env, shared_memory: &SharedMemoryPointer) {
let func = env
.module
@ -220,7 +230,6 @@ pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
cursors,
value,
layout,
WhenRecursive::Unreachable,
);
offset = extra_offset;
@ -252,7 +261,7 @@ pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
)
};
let u32_ptr = env.context.i32_type().ptr_type(AddressSpace::Generic);
let u32_ptr = env.context.i32_type().ptr_type(AddressSpace::default());
let ptr = env
.builder
.build_pointer_cast(ptr, u32_ptr, "cast_ptr_type");
@ -286,7 +295,6 @@ fn build_clone<'a, 'ctx, 'env>(
cursors: Cursors<'ctx>,
value: BasicValueEnum<'ctx>,
layout: InLayout<'a>,
when_recursive: WhenRecursive<'a>,
) -> IntValue<'ctx> {
match layout_interner.get(layout) {
Layout::Builtin(builtin) => build_clone_builtin(
@ -297,7 +305,6 @@ fn build_clone<'a, 'ctx, 'env>(
cursors,
value,
builtin,
when_recursive,
),
Layout::Struct { field_layouts, .. } => build_clone_struct(
@ -308,7 +315,6 @@ fn build_clone<'a, 'ctx, 'env>(
cursors,
value,
field_layouts,
when_recursive,
),
// Since we will never actually display functions (and hence lambda sets)
@ -326,7 +332,7 @@ fn build_clone<'a, 'ctx, 'env>(
)
};
let ptr_type = value.get_type().ptr_type(AddressSpace::Generic);
let ptr_type = value.get_type().ptr_type(AddressSpace::default());
let ptr = env
.builder
.build_pointer_cast(ptr, ptr_type, "cast_ptr_type");
@ -343,7 +349,6 @@ fn build_clone<'a, 'ctx, 'env>(
cursors,
value,
union_layout,
WhenRecursive::Loop(union_layout),
)
}
}
@ -376,39 +381,39 @@ fn build_clone<'a, 'ctx, 'env>(
cursors,
value,
inner_layout,
when_recursive,
)
}
Layout::RecursivePointer(_) => match when_recursive {
WhenRecursive::Unreachable => {
unreachable!("recursion pointers should never be compared directly")
}
Layout::RecursivePointer(rec_layout) => {
let layout = rec_layout;
WhenRecursive::Loop(union_layout) => {
let layout = layout_interner.insert(Layout::Union(union_layout));
let bt = basic_type_from_layout(env, layout_interner, layout);
let bt = basic_type_from_layout(env, layout_interner, layout);
// cast the i64 pointer to a pointer to block of memory
let field1_cast = env.builder.build_pointer_cast(
value.into_pointer_value(),
bt.into_pointer_type(),
"i64_to_opaque",
);
// cast the i64 pointer to a pointer to block of memory
let field1_cast = env.builder.build_pointer_cast(
value.into_pointer_value(),
bt.into_pointer_type(),
"i64_to_opaque",
);
let union_layout = match layout_interner.get(rec_layout) {
Layout::Union(union_layout) => {
debug_assert!(!matches!(union_layout, UnionLayout::NonRecursive(..)));
union_layout
}
_ => internal_error!(),
};
build_clone_tag(
env,
layout_interner,
layout_ids,
ptr,
cursors,
field1_cast.into(),
union_layout,
WhenRecursive::Loop(union_layout),
)
}
},
build_clone_tag(
env,
layout_interner,
layout_ids,
ptr,
cursors,
field1_cast.into(),
union_layout,
)
}
}
}
@ -420,7 +425,6 @@ fn build_clone_struct<'a, 'ctx, 'env>(
cursors: Cursors<'ctx>,
value: BasicValueEnum<'ctx>,
field_layouts: &[InLayout<'a>],
when_recursive: WhenRecursive<'a>,
) -> IntValue<'ctx> {
let layout = Layout::struct_no_name_order(field_layouts);
@ -447,7 +451,6 @@ fn build_clone_struct<'a, 'ctx, 'env>(
cursors,
field,
*field_layout,
when_recursive,
);
let field_width = env
@ -472,7 +475,6 @@ fn build_clone_tag<'a, 'ctx, 'env>(
cursors: Cursors<'ctx>,
value: BasicValueEnum<'ctx>,
union_layout: UnionLayout<'a>,
when_recursive: WhenRecursive<'a>,
) -> IntValue<'ctx> {
let layout = layout_interner.insert(Layout::Union(union_layout));
let layout_id = layout_ids.get(Symbol::CLONE, &layout);
@ -486,7 +488,10 @@ fn build_clone_tag<'a, 'ctx, 'env>(
let function_type = env.ptr_int().fn_type(
&[
env.context.i8_type().ptr_type(AddressSpace::Generic).into(),
env.context
.i8_type()
.ptr_type(AddressSpace::default())
.into(),
env.ptr_int().into(),
env.ptr_int().into(),
BasicMetadataTypeEnum::from(value.get_type()),
@ -512,13 +517,11 @@ fn build_clone_tag<'a, 'ctx, 'env>(
layout_interner,
layout_ids,
union_layout,
when_recursive,
function_value,
);
env.builder.position_at_end(block);
env.builder
.set_current_debug_location(env.context, di_location);
env.builder.set_current_debug_location(di_location);
function_value
}
@ -563,19 +566,68 @@ fn load_tag_data<'a, 'ctx, 'env>(
let data_ptr = env.builder.build_pointer_cast(
raw_data_ptr,
tag_type.ptr_type(AddressSpace::Generic),
tag_type.ptr_type(AddressSpace::default()),
"data_ptr",
);
env.builder.new_build_load(tag_type, data_ptr, "load_data")
}
fn clone_tag_payload_and_id<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_interner: &mut STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
ptr: PointerValue<'ctx>,
cursors: Cursors<'ctx>,
roc_union: RocUnion<'ctx>,
tag_id: usize,
payload_in_layout: InLayout<'a>,
opaque_payload_ptr: PointerValue<'ctx>,
) -> IntValue<'ctx> {
let payload_type = basic_type_from_layout(env, layout_interner, payload_in_layout);
let payload_ptr = env.builder.build_pointer_cast(
opaque_payload_ptr,
payload_type.ptr_type(AddressSpace::default()),
"cast_payload_ptr",
);
let payload = env
.builder
.new_build_load(payload_type, payload_ptr, "payload");
// NOTE: `answer` includes any extra_offset that the tag payload may have needed
// (e.g. because it includes a list). That is what we want to return, but not what
// we need to write the padding and offset of this tag
let answer = build_clone(
env,
layout_interner,
layout_ids,
ptr,
cursors,
payload,
payload_in_layout,
);
// include padding between data and tag id
let tag_id_internal_offset = roc_union.data_width();
let tag_id_offset = offset_add(env.builder, cursors.offset, tag_id_internal_offset);
// write the tag id
let value = env.context.i8_type().const_int(tag_id as _, false);
build_copy(env, ptr, tag_id_offset, value.into());
// NOTE: padding after tag id (is taken care of by the cursor)
answer
}
fn build_clone_tag_help<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_interner: &mut STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
union_layout: UnionLayout<'a>,
when_recursive: WhenRecursive<'a>,
fn_val: FunctionValue<'ctx>,
) {
use bumpalo::collections::Vec;
@ -629,29 +681,37 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
let block = env.context.append_basic_block(parent, "tag_id_modify");
env.builder.position_at_end(block);
let layout = layout_interner.insert(Layout::struct_no_name_order(field_layouts));
let layout = layout_interner.insert(Layout::struct_no_name_order(
env.arena.alloc([layout, union_layout.tag_id_layout()]),
));
let basic_type = basic_type_from_layout(env, layout_interner, layout);
let data = load_tag_data(
env,
let roc_union = RocUnion::tagged_from_slices(
layout_interner,
union_layout,
tag_value.into_pointer_value(),
basic_type,
env.context,
tags,
env.target_info,
);
let answer = build_clone(
// load the tag payload (if any)
let payload_layout = Layout::struct_no_name_order(field_layouts);
let payload_in_layout = layout_interner.insert(payload_layout);
let opaque_payload_ptr = env
.builder
.new_build_struct_gep(
roc_union.struct_type(),
tag_value.into_pointer_value(),
RocUnion::TAG_DATA_INDEX,
"data_buffer",
)
.unwrap();
let answer = clone_tag_payload_and_id(
env,
layout_interner,
layout_ids,
ptr,
cursors,
data,
layout,
when_recursive,
roc_union,
tag_id,
payload_in_layout,
opaque_payload_ptr,
);
env.builder.build_return(Some(&answer));
@ -712,17 +772,8 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
),
};
let when_recursive = WhenRecursive::Loop(union_layout);
let answer = build_clone(
env,
layout_interner,
layout_ids,
ptr,
cursors,
data,
layout,
when_recursive,
);
let answer =
build_clone(env, layout_interner, layout_ids, ptr, cursors, data, layout);
env.builder.build_return(Some(&answer));
@ -762,17 +813,7 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
let data = load_tag_data(env, layout_interner, union_layout, tag_value, basic_type);
let when_recursive = WhenRecursive::Loop(union_layout);
let answer = build_clone(
env,
layout_interner,
layout_ids,
ptr,
cursors,
data,
layout,
when_recursive,
);
let answer = build_clone(env, layout_interner, layout_ids, ptr, cursors, data, layout);
env.builder.build_return(Some(&answer));
}
@ -831,17 +872,8 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
let data =
load_tag_data(env, layout_interner, union_layout, tag_value, basic_type);
let when_recursive = WhenRecursive::Loop(union_layout);
let answer = build_clone(
env,
layout_interner,
layout_ids,
ptr,
cursors,
data,
layout,
when_recursive,
);
let answer =
build_clone(env, layout_interner, layout_ids, ptr, cursors, data, layout);
env.builder.build_return(Some(&answer));
@ -917,17 +949,8 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
basic_type,
);
let when_recursive = WhenRecursive::Loop(union_layout);
let answer = build_clone(
env,
layout_interner,
layout_ids,
ptr,
cursors,
data,
layout,
when_recursive,
);
let answer =
build_clone(env, layout_interner, layout_ids, ptr, cursors, data, layout);
env.builder.build_return(Some(&answer));
}
@ -978,7 +1001,7 @@ fn build_copy<'a, 'ctx, 'env>(
)
};
let ptr_type = value.get_type().ptr_type(AddressSpace::Generic);
let ptr_type = value.get_type().ptr_type(AddressSpace::default());
let ptr = env
.builder
.build_pointer_cast(ptr, ptr_type, "cast_ptr_type");
@ -997,7 +1020,6 @@ fn build_clone_builtin<'a, 'ctx, 'env>(
cursors: Cursors<'ctx>,
value: BasicValueEnum<'ctx>,
builtin: Builtin<'a>,
when_recursive: WhenRecursive<'a>,
) -> IntValue<'ctx> {
use Builtin::*;
@ -1051,7 +1073,7 @@ fn build_clone_builtin<'a, 'ctx, 'env>(
let dest = pointer_at_offset(bd, env.context.i8_type(), ptr, elements_start_offset);
let src = bd.build_pointer_cast(
elements,
env.context.i8_type().ptr_type(AddressSpace::Generic),
env.context.i8_type().ptr_type(AddressSpace::default()),
"to_bytes_pointer",
);
bd.build_memcpy(dest, 1, src, 1, elements_width).unwrap();
@ -1061,7 +1083,7 @@ fn build_clone_builtin<'a, 'ctx, 'env>(
let element_type = basic_type_from_layout(env, layout_interner, elem);
let elements = bd.build_pointer_cast(
elements,
element_type.ptr_type(AddressSpace::Generic),
element_type.ptr_type(AddressSpace::default()),
"elements",
);
@ -1102,7 +1124,6 @@ fn build_clone_builtin<'a, 'ctx, 'env>(
cursors,
element,
elem,
when_recursive,
);
bd.build_store(rest_offset, new_offset);

View file

@ -4,7 +4,6 @@ use crate::llvm::build::{CCReturn, Env, FunctionSpec};
use crate::llvm::convert::zig_str_type;
use inkwell::module::Linkage;
use inkwell::types::BasicType;
use inkwell::values::BasicValue;
use inkwell::AddressSpace;
use roc_builtins::bitcode;
@ -19,7 +18,7 @@ pub fn add_default_roc_externs(env: &Env<'_, '_, '_>) {
let builder = env.builder;
let usize_type = env.ptr_int();
let i8_ptr_type = ctx.i8_type().ptr_type(AddressSpace::Generic);
let i8_ptr_type = ctx.i8_type().ptr_type(AddressSpace::default());
match env.mode {
super::build::LlvmBackendMode::CliTest => {
@ -198,6 +197,11 @@ pub fn add_sjlj_roc_panic(env: &Env<'_, '_, '_>) {
let mut params = fn_val.get_param_iter();
let roc_str_arg = params.next().unwrap();
// normally, roc_panic is marked as external so it can be provided by the host. But when we
// define it here in LLVM IR, we never want it to be linked by the host (that would
// overwrite which implementation is used.
fn_val.set_linkage(Linkage::Internal);
let tag_id_arg = params.next().unwrap();
debug_assert!(params.next().is_none());
@ -271,7 +275,7 @@ pub fn build_longjmp_call(env: &Env) {
// Call the LLVM-intrinsic longjmp: `void @llvm.eh.sjlj.longjmp(i8* %setjmp_buf)`
let jmp_buf_i8p = env.builder.build_pointer_cast(
jmp_buf,
env.context.i8_type().ptr_type(AddressSpace::Generic),
env.context.i8_type().ptr_type(AddressSpace::default()),
"jmp_buf i8*",
);
let _call = env.build_intrinsic_call(LLVM_LONGJMP, &[jmp_buf_i8p.into()]);

View file

@ -75,7 +75,7 @@ pub(crate) fn add_intrinsics<'ctx>(ctx: &'ctx Context, module: &Module<'ctx>) {
// https://releases.llvm.org/10.0.0/docs/LangRef.html#standard-c-library-intrinsics
let i1_type = ctx.bool_type();
let i8_type = ctx.i8_type();
let i8_ptr_type = i8_type.ptr_type(AddressSpace::Generic);
let i8_ptr_type = i8_type.ptr_type(AddressSpace::default());
let i32_type = ctx.i32_type();
let void_type = ctx.void_type();

View file

@ -13,6 +13,7 @@ use roc_module::{low_level::LowLevel, symbol::Symbol};
use roc_mono::{
ir::HigherOrderLowLevel,
layout::{Builtin, InLayout, LambdaSet, Layout, LayoutIds, LayoutInterner, STLayoutInterner},
list_element_layout,
};
use roc_target::PtrWidth;
@ -27,10 +28,10 @@ use crate::llvm::{
load_roc_value, roc_function_call, BuilderExt, RocReturn,
},
build_list::{
list_append_unsafe, list_capacity, list_concat, list_drop_at, list_get_unsafe, list_len,
list_map, list_map2, list_map3, list_map4, list_prepend, list_replace_unsafe, list_reserve,
list_sort_with, list_sublist, list_swap, list_symbol_to_c_abi, list_with_capacity,
pass_update_mode,
list_append_unsafe, list_concat, list_drop_at, list_get_unsafe, list_len, list_map,
list_map2, list_map3, list_map4, list_prepend, list_release_excess_capacity,
list_replace_unsafe, list_reserve, list_sort_with, list_sublist, list_swap,
list_symbol_to_c_abi, list_with_capacity, pass_update_mode,
},
compare::{generic_eq, generic_neq},
convert::{
@ -49,15 +50,6 @@ use super::{
convert::zig_dec_type,
};
macro_rules! list_element_layout {
($interner:expr, $list_layout:expr) => {
match $interner.get($list_layout) {
Layout::Builtin(Builtin::List(list_layout)) => list_layout,
_ => unreachable!("invalid list layout"),
}
};
}
pub(crate) fn run_low_level<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_interner: &mut STLayoutInterner<'a>,
@ -256,7 +248,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
let roc_return_type =
basic_type_from_layout(env, layout_interner, layout)
.ptr_type(AddressSpace::Generic);
.ptr_type(AddressSpace::default());
let roc_return_alloca = env.builder.build_pointer_cast(
zig_return_alloca,
@ -497,7 +489,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
let return_type = basic_type_from_layout(env, layout_interner, layout);
let cast_result = env.builder.build_pointer_cast(
result,
return_type.ptr_type(AddressSpace::Generic),
return_type.ptr_type(AddressSpace::default()),
"cast",
);
@ -567,6 +559,18 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
bitcode::STR_RESERVE,
)
}
StrReleaseExcessCapacity => {
// Str.releaseExcessCapacity: Str -> Str
arguments!(string);
call_str_bitcode_fn(
env,
&[string],
&[],
BitcodeReturns::Str,
bitcode::STR_RELEASE_EXCESS_CAPACITY,
)
}
StrAppendScalar => {
// Str.appendScalar : Str, U32 -> Str
arguments!(string, capacity);
@ -640,10 +644,16 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
list_len(env.builder, list.into_struct_value()).into()
}
ListGetCapacity => {
// List.capacity : List * -> Nat
// List.capacity: List a -> Nat
arguments!(list);
list_capacity(env.builder, list.into_struct_value()).into()
call_list_bitcode_fn(
env,
&[list.into_struct_value()],
&[],
BitcodeReturns::Basic,
bitcode::LIST_CAPACITY,
)
}
ListWithCapacity => {
// List.withCapacity : Nat -> List a
@ -709,6 +719,15 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
update_mode,
)
}
ListReleaseExcessCapacity => {
// List.releaseExcessCapacity: List elem -> List elem
debug_assert_eq!(args.len(), 1);
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
let element_layout = list_element_layout!(layout_interner, list_layout);
list_release_excess_capacity(env, layout_interner, list, element_layout, update_mode)
}
ListSwap => {
// List.swap : List elem, Nat, Nat -> List elem
debug_assert_eq!(args.len(), 3);
@ -856,9 +875,24 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
_ => unreachable!(),
}
}
NumAbs | NumNeg | NumRound | NumSqrtUnchecked | NumLogUnchecked | NumSin | NumCos
| NumCeiling | NumFloor | NumToFrac | NumIsFinite | NumAtan | NumAcos | NumAsin
| NumToIntChecked => {
NumAbs
| NumNeg
| NumRound
| NumSqrtUnchecked
| NumLogUnchecked
| NumSin
| NumCos
| NumCeiling
| NumFloor
| NumToFrac
| NumIsFinite
| NumAtan
| NumAcos
| NumAsin
| NumToIntChecked
| NumCountLeadingZeroBits
| NumCountTrailingZeroBits
| NumCountOneBits => {
arguments_with_layouts!((arg, arg_layout));
match layout_interner.get(arg_layout) {
@ -922,6 +956,28 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
bitcode::NUM_BYTES_TO_U32,
)
}
NumBytesToU64 => {
arguments!(list, position);
call_list_bitcode_fn(
env,
&[list.into_struct_value()],
&[position],
BitcodeReturns::Basic,
bitcode::NUM_BYTES_TO_U64,
)
}
NumBytesToU128 => {
arguments!(list, position);
call_list_bitcode_fn(
env,
&[list.into_struct_value()],
&[position],
BitcodeReturns::Basic,
bitcode::NUM_BYTES_TO_U128,
)
}
NumCompare => {
arguments_with_layouts!((lhs_arg, lhs_layout), (rhs_arg, rhs_layout));
@ -1663,7 +1719,7 @@ fn dec_alloca<'a, 'ctx, 'env>(
let ptr = env.builder.build_pointer_cast(
alloca,
value.get_type().ptr_type(AddressSpace::Generic),
value.get_type().ptr_type(AddressSpace::default()),
"cast_to_i128_ptr",
);
@ -2013,7 +2069,7 @@ fn build_int_unary_op<'a, 'ctx, 'env>(
let roc_return_type =
basic_type_from_layout(env, layout_interner, return_layout)
.ptr_type(AddressSpace::Generic);
.ptr_type(AddressSpace::default());
let roc_return_alloca = env.builder.build_pointer_cast(
zig_return_alloca,
@ -2053,6 +2109,19 @@ fn build_int_unary_op<'a, 'ctx, 'env>(
complex_bitcast_check_size(env, result, return_type.into(), "cast_bitpacked")
}
}
NumCountLeadingZeroBits => call_bitcode_fn(
env,
&[arg.into()],
&bitcode::NUM_COUNT_LEADING_ZERO_BITS[arg_width],
),
NumCountTrailingZeroBits => call_bitcode_fn(
env,
&[arg.into()],
&bitcode::NUM_COUNT_TRAILING_ZERO_BITS[arg_width],
),
NumCountOneBits => {
call_bitcode_fn(env, &[arg.into()], &bitcode::NUM_COUNT_ONE_BITS[arg_width])
}
_ => {
unreachable!("Unrecognized int unary operation: {:?}", op);
}

View file

@ -3,17 +3,18 @@ use crate::llvm::bitcode::call_void_bitcode_fn;
use crate::llvm::build::BuilderExt;
use crate::llvm::build::{
add_func, cast_basic_basic, get_tag_id, tag_pointer_clear_tag_id, use_roc_value, Env,
WhenRecursive, FAST_CALL_CONV,
FAST_CALL_CONV,
};
use crate::llvm::build_list::{incrementing_elem_loop, list_capacity, load_list};
use crate::llvm::build_list::{
incrementing_elem_loop, list_capacity_or_ref_ptr, list_refcount_ptr, load_list,
};
use crate::llvm::build_str::str_refcount_ptr;
use crate::llvm::convert::{basic_type_from_layout, zig_str_type, RocUnion};
use bumpalo::collections::Vec;
use inkwell::basic_block::BasicBlock;
use inkwell::module::Linkage;
use inkwell::types::{AnyTypeEnum, BasicMetadataTypeEnum, BasicType, BasicTypeEnum};
use inkwell::values::{
BasicValue, BasicValueEnum, FunctionValue, IntValue, PointerValue, StructValue,
};
use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue};
use inkwell::{AddressSpace, IntPredicate};
use roc_module::symbol::Interns;
use roc_module::symbol::Symbol;
@ -40,7 +41,7 @@ impl<'ctx> PointerToRefcount<'ctx> {
let value = env.builder.build_pointer_cast(
ptr,
refcount_type.ptr_type(AddressSpace::Generic),
refcount_type.ptr_type(AddressSpace::default()),
"to_refcount_ptr",
);
@ -54,7 +55,7 @@ impl<'ctx> PointerToRefcount<'ctx> {
let builder = env.builder;
// pointer to usize
let refcount_type = env.ptr_int();
let refcount_ptr_type = refcount_type.ptr_type(AddressSpace::Generic);
let refcount_ptr_type = refcount_type.ptr_type(AddressSpace::default());
let ptr_as_usize_ptr =
builder.build_pointer_cast(data_ptr, refcount_ptr_type, "as_usize_ptr");
@ -75,16 +76,6 @@ impl<'ctx> PointerToRefcount<'ctx> {
}
}
fn from_list_wrapper(env: &Env<'_, 'ctx, '_>, list_wrapper: StructValue<'ctx>) -> Self {
let data_ptr = env
.builder
.build_extract_value(list_wrapper, Builtin::WRAPPER_PTR, "read_list_ptr")
.unwrap()
.into_pointer_value();
Self::from_ptr_to_data(env, data_ptr)
}
pub fn is_1<'a, 'env>(&self, env: &Env<'a, 'ctx, 'env>) -> IntValue<'ctx> {
let current = self.get_refcount(env);
let one = match env.target_info.ptr_width() {
@ -148,7 +139,7 @@ impl<'ctx> PointerToRefcount<'ctx> {
None => {
// inc and dec return void
let fn_type = context.void_type().fn_type(
&[env.ptr_int().ptr_type(AddressSpace::Generic).into()],
&[env.ptr_int().ptr_type(AddressSpace::default()).into()],
false,
);
@ -172,8 +163,7 @@ impl<'ctx> PointerToRefcount<'ctx> {
let refcount_ptr = self.value;
env.builder.position_at_end(block);
env.builder
.set_current_debug_location(env.context, di_location);
env.builder.set_current_debug_location(di_location);
let call = env
.builder
@ -216,7 +206,7 @@ fn incref_pointer<'a, 'ctx, 'env>(
env.builder
.build_pointer_cast(
pointer,
env.ptr_int().ptr_type(AddressSpace::Generic),
env.ptr_int().ptr_type(AddressSpace::default()),
"to_isize_ptr",
)
.into(),
@ -238,7 +228,7 @@ fn decref_pointer<'a, 'ctx, 'env>(
env.builder
.build_pointer_cast(
pointer,
env.ptr_int().ptr_type(AddressSpace::Generic),
env.ptr_int().ptr_type(AddressSpace::default()),
"to_isize_ptr",
)
.into(),
@ -261,7 +251,7 @@ pub fn decref_pointer_check_null<'a, 'ctx, 'env>(
env.builder
.build_pointer_cast(
pointer,
env.context.i8_type().ptr_type(AddressSpace::Generic),
env.context.i8_type().ptr_type(AddressSpace::default()),
"to_i8_ptr",
)
.into(),
@ -277,7 +267,6 @@ fn modify_refcount_struct<'a, 'ctx, 'env>(
layout_ids: &mut LayoutIds<'a>,
layouts: &'a [InLayout<'a>],
mode: Mode,
when_recursive: &WhenRecursive<'a>,
) -> FunctionValue<'ctx> {
let block = env.builder.get_insert_block().expect("to be in a function");
let di_location = env.builder.get_current_debug_location().unwrap();
@ -304,7 +293,6 @@ fn modify_refcount_struct<'a, 'ctx, 'env>(
layout_interner,
layout_ids,
mode,
when_recursive,
layouts,
function_value,
);
@ -314,8 +302,7 @@ fn modify_refcount_struct<'a, 'ctx, 'env>(
};
env.builder.position_at_end(block);
env.builder
.set_current_debug_location(env.context, di_location);
env.builder.set_current_debug_location(di_location);
function
}
@ -326,7 +313,6 @@ fn modify_refcount_struct_help<'a, 'ctx, 'env>(
layout_interner: &mut STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
mode: Mode,
when_recursive: &WhenRecursive<'a>,
layouts: &[InLayout<'a>],
fn_val: FunctionValue<'ctx>,
) {
@ -368,7 +354,6 @@ fn modify_refcount_struct_help<'a, 'ctx, 'env>(
layout_interner,
layout_ids,
mode.to_call_mode(fn_val),
when_recursive,
field_value,
*field_layout,
);
@ -430,7 +415,6 @@ fn modify_refcount_builtin<'a, 'ctx, 'env>(
layout_interner: &mut STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
mode: Mode,
when_recursive: &WhenRecursive<'a>,
layout: InLayout<'a>,
builtin: &Builtin<'a>,
) -> Option<FunctionValue<'ctx>> {
@ -438,14 +422,8 @@ fn modify_refcount_builtin<'a, 'ctx, 'env>(
match builtin {
List(element_layout) => {
let function = modify_refcount_list(
env,
layout_interner,
layout_ids,
mode,
when_recursive,
*element_layout,
);
let function =
modify_refcount_list(env, layout_interner, layout_ids, mode, *element_layout);
Some(function)
}
@ -473,15 +451,7 @@ fn modify_refcount_layout<'a, 'ctx, 'env>(
value: BasicValueEnum<'ctx>,
layout: InLayout<'a>,
) {
modify_refcount_layout_help(
env,
layout_interner,
layout_ids,
call_mode,
&WhenRecursive::Unreachable,
value,
layout,
);
modify_refcount_layout_help(env, layout_interner, layout_ids, call_mode, value, layout);
}
fn modify_refcount_layout_help<'a, 'ctx, 'env>(
@ -489,7 +459,6 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>(
layout_interner: &mut STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
call_mode: CallMode<'ctx>,
when_recursive: &WhenRecursive<'a>,
value: BasicValueEnum<'ctx>,
layout: InLayout<'a>,
) {
@ -498,38 +467,28 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>(
CallMode::Dec => Mode::Dec,
};
let function = match modify_refcount_layout_build_function(
env,
layout_interner,
layout_ids,
mode,
when_recursive,
layout,
) {
Some(f) => f,
None => return,
};
let function =
match modify_refcount_layout_build_function(env, layout_interner, layout_ids, mode, layout)
{
Some(f) => f,
None => return,
};
match layout_interner.get(layout) {
Layout::RecursivePointer(_) => match when_recursive {
WhenRecursive::Unreachable => {
unreachable!("recursion pointers should never be hashed directly")
}
WhenRecursive::Loop(union_layout) => {
let layout = layout_interner.insert(Layout::Union(*union_layout));
Layout::RecursivePointer(rec_layout) => {
let layout = rec_layout;
let bt = basic_type_from_layout(env, layout_interner, layout);
let bt = basic_type_from_layout(env, layout_interner, layout);
// cast the i64 pointer to a pointer to block of memory
let field_cast = env.builder.build_pointer_cast(
value.into_pointer_value(),
bt.into_pointer_type(),
"i64_to_opaque",
);
// cast the i64 pointer to a pointer to block of memory
let field_cast = env.builder.build_pointer_cast(
value.into_pointer_value(),
bt.into_pointer_type(),
"i64_to_opaque",
);
call_help(env, function, call_mode, field_cast.into());
}
},
call_help(env, function, call_mode, field_cast.into());
}
_ => {
call_help(env, function, call_mode, value);
}
@ -568,21 +527,14 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>(
layout_interner: &mut STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
mode: Mode,
when_recursive: &WhenRecursive<'a>,
layout: InLayout<'a>,
) -> Option<FunctionValue<'ctx>> {
use Layout::*;
match layout_interner.get(layout) {
Builtin(builtin) => modify_refcount_builtin(
env,
layout_interner,
layout_ids,
mode,
when_recursive,
layout,
&builtin,
),
Builtin(builtin) => {
modify_refcount_builtin(env, layout_interner, layout_ids, mode, layout, &builtin)
}
Boxed(inner) => {
let function = modify_refcount_boxed(env, layout_interner, layout_ids, mode, inner);
@ -600,27 +552,14 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>(
}
NonRecursive(tags) => {
let function = modify_refcount_nonrecursive(
env,
layout_interner,
layout_ids,
mode,
when_recursive,
tags,
);
let function =
modify_refcount_nonrecursive(env, layout_interner, layout_ids, mode, tags);
Some(function)
}
_ => {
let function = build_rec_union(
env,
layout_interner,
layout_ids,
mode,
&WhenRecursive::Loop(variant),
variant,
);
let function = build_rec_union(env, layout_interner, layout_ids, mode, variant);
Some(function)
}
@ -628,43 +567,30 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>(
}
Struct { field_layouts, .. } => {
let function = modify_refcount_struct(
env,
layout_interner,
layout_ids,
field_layouts,
mode,
when_recursive,
);
let function =
modify_refcount_struct(env, layout_interner, layout_ids, field_layouts, mode);
Some(function)
}
Layout::RecursivePointer(_) => match when_recursive {
WhenRecursive::Unreachable => {
unreachable!("recursion pointers cannot be in/decremented directly")
}
WhenRecursive::Loop(union_layout) => {
let layout = layout_interner.insert(Layout::Union(*union_layout));
Layout::RecursivePointer(rec_layout) => {
let layout = rec_layout;
let function = modify_refcount_layout_build_function(
env,
layout_interner,
layout_ids,
mode,
when_recursive,
layout,
)?;
let function = modify_refcount_layout_build_function(
env,
layout_interner,
layout_ids,
mode,
layout,
)?;
Some(function)
}
},
Some(function)
}
LambdaSet(lambda_set) => modify_refcount_layout_build_function(
env,
layout_interner,
layout_ids,
mode,
when_recursive,
lambda_set.runtime_representation(),
),
}
@ -675,15 +601,18 @@ fn modify_refcount_list<'a, 'ctx, 'env>(
layout_interner: &mut STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
mode: Mode,
when_recursive: &WhenRecursive<'a>,
element_layout: InLayout<'a>,
) -> FunctionValue<'ctx> {
let block = env.builder.get_insert_block().expect("to be in a function");
let di_location = env.builder.get_current_debug_location().unwrap();
let element_layout = layout_interner.get(element_layout);
let element_layout = when_recursive.unwrap_recursive_pointer(element_layout);
let element_layout = layout_interner.insert(element_layout);
let element_layout = if let Layout::RecursivePointer(rec) = layout_interner.get(element_layout)
{
rec
} else {
element_layout
};
let list_layout = layout_interner.insert(Layout::Builtin(Builtin::List(element_layout)));
let (_, fn_name) = function_name_from_mode(
layout_ids,
@ -705,7 +634,6 @@ fn modify_refcount_list<'a, 'ctx, 'env>(
layout_interner,
layout_ids,
mode,
when_recursive,
list_layout,
element_layout,
function_value,
@ -716,8 +644,7 @@ fn modify_refcount_list<'a, 'ctx, 'env>(
};
env.builder.position_at_end(block);
env.builder
.set_current_debug_location(env.context, di_location);
env.builder.set_current_debug_location(di_location);
function
}
@ -734,7 +661,6 @@ fn modify_refcount_list_help<'a, 'ctx, 'env>(
layout_interner: &mut STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
mode: Mode,
when_recursive: &WhenRecursive<'a>,
layout: InLayout<'a>,
element_layout: InLayout<'a>,
fn_val: FunctionValue<'ctx>,
@ -758,26 +684,27 @@ fn modify_refcount_list_help<'a, 'ctx, 'env>(
let parent = fn_val;
let original_wrapper = arg_val.into_struct_value();
let len = list_capacity(builder, original_wrapper);
// We use the raw capacity to ensure we always decrement the refcount of seamless slices.
let capacity = list_capacity_or_ref_ptr(builder, original_wrapper);
let is_non_empty = builder.build_int_compare(
IntPredicate::UGT,
len,
capacity,
env.ptr_int().const_zero(),
"len > 0",
"cap > 0",
);
// build blocks
let modification_block = ctx.append_basic_block(parent, "modification_block");
let modification_list_block = ctx.append_basic_block(parent, "modification_list_block");
let cont_block = ctx.append_basic_block(parent, "modify_rc_list_cont");
builder.build_conditional_branch(is_non_empty, modification_block, cont_block);
builder.build_conditional_branch(is_non_empty, modification_list_block, cont_block);
builder.position_at_end(modification_block);
builder.position_at_end(modification_list_block);
if layout_interner.contains_refcounted(element_layout) {
let ptr_type = basic_type_from_layout(env, layout_interner, element_layout)
.ptr_type(AddressSpace::Generic);
.ptr_type(AddressSpace::default());
let (len, ptr) = load_list(env.builder, original_wrapper, ptr_type);
@ -787,7 +714,6 @@ fn modify_refcount_list_help<'a, 'ctx, 'env>(
layout_interner,
layout_ids,
mode.to_call_mode(fn_val),
when_recursive,
element,
element_layout,
);
@ -805,7 +731,8 @@ fn modify_refcount_list_help<'a, 'ctx, 'env>(
);
}
let refcount_ptr = PointerToRefcount::from_list_wrapper(env, original_wrapper);
let refcount_ptr =
PointerToRefcount::from_ptr_to_data(env, list_refcount_ptr(env, original_wrapper));
let call_mode = mode_to_call_mode(fn_val, mode);
refcount_ptr.modify(call_mode, layout, env, layout_interner);
@ -849,8 +776,7 @@ fn modify_refcount_str<'a, 'ctx, 'env>(
};
env.builder.position_at_end(block);
env.builder
.set_current_debug_location(env.context, di_location);
env.builder.set_current_debug_location(di_location);
function
}
@ -880,9 +806,9 @@ fn modify_refcount_str_help<'a, 'ctx, 'env>(
let parent = fn_val;
let arg_val =
let str_type = zig_str_type(env);
let str_wrapper =
if Layout::Builtin(Builtin::Str).is_passed_by_reference(layout_interner, env.target_info) {
let str_type = zig_str_type(env);
env.builder
.new_build_load(str_type, arg_val.into_pointer_value(), "load_str_to_stack")
} else {
@ -890,7 +816,7 @@ fn modify_refcount_str_help<'a, 'ctx, 'env>(
debug_assert!(arg_val.is_struct_value());
arg_val
};
let str_wrapper = arg_val.into_struct_value();
let str_wrapper = str_wrapper.into_struct_value();
let capacity = builder
.build_extract_value(str_wrapper, Builtin::WRAPPER_CAPACITY, "read_str_capacity")
@ -913,7 +839,7 @@ fn modify_refcount_str_help<'a, 'ctx, 'env>(
builder.build_conditional_branch(is_big_and_non_empty, modification_block, cont_block);
builder.position_at_end(modification_block);
let refcount_ptr = PointerToRefcount::from_list_wrapper(env, str_wrapper);
let refcount_ptr = PointerToRefcount::from_ptr_to_data(env, str_refcount_ptr(env, arg_val));
let call_mode = mode_to_call_mode(fn_val, mode);
refcount_ptr.modify(call_mode, layout, env, layout_interner);
@ -959,8 +885,7 @@ fn modify_refcount_boxed<'a, 'ctx, 'env>(
};
env.builder.position_at_end(block);
env.builder
.set_current_debug_location(env.context, di_location);
env.builder.set_current_debug_location(di_location);
function
}
@ -1093,7 +1018,6 @@ fn build_rec_union<'a, 'ctx, 'env>(
layout_interner: &mut STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
mode: Mode,
when_recursive: &WhenRecursive<'a>,
union_layout: UnionLayout<'a>,
) -> FunctionValue<'ctx> {
let layout = layout_interner.insert(Layout::Union(union_layout));
@ -1121,14 +1045,12 @@ fn build_rec_union<'a, 'ctx, 'env>(
layout_interner,
layout_ids,
mode,
when_recursive,
union_layout,
function_value,
);
env.builder.position_at_end(block);
env.builder
.set_current_debug_location(env.context, di_location);
env.builder.set_current_debug_location(di_location);
function_value
}
@ -1143,7 +1065,6 @@ fn build_rec_union_help<'a, 'ctx, 'env>(
layout_interner: &mut STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
mode: Mode,
when_recursive: &WhenRecursive<'a>,
union_layout: UnionLayout<'a>,
fn_val: FunctionValue<'ctx>,
) {
@ -1235,7 +1156,6 @@ fn build_rec_union_help<'a, 'ctx, 'env>(
env,
layout_interner,
layout_ids,
when_recursive,
parent,
fn_val,
union_layout,
@ -1268,7 +1188,6 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_interner: &mut STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
when_recursive: &WhenRecursive<'a>,
parent: FunctionValue<'ctx>,
decrement_fn: FunctionValue<'ctx>,
union_layout: UnionLayout<'a>,
@ -1316,7 +1235,7 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>(
// cast the opaque pointer to a pointer of the correct shape
let struct_ptr = env.builder.build_pointer_cast(
value_ptr,
wrapper_type.ptr_type(AddressSpace::Generic),
wrapper_type.ptr_type(AddressSpace::default()),
"opaque_to_correct_recursive_decrement",
);
@ -1339,7 +1258,7 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>(
.unwrap();
let ptr_as_i64_ptr = env.builder.new_build_load(
env.context.i64_type().ptr_type(AddressSpace::Generic),
env.context.i64_type().ptr_type(AddressSpace::default()),
elem_pointer,
"load_recursive_pointer",
);
@ -1396,7 +1315,6 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>(
layout_interner,
layout_ids,
mode.to_call_mode(decrement_fn),
when_recursive,
field,
*field_layout,
);
@ -1422,11 +1340,16 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>(
union_layout,
UnionLayout::NullableUnwrapped { .. } | UnionLayout::NonNullableUnwrapped { .. }
) {
debug_assert_eq!(cases.len(), 1);
debug_assert!(cases.len() <= 1, "{cases:?}");
// in this case, don't switch, because the `else` branch below would try to read the (nonexistent) tag id
let (_, only_branch) = cases.pop().unwrap();
env.builder.build_unconditional_branch(only_branch);
if cases.is_empty() {
// The only other layout doesn't need refcounting. Pass through.
builder.build_return(None);
} else {
// in this case, don't switch, because the `else` branch below would try to read the (nonexistent) tag id
let (_, only_branch) = cases.pop().unwrap();
env.builder.build_unconditional_branch(only_branch);
}
} else {
let default_block = env.context.append_basic_block(parent, "switch_default");
@ -1449,6 +1372,7 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>(
}
}
#[derive(Debug)]
struct UnionLayoutTags<'a> {
nullable_id: Option<u16>,
tags: &'a [&'a [InLayout<'a>]],
@ -1503,15 +1427,7 @@ pub fn build_reset<'a, 'ctx, 'env>(
let fn_name = layout_id.to_symbol_string(Symbol::DEC, &env.interns);
let fn_name = format!("{}_reset", fn_name);
let when_recursive = WhenRecursive::Loop(union_layout);
let dec_function = build_rec_union(
env,
layout_interner,
layout_ids,
Mode::Dec,
&when_recursive,
union_layout,
);
let dec_function = build_rec_union(env, layout_interner, layout_ids, Mode::Dec, union_layout);
let function = match env.module.get_function(fn_name.as_str()) {
Some(function_value) => function_value,
@ -1526,15 +1442,13 @@ pub fn build_reset<'a, 'ctx, 'env>(
env,
layout_interner,
layout_ids,
&when_recursive,
union_layout,
function_value,
dec_function,
);
env.builder.position_at_end(block);
env.builder
.set_current_debug_location(env.context, di_location);
env.builder.set_current_debug_location(di_location);
function_value
}
@ -1548,7 +1462,6 @@ fn build_reuse_rec_union_help<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_interner: &mut STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
when_recursive: &WhenRecursive<'a>,
union_layout: UnionLayout<'a>,
reset_function: FunctionValue<'ctx>,
dec_function: FunctionValue<'ctx>,
@ -1626,7 +1539,6 @@ fn build_reuse_rec_union_help<'a, 'ctx, 'env>(
env,
layout_interner,
layout_ids,
when_recursive,
parent,
dec_function,
union_layout,
@ -1665,7 +1577,6 @@ fn modify_refcount_nonrecursive<'a, 'ctx, 'env>(
layout_interner: &mut STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
mode: Mode,
when_recursive: &WhenRecursive<'a>,
fields: &'a [&'a [InLayout<'a>]],
) -> FunctionValue<'ctx> {
let union_layout = UnionLayout::NonRecursive(fields);
@ -1694,7 +1605,6 @@ fn modify_refcount_nonrecursive<'a, 'ctx, 'env>(
layout_interner,
layout_ids,
mode,
when_recursive,
fields,
function_value,
);
@ -1704,8 +1614,7 @@ fn modify_refcount_nonrecursive<'a, 'ctx, 'env>(
};
env.builder.position_at_end(block);
env.builder
.set_current_debug_location(env.context, di_location);
env.builder.set_current_debug_location(di_location);
function
}
@ -1715,7 +1624,6 @@ fn modify_refcount_nonrecursive_help<'a, 'ctx, 'env>(
layout_interner: &mut STLayoutInterner<'a>,
layout_ids: &mut LayoutIds<'a>,
mode: Mode,
when_recursive: &WhenRecursive<'a>,
tags: &'a [&'a [InLayout<'a>]],
fn_val: FunctionValue<'ctx>,
) {
@ -1805,19 +1713,12 @@ fn modify_refcount_nonrecursive_help<'a, 'ctx, 'env>(
let cast_tag_data_pointer = env.builder.build_pointer_cast(
opaque_tag_data_ptr,
data_struct_type.ptr_type(AddressSpace::Generic),
data_struct_type.ptr_type(AddressSpace::default()),
"cast_to_concrete_tag",
);
for (i, field_layout) in field_layouts.iter().enumerate() {
if let Layout::RecursivePointer(_) = layout_interner.get(*field_layout) {
let recursive_union_layout = match when_recursive {
WhenRecursive::Unreachable => {
panic!("non-recursive tag unions cannot contain naked recursion pointers!");
}
WhenRecursive::Loop(recursive_union_layout) => recursive_union_layout,
};
if let Layout::RecursivePointer(union_layout) = layout_interner.get(*field_layout) {
// This field is a pointer to the recursive pointer.
let field_ptr = env
.builder
@ -1831,7 +1732,7 @@ fn modify_refcount_nonrecursive_help<'a, 'ctx, 'env>(
// This is the actual pointer to the recursive data.
let field_value = env.builder.new_build_load(
env.context.i64_type().ptr_type(AddressSpace::Generic),
env.context.i64_type().ptr_type(AddressSpace::default()),
field_ptr,
"load_recursive_pointer",
);
@ -1839,7 +1740,6 @@ fn modify_refcount_nonrecursive_help<'a, 'ctx, 'env>(
debug_assert!(field_value.is_pointer_value());
// therefore we must cast it to our desired type
let union_layout = layout_interner.insert(Layout::Union(*recursive_union_layout));
let union_type = basic_type_from_layout(env, layout_interner, union_layout);
let recursive_ptr_field_value =
cast_basic_basic(env.builder, field_value, union_type);
@ -1849,7 +1749,6 @@ fn modify_refcount_nonrecursive_help<'a, 'ctx, 'env>(
layout_interner,
layout_ids,
mode.to_call_mode(fn_val),
when_recursive,
recursive_ptr_field_value,
*field_layout,
)
@ -1879,7 +1778,6 @@ fn modify_refcount_nonrecursive_help<'a, 'ctx, 'env>(
layout_interner,
layout_ids,
mode.to_call_mode(fn_val),
when_recursive,
field_value,
*field_layout,
);