mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 05:49:08 +00:00
Merge remote-tracking branch 'origin/main' into glue-getters-rtfeldman
This commit is contained in:
commit
1c1112ec35
1136 changed files with 39670 additions and 19058 deletions
|
@ -9,7 +9,7 @@ use crate::llvm::refcounting::{
|
|||
decrement_refcount_layout, increment_n_refcount_layout, increment_refcount_layout,
|
||||
};
|
||||
use inkwell::attributes::{Attribute, AttributeLoc};
|
||||
use inkwell::types::{BasicType, BasicTypeEnum};
|
||||
use inkwell::types::{BasicType, BasicTypeEnum, StructType};
|
||||
use inkwell::values::{
|
||||
BasicValue, BasicValueEnum, CallSiteValue, FunctionValue, InstructionValue, IntValue,
|
||||
PointerValue, StructValue,
|
||||
|
@ -17,11 +17,10 @@ use inkwell::values::{
|
|||
use inkwell::AddressSpace;
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::{Builtin, LambdaSet, Layout, LayoutIds};
|
||||
use roc_mono::layout::{Builtin, LambdaSet, Layout, LayoutIds, STLayoutInterner};
|
||||
|
||||
use super::build::create_entry_block_alloca;
|
||||
|
||||
use std::convert::TryInto;
|
||||
use super::build::{create_entry_block_alloca, BuilderExt};
|
||||
use super::convert::zig_list_type;
|
||||
|
||||
pub fn call_bitcode_fn<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
|
@ -96,12 +95,14 @@ fn call_bitcode_fn_help<'a, 'ctx, 'env>(
|
|||
|
||||
pub fn call_bitcode_fn_fixing_for_convention<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
bitcode_return_type: StructType<'ctx>,
|
||||
args: &[BasicValueEnum<'ctx>],
|
||||
return_layout: &Layout<'_>,
|
||||
return_layout: &Layout<'a>,
|
||||
fn_name: &str,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
// Calling zig bitcode, so we must follow C calling conventions.
|
||||
let cc_return = to_cc_return(env, return_layout);
|
||||
let cc_return = to_cc_return(env, layout_interner, return_layout);
|
||||
match cc_return {
|
||||
CCReturn::Return => {
|
||||
// We'll get a return value
|
||||
|
@ -109,19 +110,9 @@ pub fn call_bitcode_fn_fixing_for_convention<'a, 'ctx, 'env>(
|
|||
}
|
||||
CCReturn::ByPointer => {
|
||||
// We need to pass the return value by pointer.
|
||||
let roc_return_type = basic_type_from_layout(env, return_layout);
|
||||
let roc_return_type = basic_type_from_layout(env, layout_interner, return_layout);
|
||||
|
||||
let cc_ptr_return_type = env
|
||||
.module
|
||||
.get_function(fn_name)
|
||||
.unwrap()
|
||||
.get_type()
|
||||
.get_param_types()[0]
|
||||
.into_pointer_type();
|
||||
let cc_return_type: BasicTypeEnum<'ctx> = cc_ptr_return_type
|
||||
.get_element_type()
|
||||
.try_into()
|
||||
.expect("Zig bitcode return type is not a basic type!");
|
||||
let cc_return_type: BasicTypeEnum<'ctx> = bitcode_return_type.into();
|
||||
|
||||
// when we write an i128 into this (happens in NumToInt), zig expects this pointer to
|
||||
// be 16-byte aligned. Not doing so is UB and will immediately fail on CI
|
||||
|
@ -139,7 +130,9 @@ pub fn call_bitcode_fn_fixing_for_convention<'a, 'ctx, 'env>(
|
|||
.collect();
|
||||
call_void_bitcode_fn(env, &fixed_args, fn_name);
|
||||
|
||||
let cc_return_value = env.builder.build_load(cc_return_value_ptr, "read_result");
|
||||
let cc_return_value =
|
||||
env.builder
|
||||
.new_build_load(cc_return_type, cc_return_value_ptr, "read_result");
|
||||
if roc_return_type.size_of() == cc_return_type.size_of() {
|
||||
cc_return_value
|
||||
} else {
|
||||
|
@ -172,6 +165,7 @@ const ARGUMENT_SYMBOLS: [Symbol; 8] = [
|
|||
|
||||
pub(crate) fn build_transform_caller<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
function: FunctionValue<'ctx>,
|
||||
closure_data_layout: LambdaSet<'a>,
|
||||
argument_layouts: &[Layout<'a>],
|
||||
|
@ -186,6 +180,7 @@ pub(crate) fn build_transform_caller<'a, 'ctx, 'env>(
|
|||
Some(function_value) => function_value,
|
||||
None => build_transform_caller_help(
|
||||
env,
|
||||
layout_interner,
|
||||
function,
|
||||
closure_data_layout,
|
||||
argument_layouts,
|
||||
|
@ -197,6 +192,7 @@ pub(crate) fn build_transform_caller<'a, 'ctx, 'env>(
|
|||
|
||||
fn build_transform_caller_help<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
roc_function: FunctionValue<'ctx>,
|
||||
closure_data_layout: LambdaSet<'a>,
|
||||
argument_layouts: &[Layout<'a>],
|
||||
|
@ -245,7 +241,8 @@ fn build_transform_caller_help<'a, 'ctx, 'env>(
|
|||
bumpalo::collections::Vec::with_capacity_in(arguments.len(), env.arena);
|
||||
|
||||
for (argument_ptr, layout) in arguments.iter().zip(argument_layouts) {
|
||||
let basic_type = basic_type_from_layout(env, layout).ptr_type(AddressSpace::Generic);
|
||||
let basic_type =
|
||||
basic_type_from_layout(env, layout_interner, layout).ptr_type(AddressSpace::Generic);
|
||||
|
||||
let cast_ptr = env.builder.build_pointer_cast(
|
||||
argument_ptr.into_pointer_value(),
|
||||
|
@ -253,29 +250,36 @@ fn build_transform_caller_help<'a, 'ctx, 'env>(
|
|||
"cast_ptr_to_tag_build_transform_caller_help",
|
||||
);
|
||||
|
||||
let argument = load_roc_value(env, *layout, cast_ptr, "zig_helper_load_opaque");
|
||||
let argument = load_roc_value(
|
||||
env,
|
||||
layout_interner,
|
||||
*layout,
|
||||
cast_ptr,
|
||||
"zig_helper_load_opaque",
|
||||
);
|
||||
|
||||
arguments_cast.push(argument);
|
||||
}
|
||||
|
||||
match (
|
||||
closure_data_layout
|
||||
.is_represented(env.layout_interner)
|
||||
.is_represented(layout_interner)
|
||||
.is_some(),
|
||||
closure_data_layout.runtime_representation(env.layout_interner),
|
||||
closure_data_layout.runtime_representation(layout_interner),
|
||||
) {
|
||||
(false, _) => {
|
||||
// the function doesn't expect a closure argument, nothing to add
|
||||
}
|
||||
(true, layout) => {
|
||||
let closure_type = basic_type_from_layout(env, &layout).ptr_type(AddressSpace::Generic);
|
||||
let closure_type = basic_type_from_layout(env, layout_interner, &layout)
|
||||
.ptr_type(AddressSpace::Generic);
|
||||
|
||||
let closure_cast = env
|
||||
.builder
|
||||
.build_bitcast(closure_ptr, closure_type, "cast_opaque_closure")
|
||||
.into_pointer_value();
|
||||
let closure_cast =
|
||||
env.builder
|
||||
.build_pointer_cast(closure_ptr, closure_type, "cast_opaque_closure");
|
||||
|
||||
let closure_data = load_roc_value(env, layout, closure_cast, "load_closure");
|
||||
let closure_data =
|
||||
load_roc_value(env, layout_interner, layout, closure_cast, "load_closure");
|
||||
|
||||
arguments_cast.push(closure_data);
|
||||
}
|
||||
|
@ -283,6 +287,7 @@ fn build_transform_caller_help<'a, 'ctx, 'env>(
|
|||
|
||||
let result = crate::llvm::build::call_roc_function(
|
||||
env,
|
||||
layout_interner,
|
||||
roc_function,
|
||||
&result_layout,
|
||||
arguments_cast.as_slice(),
|
||||
|
@ -293,7 +298,13 @@ fn build_transform_caller_help<'a, 'ctx, 'env>(
|
|||
.unwrap()
|
||||
.into_pointer_value();
|
||||
|
||||
crate::llvm::build::store_roc_value_opaque(env, result_layout, result_u8_ptr, result);
|
||||
crate::llvm::build::store_roc_value_opaque(
|
||||
env,
|
||||
layout_interner,
|
||||
result_layout,
|
||||
result_u8_ptr,
|
||||
result,
|
||||
);
|
||||
env.builder.build_return(None);
|
||||
|
||||
env.builder.position_at_end(block);
|
||||
|
@ -312,31 +323,35 @@ enum Mode {
|
|||
/// a function that accepts two arguments: the value to increment, and an amount to increment by
|
||||
pub fn build_inc_n_wrapper<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
layout: &Layout<'a>,
|
||||
) -> FunctionValue<'ctx> {
|
||||
build_rc_wrapper(env, layout_ids, layout, Mode::IncN)
|
||||
build_rc_wrapper(env, layout_interner, layout_ids, layout, Mode::IncN)
|
||||
}
|
||||
|
||||
/// a function that accepts two arguments: the value to increment; increments by 1
|
||||
pub fn build_inc_wrapper<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
layout: &Layout<'a>,
|
||||
) -> FunctionValue<'ctx> {
|
||||
build_rc_wrapper(env, layout_ids, layout, Mode::Inc)
|
||||
build_rc_wrapper(env, layout_interner, layout_ids, layout, Mode::Inc)
|
||||
}
|
||||
|
||||
pub fn build_dec_wrapper<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
layout: &Layout<'a>,
|
||||
) -> FunctionValue<'ctx> {
|
||||
build_rc_wrapper(env, layout_ids, layout, Mode::Dec)
|
||||
build_rc_wrapper(env, layout_interner, layout_ids, layout, Mode::Dec)
|
||||
}
|
||||
|
||||
fn build_rc_wrapper<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
layout: &Layout<'a>,
|
||||
rc_operation: Mode,
|
||||
|
@ -389,38 +404,39 @@ fn build_rc_wrapper<'a, 'ctx, 'env>(
|
|||
debug_info_init!(env, function_value);
|
||||
|
||||
let mut it = function_value.get_param_iter();
|
||||
let value_ptr = it.next().unwrap().into_pointer_value();
|
||||
let generic_value_ptr = it.next().unwrap().into_pointer_value();
|
||||
|
||||
value_ptr.set_name(Symbol::ARG_1.as_str(&env.interns));
|
||||
generic_value_ptr.set_name(Symbol::ARG_1.as_str(&env.interns));
|
||||
|
||||
let value_type = basic_type_from_layout(env, layout).ptr_type(AddressSpace::Generic);
|
||||
|
||||
let value = if layout.is_passed_by_reference(env.layout_interner, env.target_info) {
|
||||
let value_type = basic_type_from_layout(env, layout_interner, layout);
|
||||
let value_ptr_type = value_type.ptr_type(AddressSpace::Generic);
|
||||
let value_ptr =
|
||||
env.builder
|
||||
.build_pointer_cast(value_ptr, value_type, "cast_ptr_to_tag_build_rc_wrapper")
|
||||
.into()
|
||||
} else {
|
||||
let value_cast = env
|
||||
.builder
|
||||
.build_bitcast(value_ptr, value_type, "load_opaque")
|
||||
.into_pointer_value();
|
||||
.build_pointer_cast(generic_value_ptr, value_ptr_type, "load_opaque");
|
||||
|
||||
env.builder.build_load(value_cast, "load_opaque")
|
||||
// even though this looks like a `load_roc_value`, that gives segfaults in practice.
|
||||
// I suspect it has something to do with the lifetime of the alloca that is created by
|
||||
// `load_roc_value`
|
||||
let value = if layout.is_passed_by_reference(layout_interner, env.target_info) {
|
||||
value_ptr.into()
|
||||
} else {
|
||||
env.builder
|
||||
.new_build_load(value_type, value_ptr, "load_opaque")
|
||||
};
|
||||
|
||||
match rc_operation {
|
||||
Mode::Inc => {
|
||||
let n = 1;
|
||||
increment_refcount_layout(env, layout_ids, n, value, layout);
|
||||
increment_refcount_layout(env, layout_interner, layout_ids, n, value, layout);
|
||||
}
|
||||
Mode::IncN => {
|
||||
let n = it.next().unwrap().into_int_value();
|
||||
n.set_name(Symbol::ARG_2.as_str(&env.interns));
|
||||
|
||||
increment_n_refcount_layout(env, layout_ids, n, value, layout);
|
||||
increment_n_refcount_layout(env, layout_interner, layout_ids, n, value, layout);
|
||||
}
|
||||
Mode::Dec => {
|
||||
decrement_refcount_layout(env, layout_ids, value, layout);
|
||||
decrement_refcount_layout(env, layout_interner, layout_ids, value, layout);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -439,6 +455,7 @@ fn build_rc_wrapper<'a, 'ctx, 'env>(
|
|||
|
||||
pub fn build_eq_wrapper<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
layout: &Layout<'a>,
|
||||
) -> FunctionValue<'ctx> {
|
||||
|
@ -482,24 +499,30 @@ pub fn build_eq_wrapper<'a, 'ctx, 'env>(
|
|||
value_ptr1.set_name(Symbol::ARG_1.as_str(&env.interns));
|
||||
value_ptr2.set_name(Symbol::ARG_2.as_str(&env.interns));
|
||||
|
||||
let value_type = basic_type_from_layout(env, layout).ptr_type(AddressSpace::Generic);
|
||||
let value_type = basic_type_from_layout(env, layout_interner, layout)
|
||||
.ptr_type(AddressSpace::Generic);
|
||||
|
||||
let value_cast1 = env
|
||||
.builder
|
||||
.build_bitcast(value_ptr1, value_type, "load_opaque")
|
||||
.into_pointer_value();
|
||||
.build_pointer_cast(value_ptr1, value_type, "load_opaque");
|
||||
|
||||
let value_cast2 = env
|
||||
.builder
|
||||
.build_bitcast(value_ptr2, value_type, "load_opaque")
|
||||
.into_pointer_value();
|
||||
.build_pointer_cast(value_ptr2, value_type, "load_opaque");
|
||||
|
||||
// load_roc_value(env, *element_layout, elem_ptr, "get_elem")
|
||||
let value1 = load_roc_value(env, *layout, value_cast1, "load_opaque");
|
||||
let value2 = load_roc_value(env, *layout, value_cast2, "load_opaque");
|
||||
let value1 = load_roc_value(env, layout_interner, *layout, value_cast1, "load_opaque");
|
||||
let value2 = load_roc_value(env, layout_interner, *layout, value_cast2, "load_opaque");
|
||||
|
||||
let result =
|
||||
crate::llvm::compare::generic_eq(env, layout_ids, value1, value2, layout, layout);
|
||||
let result = crate::llvm::compare::generic_eq(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
value1,
|
||||
value2,
|
||||
layout,
|
||||
layout,
|
||||
);
|
||||
|
||||
env.builder.build_return(Some(&result));
|
||||
|
||||
|
@ -516,6 +539,7 @@ pub fn build_eq_wrapper<'a, 'ctx, 'env>(
|
|||
|
||||
pub fn build_compare_wrapper<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
roc_function: FunctionValue<'ctx>,
|
||||
closure_data_layout: LambdaSet<'a>,
|
||||
layout: &Layout<'a>,
|
||||
|
@ -565,48 +589,52 @@ pub fn build_compare_wrapper<'a, 'ctx, 'env>(
|
|||
value_ptr1.set_name(Symbol::ARG_2.as_str(&env.interns));
|
||||
value_ptr2.set_name(Symbol::ARG_3.as_str(&env.interns));
|
||||
|
||||
let value_type = basic_type_from_layout(env, layout);
|
||||
let value_type = basic_type_from_layout(env, layout_interner, layout);
|
||||
let value_ptr_type = value_type.ptr_type(AddressSpace::Generic);
|
||||
|
||||
let value_cast1 = env
|
||||
.builder
|
||||
.build_bitcast(value_ptr1, value_ptr_type, "load_opaque")
|
||||
.into_pointer_value();
|
||||
let value_cast1 =
|
||||
env.builder
|
||||
.build_pointer_cast(value_ptr1, value_ptr_type, "load_opaque");
|
||||
|
||||
let value_cast2 = env
|
||||
.builder
|
||||
.build_bitcast(value_ptr2, value_ptr_type, "load_opaque")
|
||||
.into_pointer_value();
|
||||
let value_cast2 =
|
||||
env.builder
|
||||
.build_pointer_cast(value_ptr2, value_ptr_type, "load_opaque");
|
||||
|
||||
let value1 = env.builder.build_load(value_cast1, "load_opaque");
|
||||
let value2 = env.builder.build_load(value_cast2, "load_opaque");
|
||||
let value1 = env
|
||||
.builder
|
||||
.new_build_load(value_type, value_cast1, "load_opaque");
|
||||
let value2 = env
|
||||
.builder
|
||||
.new_build_load(value_type, value_cast2, "load_opaque");
|
||||
|
||||
let default = [value1.into(), value2.into()];
|
||||
|
||||
let arguments_cast =
|
||||
match closure_data_layout.runtime_representation(env.layout_interner) {
|
||||
Layout::Struct {
|
||||
field_layouts: &[], ..
|
||||
} => {
|
||||
// nothing to add
|
||||
&default
|
||||
}
|
||||
other => {
|
||||
let closure_type =
|
||||
basic_type_from_layout(env, &other).ptr_type(AddressSpace::Generic);
|
||||
let arguments_cast = match closure_data_layout.runtime_representation(layout_interner) {
|
||||
Layout::Struct {
|
||||
field_layouts: &[], ..
|
||||
} => {
|
||||
// nothing to add
|
||||
&default
|
||||
}
|
||||
other => {
|
||||
let closure_type = basic_type_from_layout(env, layout_interner, &other);
|
||||
let closure_ptr_type = closure_type.ptr_type(AddressSpace::Generic);
|
||||
|
||||
let closure_cast = env
|
||||
.builder
|
||||
.build_bitcast(closure_ptr, closure_type, "load_opaque")
|
||||
.into_pointer_value();
|
||||
let closure_cast = env.builder.build_pointer_cast(
|
||||
closure_ptr,
|
||||
closure_ptr_type,
|
||||
"load_opaque",
|
||||
);
|
||||
|
||||
let closure_data = env.builder.build_load(closure_cast, "load_opaque");
|
||||
let closure_data =
|
||||
env.builder
|
||||
.new_build_load(closure_type, closure_cast, "load_opaque");
|
||||
|
||||
env.arena
|
||||
.alloc([value1.into(), value2.into(), closure_data.into()])
|
||||
as &[_]
|
||||
}
|
||||
};
|
||||
env.arena
|
||||
.alloc([value1.into(), value2.into(), closure_data.into()])
|
||||
as &[_]
|
||||
}
|
||||
};
|
||||
|
||||
let call = env.builder.build_call(
|
||||
roc_function,
|
||||
|
@ -648,7 +676,8 @@ impl<'ctx> BitcodeReturnValue<'ctx> {
|
|||
match self {
|
||||
BitcodeReturnValue::List(result) => {
|
||||
call_void_bitcode_fn(env, arguments, fn_name);
|
||||
env.builder.build_load(*result, "load_list")
|
||||
env.builder
|
||||
.new_build_load(zig_list_type(env), *result, "load_list")
|
||||
}
|
||||
BitcodeReturnValue::Str(result) => {
|
||||
call_void_bitcode_fn(env, arguments, fn_name);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,844 +0,0 @@
|
|||
use crate::debug_info_init;
|
||||
use crate::llvm::bitcode::{
|
||||
build_dec_wrapper, build_eq_wrapper, build_inc_wrapper, call_bitcode_fn, call_void_bitcode_fn,
|
||||
};
|
||||
use crate::llvm::build::{
|
||||
complex_bitcast, load_roc_value, load_symbol, load_symbol_and_layout, Env, RocFunctionCall,
|
||||
Scope,
|
||||
};
|
||||
use crate::llvm::build_list::{layout_width, pass_as_opaque};
|
||||
use crate::llvm::convert::{basic_type_from_layout, zig_dict_type};
|
||||
use crate::llvm::refcounting::Mode;
|
||||
use inkwell::attributes::{Attribute, AttributeLoc};
|
||||
use inkwell::builder::Builder;
|
||||
use inkwell::context::Context;
|
||||
use inkwell::types::BasicType;
|
||||
use inkwell::values::{BasicValue, BasicValueEnum, FunctionValue, IntValue, StructValue};
|
||||
use inkwell::AddressSpace;
|
||||
use roc_builtins::bitcode;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::{Builtin, Layout, LayoutIds};
|
||||
use roc_target::TargetInfo;
|
||||
|
||||
use super::bitcode::call_list_bitcode_fn;
|
||||
use super::build::store_roc_value;
|
||||
use super::build_list::list_to_c_abi;
|
||||
|
||||
#[repr(transparent)]
|
||||
struct Alignment(u8);
|
||||
|
||||
impl Alignment {
|
||||
fn from_key_value_layout(key: &Layout, value: &Layout, target_info: TargetInfo) -> Alignment {
|
||||
let key_align = key.alignment_bytes(target_info);
|
||||
let value_align = value.alignment_bytes(target_info);
|
||||
|
||||
let mut bits = key_align.max(value_align) as u8;
|
||||
|
||||
// alignment must be a power of 2
|
||||
debug_assert!(bits.is_power_of_two());
|
||||
|
||||
let value_before_key_flag = 0b1000_0000;
|
||||
|
||||
if key_align < value_align {
|
||||
bits |= value_before_key_flag;
|
||||
}
|
||||
|
||||
Alignment(bits)
|
||||
}
|
||||
|
||||
fn as_int_value<'ctx>(&self, context: &'ctx Context) -> IntValue<'ctx> {
|
||||
context.i8_type().const_int(self.0 as u64, false)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dict_len<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
scope: &Scope<'a, 'ctx>,
|
||||
dict_symbol: Symbol,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let (_, dict_layout) = load_symbol_and_layout(scope, &dict_symbol);
|
||||
|
||||
match dict_layout {
|
||||
Layout::Builtin(Builtin::Dict(_, _)) =>
|
||||
_ => unreachable!("Invalid layout given to Dict.len : {:?}", dict_layout),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dict_empty<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> BasicValueEnum<'ctx> {
|
||||
// get the RocDict type defined by zig
|
||||
let roc_dict_type = env.module.get_struct_type("dict.RocDict").unwrap();
|
||||
|
||||
// we must give a pointer for the bitcode function to write the result into
|
||||
let result_alloc = env.builder.build_alloca(roc_dict_type, "dict_empty");
|
||||
|
||||
call_void_bitcode_fn(env, &[result_alloc.into()], bitcode::DICT_EMPTY);
|
||||
|
||||
env.builder.build_load(result_alloc, "load_result")
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn dict_insert<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
dict: BasicValueEnum<'ctx>,
|
||||
key: BasicValueEnum<'ctx>,
|
||||
key_layout: &Layout<'a>,
|
||||
value: BasicValueEnum<'ctx>,
|
||||
value_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let builder = env.builder;
|
||||
|
||||
let u8_ptr = env.context.i8_type().ptr_type(AddressSpace::Generic);
|
||||
|
||||
let key_type = basic_type_from_layout(env, key_layout);
|
||||
let value_type = basic_type_from_layout(env, value_layout);
|
||||
|
||||
let key_ptr = builder.build_alloca(key_type, "key_ptr");
|
||||
let value_ptr = builder.build_alloca(value_type, "value_ptr");
|
||||
|
||||
store_roc_value(env, *key_layout, key_ptr, key);
|
||||
store_roc_value(env, *value_layout, value_ptr, value);
|
||||
|
||||
let key_width = env
|
||||
.ptr_int()
|
||||
.const_int(key_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let value_width = env
|
||||
.ptr_int()
|
||||
.const_int(value_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let result_ptr = builder.build_alloca(zig_dict_type(env), "result_ptr");
|
||||
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
|
||||
let alignment_iv = alignment.as_int_value(env.context);
|
||||
|
||||
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout);
|
||||
let eq_fn = build_eq_wrapper(env, layout_ids, key_layout);
|
||||
|
||||
let dec_key_fn = build_dec_wrapper(env, layout_ids, key_layout);
|
||||
let dec_value_fn = build_dec_wrapper(env, layout_ids, value_layout);
|
||||
|
||||
call_void_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
pass_dict_c_abi(env, dict),
|
||||
alignment_iv.into(),
|
||||
env.builder.build_bitcast(key_ptr, u8_ptr, "to_u8_ptr"),
|
||||
key_width.into(),
|
||||
env.builder.build_bitcast(value_ptr, u8_ptr, "to_u8_ptr"),
|
||||
value_width.into(),
|
||||
hash_fn.as_global_value().as_pointer_value().into(),
|
||||
eq_fn.as_global_value().as_pointer_value().into(),
|
||||
dec_key_fn.as_global_value().as_pointer_value().into(),
|
||||
dec_value_fn.as_global_value().as_pointer_value().into(),
|
||||
result_ptr.into(),
|
||||
],
|
||||
bitcode::DICT_INSERT,
|
||||
);
|
||||
|
||||
env.builder.build_load(result_ptr, "load_result")
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn dict_remove<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
dict: BasicValueEnum<'ctx>,
|
||||
key: BasicValueEnum<'ctx>,
|
||||
key_layout: &Layout<'a>,
|
||||
value_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let builder = env.builder;
|
||||
|
||||
let u8_ptr = env.context.i8_type().ptr_type(AddressSpace::Generic);
|
||||
|
||||
let key_ptr = builder.build_alloca(key.get_type(), "key_ptr");
|
||||
|
||||
env.builder.build_store(key_ptr, key);
|
||||
|
||||
let key_width = env
|
||||
.ptr_int()
|
||||
.const_int(key_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let value_width = env
|
||||
.ptr_int()
|
||||
.const_int(value_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let result_ptr = builder.build_alloca(zig_dict_type(env), "result_ptr");
|
||||
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
|
||||
let alignment_iv = alignment.as_int_value(env.context);
|
||||
|
||||
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout);
|
||||
let eq_fn = build_eq_wrapper(env, layout_ids, key_layout);
|
||||
|
||||
let dec_key_fn = build_dec_wrapper(env, layout_ids, key_layout);
|
||||
let dec_value_fn = build_dec_wrapper(env, layout_ids, value_layout);
|
||||
|
||||
call_void_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
pass_dict_c_abi(env, dict),
|
||||
alignment_iv.into(),
|
||||
env.builder.build_bitcast(key_ptr, u8_ptr, "to_u8_ptr"),
|
||||
key_width.into(),
|
||||
value_width.into(),
|
||||
hash_fn.as_global_value().as_pointer_value().into(),
|
||||
eq_fn.as_global_value().as_pointer_value().into(),
|
||||
dec_key_fn.as_global_value().as_pointer_value().into(),
|
||||
dec_value_fn.as_global_value().as_pointer_value().into(),
|
||||
result_ptr.into(),
|
||||
],
|
||||
bitcode::DICT_REMOVE,
|
||||
);
|
||||
|
||||
env.builder.build_load(result_ptr, "load_result")
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn dict_contains<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
dict: BasicValueEnum<'ctx>,
|
||||
key: BasicValueEnum<'ctx>,
|
||||
key_layout: &Layout<'a>,
|
||||
value_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let builder = env.builder;
|
||||
|
||||
let u8_ptr = env.context.i8_type().ptr_type(AddressSpace::Generic);
|
||||
|
||||
let key_ptr = builder.build_alloca(key.get_type(), "key_ptr");
|
||||
|
||||
env.builder.build_store(key_ptr, key);
|
||||
|
||||
let key_width = env
|
||||
.ptr_int()
|
||||
.const_int(key_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let value_width = env
|
||||
.ptr_int()
|
||||
.const_int(value_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
|
||||
let alignment_iv = alignment.as_int_value(env.context);
|
||||
|
||||
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout);
|
||||
let eq_fn = build_eq_wrapper(env, layout_ids, key_layout);
|
||||
|
||||
call_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
pass_dict_c_abi(env, dict),
|
||||
alignment_iv.into(),
|
||||
env.builder.build_bitcast(key_ptr, u8_ptr, "to_u8_ptr"),
|
||||
key_width.into(),
|
||||
value_width.into(),
|
||||
hash_fn.as_global_value().as_pointer_value().into(),
|
||||
eq_fn.as_global_value().as_pointer_value().into(),
|
||||
],
|
||||
bitcode::DICT_CONTAINS,
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn dict_get<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
dict: BasicValueEnum<'ctx>,
|
||||
key: BasicValueEnum<'ctx>,
|
||||
key_layout: &Layout<'a>,
|
||||
value_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let builder = env.builder;
|
||||
|
||||
let u8_ptr = env.context.i8_type().ptr_type(AddressSpace::Generic);
|
||||
|
||||
let key_ptr = builder.build_alloca(key.get_type(), "key_ptr");
|
||||
|
||||
env.builder.build_store(key_ptr, key);
|
||||
|
||||
let key_width = env
|
||||
.ptr_int()
|
||||
.const_int(key_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let value_width = env
|
||||
.ptr_int()
|
||||
.const_int(value_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let value_bt = basic_type_from_layout(env, value_layout);
|
||||
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
|
||||
let alignment_iv = alignment.as_int_value(env.context);
|
||||
|
||||
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout);
|
||||
let eq_fn = build_eq_wrapper(env, layout_ids, key_layout);
|
||||
|
||||
let inc_value_fn = build_inc_wrapper(env, layout_ids, value_layout);
|
||||
|
||||
// { flag: bool, value: *const u8 }
|
||||
let result = call_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
pass_dict_c_abi(env, dict),
|
||||
alignment_iv.into(),
|
||||
env.builder.build_bitcast(key_ptr, u8_ptr, "to_u8_ptr"),
|
||||
key_width.into(),
|
||||
value_width.into(),
|
||||
hash_fn.as_global_value().as_pointer_value().into(),
|
||||
eq_fn.as_global_value().as_pointer_value().into(),
|
||||
inc_value_fn.as_global_value().as_pointer_value().into(),
|
||||
],
|
||||
bitcode::DICT_GET,
|
||||
)
|
||||
.into_struct_value();
|
||||
|
||||
let flag_u8 = env
|
||||
.builder
|
||||
.build_extract_value(result, 1, "get_flag")
|
||||
.unwrap()
|
||||
.into_int_value();
|
||||
|
||||
let flag = env
|
||||
.builder
|
||||
.build_int_cast(flag_u8, env.context.bool_type(), "to_bool");
|
||||
|
||||
let value_u8_ptr_int = env
|
||||
.builder
|
||||
.build_extract_value(result, 0, "get_value_ptr_int")
|
||||
.unwrap()
|
||||
.into_int_value();
|
||||
|
||||
let ptr_type = value_bt.ptr_type(AddressSpace::Generic);
|
||||
let value_u8_ptr = env
|
||||
.builder
|
||||
.build_int_to_ptr(value_u8_ptr_int, ptr_type, "opaque_value_ptr");
|
||||
|
||||
let start_block = env.builder.get_insert_block().unwrap();
|
||||
let parent = start_block.get_parent().unwrap();
|
||||
|
||||
let if_not_null = env.context.append_basic_block(parent, "if_not_null");
|
||||
let done_block = env.context.append_basic_block(parent, "done");
|
||||
|
||||
let default = value_bt.const_zero();
|
||||
|
||||
env.builder
|
||||
.build_conditional_branch(flag, if_not_null, done_block);
|
||||
|
||||
env.builder.position_at_end(if_not_null);
|
||||
let value_ptr = env
|
||||
.builder
|
||||
.build_bitcast(
|
||||
value_u8_ptr,
|
||||
value_bt.ptr_type(AddressSpace::Generic),
|
||||
"from_opaque",
|
||||
)
|
||||
.into_pointer_value();
|
||||
let loaded = env.builder.build_load(value_ptr, "load_value");
|
||||
env.builder.build_unconditional_branch(done_block);
|
||||
|
||||
env.builder.position_at_end(done_block);
|
||||
let result_phi = env.builder.build_phi(value_bt, "result");
|
||||
|
||||
result_phi.add_incoming(&[(&default, start_block), (&loaded, if_not_null)]);
|
||||
|
||||
let value = result_phi.as_basic_value();
|
||||
|
||||
let result = env
|
||||
.context
|
||||
.struct_type(&[value_bt, env.context.bool_type().into()], false)
|
||||
.const_zero();
|
||||
|
||||
let result = env
|
||||
.builder
|
||||
.build_insert_value(result, flag, 1, "insert_flag")
|
||||
.unwrap();
|
||||
|
||||
env.builder
|
||||
.build_insert_value(result, value, 0, "insert_value")
|
||||
.unwrap()
|
||||
.into_struct_value()
|
||||
.into()
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn dict_elements_rc<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
dict: BasicValueEnum<'ctx>,
|
||||
key_layout: &Layout<'a>,
|
||||
value_layout: &Layout<'a>,
|
||||
rc_operation: Mode,
|
||||
) {
|
||||
let key_width = env
|
||||
.ptr_int()
|
||||
.const_int(key_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let value_width = env
|
||||
.ptr_int()
|
||||
.const_int(value_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
|
||||
let alignment_iv = alignment.as_int_value(env.context);
|
||||
|
||||
let (key_fn, value_fn) = match rc_operation {
|
||||
Mode::Inc => (
|
||||
build_inc_wrapper(env, layout_ids, key_layout),
|
||||
build_inc_wrapper(env, layout_ids, value_layout),
|
||||
),
|
||||
Mode::Dec => (
|
||||
build_dec_wrapper(env, layout_ids, key_layout),
|
||||
build_dec_wrapper(env, layout_ids, value_layout),
|
||||
),
|
||||
};
|
||||
|
||||
call_void_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
pass_dict_c_abi(env, dict),
|
||||
alignment_iv.into(),
|
||||
key_width.into(),
|
||||
value_width.into(),
|
||||
key_fn.as_global_value().as_pointer_value().into(),
|
||||
value_fn.as_global_value().as_pointer_value().into(),
|
||||
],
|
||||
bitcode::DICT_ELEMENTS_RC,
|
||||
);
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn dict_keys<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
dict: BasicValueEnum<'ctx>,
|
||||
key_layout: &Layout<'a>,
|
||||
value_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let key_width = env
|
||||
.ptr_int()
|
||||
.const_int(key_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let value_width = env
|
||||
.ptr_int()
|
||||
.const_int(value_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
|
||||
let alignment_iv = alignment.as_int_value(env.context);
|
||||
|
||||
let inc_key_fn = build_inc_wrapper(env, layout_ids, key_layout);
|
||||
|
||||
call_list_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
pass_dict_c_abi(env, dict),
|
||||
alignment_iv.into(),
|
||||
key_width.into(),
|
||||
value_width.into(),
|
||||
inc_key_fn.as_global_value().as_pointer_value().into(),
|
||||
],
|
||||
bitcode::DICT_KEYS,
|
||||
)
|
||||
}
|
||||
|
||||
fn pass_dict_c_abi<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
dict: BasicValueEnum<'ctx>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
match env.target_info.ptr_width() {
|
||||
roc_target::PtrWidth::Bytes4 => {
|
||||
let target_type = env.context.custom_width_int_type(96).into();
|
||||
|
||||
complex_bitcast(env.builder, dict, target_type, "to_i96")
|
||||
}
|
||||
roc_target::PtrWidth::Bytes8 => {
|
||||
let dict_ptr = env.builder.build_alloca(zig_dict_type(env), "dict_ptr");
|
||||
env.builder.build_store(dict_ptr, dict);
|
||||
|
||||
dict_ptr.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn dict_union<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
dict1: BasicValueEnum<'ctx>,
|
||||
dict2: BasicValueEnum<'ctx>,
|
||||
key_layout: &Layout<'a>,
|
||||
value_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let builder = env.builder;
|
||||
|
||||
let key_width = env
|
||||
.ptr_int()
|
||||
.const_int(key_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let value_width = env
|
||||
.ptr_int()
|
||||
.const_int(value_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
|
||||
let alignment_iv = alignment.as_int_value(env.context);
|
||||
|
||||
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout);
|
||||
let eq_fn = build_eq_wrapper(env, layout_ids, key_layout);
|
||||
|
||||
let inc_key_fn = build_inc_wrapper(env, layout_ids, key_layout);
|
||||
let inc_value_fn = build_inc_wrapper(env, layout_ids, value_layout);
|
||||
|
||||
let output_ptr = builder.build_alloca(zig_dict_type(env), "output_ptr");
|
||||
|
||||
call_void_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
pass_dict_c_abi(env, dict1),
|
||||
pass_dict_c_abi(env, dict2),
|
||||
alignment_iv.into(),
|
||||
key_width.into(),
|
||||
value_width.into(),
|
||||
hash_fn.as_global_value().as_pointer_value().into(),
|
||||
eq_fn.as_global_value().as_pointer_value().into(),
|
||||
inc_key_fn.as_global_value().as_pointer_value().into(),
|
||||
inc_value_fn.as_global_value().as_pointer_value().into(),
|
||||
output_ptr.into(),
|
||||
],
|
||||
bitcode::DICT_UNION,
|
||||
);
|
||||
|
||||
env.builder.build_load(output_ptr, "load_output_ptr")
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn dict_difference<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
dict1: BasicValueEnum<'ctx>,
|
||||
dict2: BasicValueEnum<'ctx>,
|
||||
key_layout: &Layout<'a>,
|
||||
value_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
dict_intersect_or_difference(
|
||||
env,
|
||||
layout_ids,
|
||||
dict1,
|
||||
dict2,
|
||||
key_layout,
|
||||
value_layout,
|
||||
bitcode::DICT_DIFFERENCE,
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn dict_intersection<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
dict1: BasicValueEnum<'ctx>,
|
||||
dict2: BasicValueEnum<'ctx>,
|
||||
key_layout: &Layout<'a>,
|
||||
value_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
dict_intersect_or_difference(
|
||||
env,
|
||||
layout_ids,
|
||||
dict1,
|
||||
dict2,
|
||||
key_layout,
|
||||
value_layout,
|
||||
bitcode::DICT_INTERSECTION,
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn dict_intersect_or_difference<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
dict1: BasicValueEnum<'ctx>,
|
||||
dict2: BasicValueEnum<'ctx>,
|
||||
key_layout: &Layout<'a>,
|
||||
value_layout: &Layout<'a>,
|
||||
op: &str,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let builder = env.builder;
|
||||
|
||||
let zig_dict_type = env.module.get_struct_type("dict.RocDict").unwrap();
|
||||
|
||||
let key_width = env
|
||||
.ptr_int()
|
||||
.const_int(key_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let value_width = env
|
||||
.ptr_int()
|
||||
.const_int(value_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
|
||||
let alignment_iv = alignment.as_int_value(env.context);
|
||||
|
||||
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout);
|
||||
let eq_fn = build_eq_wrapper(env, layout_ids, key_layout);
|
||||
|
||||
let dec_key_fn = build_dec_wrapper(env, layout_ids, key_layout);
|
||||
let dec_value_fn = build_dec_wrapper(env, layout_ids, value_layout);
|
||||
|
||||
let output_ptr = builder.build_alloca(zig_dict_type, "output_ptr");
|
||||
|
||||
call_void_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
pass_dict_c_abi(env, dict1),
|
||||
pass_dict_c_abi(env, dict2),
|
||||
alignment_iv.into(),
|
||||
key_width.into(),
|
||||
value_width.into(),
|
||||
hash_fn.as_global_value().as_pointer_value().into(),
|
||||
eq_fn.as_global_value().as_pointer_value().into(),
|
||||
dec_key_fn.as_global_value().as_pointer_value().into(),
|
||||
dec_value_fn.as_global_value().as_pointer_value().into(),
|
||||
output_ptr.into(),
|
||||
],
|
||||
op,
|
||||
);
|
||||
|
||||
env.builder.build_load(output_ptr, "load_output_ptr")
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn dict_walk<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
roc_function_call: RocFunctionCall<'ctx>,
|
||||
dict: BasicValueEnum<'ctx>,
|
||||
accum: BasicValueEnum<'ctx>,
|
||||
key_layout: &Layout<'a>,
|
||||
value_layout: &Layout<'a>,
|
||||
accum_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let builder = env.builder;
|
||||
|
||||
let u8_ptr = env.context.i8_type().ptr_type(AddressSpace::Generic);
|
||||
|
||||
let accum_bt = basic_type_from_layout(env, accum_layout);
|
||||
let accum_ptr = builder.build_alloca(accum_bt, "accum_ptr");
|
||||
env.builder.build_store(accum_ptr, accum);
|
||||
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
|
||||
let alignment_iv = alignment.as_int_value(env.context);
|
||||
|
||||
let output_ptr = builder.build_alloca(accum_bt, "output_ptr");
|
||||
|
||||
call_void_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
pass_dict_c_abi(env, dict),
|
||||
roc_function_call.caller.into(),
|
||||
pass_as_opaque(env, roc_function_call.data),
|
||||
roc_function_call.inc_n_data.into(),
|
||||
roc_function_call.data_is_owned.into(),
|
||||
env.builder.build_bitcast(accum_ptr, u8_ptr, "to_opaque"),
|
||||
alignment_iv.into(),
|
||||
layout_width(env, key_layout),
|
||||
layout_width(env, value_layout),
|
||||
layout_width(env, accum_layout),
|
||||
env.builder.build_bitcast(output_ptr, u8_ptr, "to_opaque"),
|
||||
],
|
||||
bitcode::DICT_WALK,
|
||||
);
|
||||
|
||||
env.builder.build_load(output_ptr, "load_output_ptr")
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn dict_values<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
dict: BasicValueEnum<'ctx>,
|
||||
key_layout: &Layout<'a>,
|
||||
value_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let key_width = env
|
||||
.ptr_int()
|
||||
.const_int(key_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let value_width = env
|
||||
.ptr_int()
|
||||
.const_int(value_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, value_layout, env.target_info);
|
||||
let alignment_iv = alignment.as_int_value(env.context);
|
||||
|
||||
let inc_value_fn = build_inc_wrapper(env, layout_ids, value_layout);
|
||||
|
||||
call_list_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
pass_dict_c_abi(env, dict),
|
||||
alignment_iv.into(),
|
||||
key_width.into(),
|
||||
value_width.into(),
|
||||
inc_value_fn.as_global_value().as_pointer_value().into(),
|
||||
],
|
||||
bitcode::DICT_VALUES,
|
||||
)
|
||||
}
|
||||
|
||||
/// Dict.capacity : Dict * * -> Nat
|
||||
pub fn dict_capacity<'ctx>(
|
||||
builder: &Builder<'ctx>,
|
||||
wrapper_struct: StructValue<'ctx>,
|
||||
) -> IntValue<'ctx> {
|
||||
builder
|
||||
.build_extract_value(wrapper_struct, Builtin::WRAPPER_CAPACITY, "dict_capacity")
|
||||
.unwrap()
|
||||
.into_int_value()
|
||||
}
|
||||
|
||||
/// Set.capacity : Set * -> Nat
|
||||
pub fn set_capacity<'ctx>(
|
||||
builder: &Builder<'ctx>,
|
||||
wrapper_struct: StructValue<'ctx>,
|
||||
) -> IntValue<'ctx> {
|
||||
builder
|
||||
.build_extract_value(wrapper_struct, Builtin::WRAPPER_CAPACITY, "set_capacity")
|
||||
.unwrap()
|
||||
.into_int_value()
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn set_from_list<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
list: BasicValueEnum<'ctx>,
|
||||
key_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let builder = env.builder;
|
||||
|
||||
let key_width = env
|
||||
.ptr_int()
|
||||
.const_int(key_layout.stack_size(env.target_info) as u64, false);
|
||||
|
||||
let value_width = env.ptr_int().const_zero();
|
||||
|
||||
let result_alloca = builder.build_alloca(zig_dict_type(env), "result_alloca");
|
||||
|
||||
let alignment = Alignment::from_key_value_layout(key_layout, &Layout::UNIT, env.target_info);
|
||||
let alignment_iv = alignment.as_int_value(env.context);
|
||||
|
||||
let hash_fn = build_hash_wrapper(env, layout_ids, key_layout);
|
||||
let eq_fn = build_eq_wrapper(env, layout_ids, key_layout);
|
||||
|
||||
let dec_key_fn = build_dec_wrapper(env, layout_ids, key_layout);
|
||||
|
||||
call_void_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
list_to_c_abi(env, list).into(),
|
||||
alignment_iv.into(),
|
||||
key_width.into(),
|
||||
value_width.into(),
|
||||
hash_fn.as_global_value().as_pointer_value().into(),
|
||||
eq_fn.as_global_value().as_pointer_value().into(),
|
||||
dec_key_fn.as_global_value().as_pointer_value().into(),
|
||||
result_alloca.into(),
|
||||
],
|
||||
bitcode::SET_FROM_LIST,
|
||||
);
|
||||
|
||||
env.builder.build_load(result_alloca, "load_result")
|
||||
}
|
||||
|
||||
fn build_hash_wrapper<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
layout: &Layout<'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 symbol = Symbol::GENERIC_HASH_REF;
|
||||
let fn_name = layout_ids
|
||||
.get(symbol, layout)
|
||||
.to_symbol_string(symbol, &env.interns);
|
||||
|
||||
let function_value = match env.module.get_function(fn_name.as_str()) {
|
||||
Some(function_value) => function_value,
|
||||
None => {
|
||||
let seed_type = env.context.i64_type();
|
||||
let arg_type = env.context.i8_type().ptr_type(AddressSpace::Generic);
|
||||
|
||||
let function_value = crate::llvm::refcounting::build_header_help(
|
||||
env,
|
||||
&fn_name,
|
||||
seed_type.into(),
|
||||
&[seed_type.into(), arg_type.into()],
|
||||
);
|
||||
|
||||
let kind_id = Attribute::get_named_enum_kind_id("alwaysinline");
|
||||
debug_assert!(kind_id > 0);
|
||||
let attr = env.context.create_enum_attribute(kind_id, 1);
|
||||
function_value.add_attribute(AttributeLoc::Function, attr);
|
||||
|
||||
let entry = env.context.append_basic_block(function_value, "entry");
|
||||
env.builder.position_at_end(entry);
|
||||
|
||||
debug_info_init!(env, function_value);
|
||||
|
||||
let mut it = function_value.get_param_iter();
|
||||
let seed_arg = it.next().unwrap().into_int_value();
|
||||
let value_ptr = it.next().unwrap().into_pointer_value();
|
||||
|
||||
seed_arg.set_name(Symbol::ARG_1.as_str(&env.interns));
|
||||
value_ptr.set_name(Symbol::ARG_2.as_str(&env.interns));
|
||||
|
||||
let value_type = basic_type_from_layout(env, layout).ptr_type(AddressSpace::Generic);
|
||||
|
||||
let value_cast = env
|
||||
.builder
|
||||
.build_bitcast(value_ptr, value_type, "cast_to_known_type")
|
||||
.into_pointer_value();
|
||||
|
||||
let val_arg = load_roc_value(env, *layout, value_cast, "load_opaque");
|
||||
|
||||
let result =
|
||||
crate::llvm::build_hash::generic_hash(env, layout_ids, seed_arg, val_arg, layout);
|
||||
|
||||
env.builder.build_return(Some(&result));
|
||||
|
||||
function_value
|
||||
}
|
||||
};
|
||||
|
||||
env.builder.position_at_end(block);
|
||||
env.builder
|
||||
.set_current_debug_location(env.context, di_location);
|
||||
|
||||
function_value
|
||||
}
|
||||
|
||||
fn dict_symbol_to_zig_dict<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
scope: &Scope<'a, 'ctx>,
|
||||
symbol: Symbol,
|
||||
) -> StructValue<'ctx> {
|
||||
let dict = load_symbol(scope, &symbol);
|
||||
|
||||
complex_bitcast(
|
||||
env.builder,
|
||||
dict,
|
||||
crate::llvm::convert::zig_dict_type(env).into(),
|
||||
"dict_to_zig_dict",
|
||||
)
|
||||
.into_struct_value()
|
||||
}
|
||||
|
||||
pub fn decref<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
wrapper_struct: StructValue<'ctx>,
|
||||
alignment: u32,
|
||||
) {
|
||||
let pointer = env
|
||||
.builder
|
||||
.build_extract_value(wrapper_struct, Builtin::WRAPPER_PTR, "read_list_ptr")
|
||||
.unwrap()
|
||||
.into_pointer_value();
|
||||
|
||||
crate::llvm::refcounting::decref_pointer_check_null(env, pointer, alignment);
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
#![allow(clippy::too_many_arguments)]
|
||||
use crate::llvm::bitcode::build_dec_wrapper;
|
||||
use crate::llvm::build::{
|
||||
allocate_with_refcount_help, cast_basic_basic, Env, RocFunctionCall, Scope,
|
||||
|
@ -11,12 +10,14 @@ use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue, Str
|
|||
use inkwell::{AddressSpace, IntPredicate};
|
||||
use morphic_lib::UpdateMode;
|
||||
use roc_builtins::bitcode;
|
||||
use roc_intern::Interner;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::{Builtin, Layout, LayoutIds};
|
||||
use roc_mono::layout::{Builtin, InLayout, Layout, LayoutIds, STLayoutInterner};
|
||||
|
||||
use super::bitcode::{call_list_bitcode_fn, BitcodeReturns};
|
||||
use super::build::{
|
||||
create_entry_block_alloca, load_roc_value, load_symbol, store_roc_value, struct_from_fields,
|
||||
BuilderExt,
|
||||
};
|
||||
use super::convert::zig_list_type;
|
||||
|
||||
|
@ -61,29 +62,33 @@ pub(crate) fn pass_update_mode<'a, 'ctx, 'env>(
|
|||
|
||||
fn pass_element_as_opaque<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
element: BasicValueEnum<'ctx>,
|
||||
layout: Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let element_type = basic_type_from_layout(env, &layout);
|
||||
let element_type = basic_type_from_layout(env, layout_interner, &layout);
|
||||
let element_ptr = env
|
||||
.builder
|
||||
.build_alloca(element_type, "element_to_pass_as_opaque");
|
||||
store_roc_value(env, layout, element_ptr, element);
|
||||
store_roc_value(env, layout_interner, layout, element_ptr, element);
|
||||
|
||||
env.builder.build_bitcast(
|
||||
element_ptr,
|
||||
env.context.i8_type().ptr_type(AddressSpace::Generic),
|
||||
"pass_element_as_opaque",
|
||||
)
|
||||
env.builder
|
||||
.build_pointer_cast(
|
||||
element_ptr,
|
||||
env.context.i8_type().ptr_type(AddressSpace::Generic),
|
||||
"pass_element_as_opaque",
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
||||
pub(crate) fn layout_width<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
env.ptr_int()
|
||||
.const_int(
|
||||
layout.stack_size(env.layout_interner, env.target_info) as u64,
|
||||
layout.stack_size(layout_interner, env.target_info) as u64,
|
||||
false,
|
||||
)
|
||||
.into()
|
||||
|
@ -93,25 +98,29 @@ pub(crate) fn pass_as_opaque<'a, 'ctx, 'env>(
|
|||
env: &Env<'a, 'ctx, 'env>,
|
||||
ptr: PointerValue<'ctx>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
env.builder.build_bitcast(
|
||||
ptr,
|
||||
env.context.i8_type().ptr_type(AddressSpace::Generic),
|
||||
"pass_as_opaque",
|
||||
)
|
||||
env.builder
|
||||
.build_pointer_cast(
|
||||
ptr,
|
||||
env.context.i8_type().ptr_type(AddressSpace::Generic),
|
||||
"pass_as_opaque",
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
||||
pub(crate) fn list_with_capacity<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
capacity: IntValue<'ctx>,
|
||||
element_layout: &Layout<'a>,
|
||||
element_layout: InLayout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let element_layout = layout_interner.get(element_layout);
|
||||
call_list_bitcode_fn(
|
||||
env,
|
||||
&[],
|
||||
&[
|
||||
capacity.into(),
|
||||
env.alignment_intvalue(element_layout),
|
||||
layout_width(env, element_layout),
|
||||
env.alignment_intvalue(layout_interner, element_layout),
|
||||
layout_width(env, layout_interner, element_layout),
|
||||
],
|
||||
BitcodeReturns::List,
|
||||
bitcode::LIST_WITH_CAPACITY,
|
||||
|
@ -120,26 +129,40 @@ pub(crate) fn list_with_capacity<'a, 'ctx, 'env>(
|
|||
|
||||
pub(crate) fn list_get_unsafe<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
element_layout: &Layout<'a>,
|
||||
element_layout: InLayout<'a>,
|
||||
elem_index: IntValue<'ctx>,
|
||||
wrapper_struct: StructValue<'ctx>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let builder = env.builder;
|
||||
|
||||
let elem_type = basic_type_from_layout(env, element_layout);
|
||||
let element_layout = layout_interner.get(element_layout);
|
||||
let elem_type = basic_type_from_layout(env, layout_interner, element_layout);
|
||||
let ptr_type = elem_type.ptr_type(AddressSpace::Generic);
|
||||
// Load the pointer to the array data
|
||||
let array_data_ptr = load_list_ptr(builder, wrapper_struct, ptr_type);
|
||||
|
||||
// Assume the bounds have already been checked earlier
|
||||
// (e.g. by List.get or List.first, which wrap List.#getUnsafe)
|
||||
let elem_ptr =
|
||||
unsafe { builder.build_in_bounds_gep(array_data_ptr, &[elem_index], "list_get_element") };
|
||||
let elem_ptr = unsafe {
|
||||
builder.new_build_in_bounds_gep(
|
||||
elem_type,
|
||||
array_data_ptr,
|
||||
&[elem_index],
|
||||
"list_get_element",
|
||||
)
|
||||
};
|
||||
|
||||
let result = load_roc_value(env, *element_layout, elem_ptr, "list_get_load_element");
|
||||
let result = load_roc_value(
|
||||
env,
|
||||
layout_interner,
|
||||
*element_layout,
|
||||
elem_ptr,
|
||||
"list_get_load_element",
|
||||
);
|
||||
|
||||
increment_refcount_layout(env, layout_ids, 1, result, element_layout);
|
||||
increment_refcount_layout(env, layout_interner, layout_ids, 1, result, element_layout);
|
||||
|
||||
result
|
||||
}
|
||||
|
@ -147,18 +170,20 @@ pub(crate) fn list_get_unsafe<'a, 'ctx, 'env>(
|
|||
/// List.reserve : List elem, Nat -> List elem
|
||||
pub(crate) fn list_reserve<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
list: BasicValueEnum<'ctx>,
|
||||
spare: BasicValueEnum<'ctx>,
|
||||
element_layout: &Layout<'a>,
|
||||
element_layout: InLayout<'a>,
|
||||
update_mode: UpdateMode,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let element_layout = layout_interner.get(element_layout);
|
||||
call_list_bitcode_fn_1(
|
||||
env,
|
||||
list.into_struct_value(),
|
||||
&[
|
||||
env.alignment_intvalue(element_layout),
|
||||
env.alignment_intvalue(layout_interner, element_layout),
|
||||
spare,
|
||||
layout_width(env, element_layout),
|
||||
layout_width(env, layout_interner, element_layout),
|
||||
pass_update_mode(env, update_mode),
|
||||
],
|
||||
bitcode::LIST_RESERVE,
|
||||
|
@ -168,6 +193,7 @@ pub(crate) fn list_reserve<'a, 'ctx, 'env>(
|
|||
/// List.appendUnsafe : List elem, elem -> List elem
|
||||
pub(crate) fn list_append_unsafe<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
original_wrapper: StructValue<'ctx>,
|
||||
element: BasicValueEnum<'ctx>,
|
||||
element_layout: &Layout<'a>,
|
||||
|
@ -176,8 +202,8 @@ pub(crate) fn list_append_unsafe<'a, 'ctx, 'env>(
|
|||
env,
|
||||
original_wrapper,
|
||||
&[
|
||||
pass_element_as_opaque(env, element, *element_layout),
|
||||
layout_width(env, element_layout),
|
||||
pass_element_as_opaque(env, layout_interner, element, *element_layout),
|
||||
layout_width(env, layout_interner, element_layout),
|
||||
],
|
||||
bitcode::LIST_APPEND_UNSAFE,
|
||||
)
|
||||
|
@ -186,6 +212,7 @@ pub(crate) fn list_append_unsafe<'a, 'ctx, 'env>(
|
|||
/// List.prepend : List elem, elem -> List elem
|
||||
pub(crate) fn list_prepend<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
original_wrapper: StructValue<'ctx>,
|
||||
element: BasicValueEnum<'ctx>,
|
||||
element_layout: &Layout<'a>,
|
||||
|
@ -194,9 +221,9 @@ pub(crate) fn list_prepend<'a, 'ctx, 'env>(
|
|||
env,
|
||||
original_wrapper,
|
||||
&[
|
||||
env.alignment_intvalue(element_layout),
|
||||
pass_element_as_opaque(env, element, *element_layout),
|
||||
layout_width(env, element_layout),
|
||||
env.alignment_intvalue(layout_interner, element_layout),
|
||||
pass_element_as_opaque(env, layout_interner, element, *element_layout),
|
||||
layout_width(env, layout_interner, element_layout),
|
||||
],
|
||||
bitcode::LIST_PREPEND,
|
||||
)
|
||||
|
@ -205,18 +232,20 @@ pub(crate) fn list_prepend<'a, 'ctx, 'env>(
|
|||
/// List.swap : List elem, Nat, Nat -> List elem
|
||||
pub(crate) fn list_swap<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
original_wrapper: StructValue<'ctx>,
|
||||
index_1: IntValue<'ctx>,
|
||||
index_2: IntValue<'ctx>,
|
||||
element_layout: &Layout<'a>,
|
||||
element_layout: InLayout<'a>,
|
||||
update_mode: UpdateMode,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let element_layout = layout_interner.get(element_layout);
|
||||
call_list_bitcode_fn_1(
|
||||
env,
|
||||
original_wrapper,
|
||||
&[
|
||||
env.alignment_intvalue(element_layout),
|
||||
layout_width(env, element_layout),
|
||||
env.alignment_intvalue(layout_interner, element_layout),
|
||||
layout_width(env, layout_interner, element_layout),
|
||||
index_1.into(),
|
||||
index_2.into(),
|
||||
pass_update_mode(env, update_mode),
|
||||
|
@ -228,19 +257,21 @@ pub(crate) fn list_swap<'a, 'ctx, 'env>(
|
|||
/// List.sublist : List elem, { start : Nat, len : Nat } -> List elem
|
||||
pub(crate) fn list_sublist<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
original_wrapper: StructValue<'ctx>,
|
||||
start: IntValue<'ctx>,
|
||||
len: IntValue<'ctx>,
|
||||
element_layout: &Layout<'a>,
|
||||
element_layout: InLayout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let dec_element_fn = build_dec_wrapper(env, layout_ids, element_layout);
|
||||
let element_layout = layout_interner.get(element_layout);
|
||||
let dec_element_fn = build_dec_wrapper(env, layout_interner, layout_ids, element_layout);
|
||||
call_list_bitcode_fn_1(
|
||||
env,
|
||||
original_wrapper,
|
||||
&[
|
||||
env.alignment_intvalue(element_layout),
|
||||
layout_width(env, element_layout),
|
||||
env.alignment_intvalue(layout_interner, element_layout),
|
||||
layout_width(env, layout_interner, element_layout),
|
||||
start.into(),
|
||||
len.into(),
|
||||
dec_element_fn.as_global_value().as_pointer_value().into(),
|
||||
|
@ -252,18 +283,20 @@ pub(crate) fn list_sublist<'a, 'ctx, 'env>(
|
|||
/// List.dropAt : List elem, Nat -> List elem
|
||||
pub(crate) fn list_drop_at<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
original_wrapper: StructValue<'ctx>,
|
||||
count: IntValue<'ctx>,
|
||||
element_layout: &Layout<'a>,
|
||||
element_layout: InLayout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let dec_element_fn = build_dec_wrapper(env, layout_ids, element_layout);
|
||||
let element_layout = layout_interner.get(element_layout);
|
||||
let dec_element_fn = build_dec_wrapper(env, layout_interner, layout_ids, element_layout);
|
||||
call_list_bitcode_fn_1(
|
||||
env,
|
||||
original_wrapper,
|
||||
&[
|
||||
env.alignment_intvalue(element_layout),
|
||||
layout_width(env, element_layout),
|
||||
env.alignment_intvalue(layout_interner, element_layout),
|
||||
layout_width(env, layout_interner, element_layout),
|
||||
count.into(),
|
||||
dec_element_fn.as_global_value().as_pointer_value().into(),
|
||||
],
|
||||
|
@ -274,6 +307,7 @@ pub(crate) fn list_drop_at<'a, 'ctx, 'env>(
|
|||
/// List.replace_unsafe : List elem, Nat, elem -> { list: List elem, value: elem }
|
||||
pub(crate) fn list_replace_unsafe<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
_layout_ids: &mut LayoutIds<'a>,
|
||||
list: BasicValueEnum<'ctx>,
|
||||
index: IntValue<'ctx>,
|
||||
|
@ -281,7 +315,7 @@ pub(crate) fn list_replace_unsafe<'a, 'ctx, 'env>(
|
|||
element_layout: &Layout<'a>,
|
||||
update_mode: UpdateMode,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let element_type = basic_type_from_layout(env, element_layout);
|
||||
let element_type = basic_type_from_layout(env, layout_interner, element_layout);
|
||||
let element_ptr = env
|
||||
.builder
|
||||
.build_alloca(element_type, "output_element_as_opaque");
|
||||
|
@ -294,8 +328,8 @@ pub(crate) fn list_replace_unsafe<'a, 'ctx, 'env>(
|
|||
list.into_struct_value(),
|
||||
&[
|
||||
index.into(),
|
||||
pass_element_as_opaque(env, element, *element_layout),
|
||||
layout_width(env, element_layout),
|
||||
pass_element_as_opaque(env, layout_interner, element, *element_layout),
|
||||
layout_width(env, layout_interner, element_layout),
|
||||
pass_as_opaque(env, element_ptr),
|
||||
],
|
||||
bitcode::LIST_REPLACE_IN_PLACE,
|
||||
|
@ -304,10 +338,10 @@ pub(crate) fn list_replace_unsafe<'a, 'ctx, 'env>(
|
|||
env,
|
||||
list.into_struct_value(),
|
||||
&[
|
||||
env.alignment_intvalue(element_layout),
|
||||
env.alignment_intvalue(layout_interner, element_layout),
|
||||
index.into(),
|
||||
pass_element_as_opaque(env, element, *element_layout),
|
||||
layout_width(env, element_layout),
|
||||
pass_element_as_opaque(env, layout_interner, element, *element_layout),
|
||||
layout_width(env, layout_interner, element_layout),
|
||||
pass_as_opaque(env, element_ptr),
|
||||
],
|
||||
bitcode::LIST_REPLACE,
|
||||
|
@ -315,11 +349,13 @@ pub(crate) fn list_replace_unsafe<'a, 'ctx, 'env>(
|
|||
};
|
||||
|
||||
// Load the element and returned list into a struct.
|
||||
let old_element = env.builder.build_load(element_ptr, "load_element");
|
||||
let old_element = env
|
||||
.builder
|
||||
.new_build_load(element_type, element_ptr, "load_element");
|
||||
|
||||
// the list has the same alignment as a usize / ptr. The element comes first in the struct if
|
||||
// its alignment is bigger than that of a list.
|
||||
let element_align = element_layout.alignment_bytes(env.layout_interner, env.target_info);
|
||||
let element_align = element_layout.alignment_bytes(layout_interner, env.target_info);
|
||||
let element_first = element_align > env.target_info.ptr_width() as u32;
|
||||
|
||||
let fields = if element_first {
|
||||
|
@ -404,6 +440,7 @@ pub(crate) fn destructure<'ctx>(
|
|||
/// List.sortWith : List a, (a, a -> Ordering) -> List a
|
||||
pub(crate) fn list_sort_with<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
roc_function_call: RocFunctionCall<'ctx>,
|
||||
compare_wrapper: PointerValue<'ctx>,
|
||||
list: BasicValueEnum<'ctx>,
|
||||
|
@ -417,8 +454,8 @@ pub(crate) fn list_sort_with<'a, 'ctx, 'env>(
|
|||
pass_as_opaque(env, roc_function_call.data),
|
||||
roc_function_call.inc_n_data.into(),
|
||||
roc_function_call.data_is_owned.into(),
|
||||
env.alignment_intvalue(element_layout),
|
||||
layout_width(env, element_layout),
|
||||
env.alignment_intvalue(layout_interner, element_layout),
|
||||
layout_width(env, layout_interner, element_layout),
|
||||
],
|
||||
bitcode::LIST_SORT_WITH,
|
||||
)
|
||||
|
@ -427,6 +464,7 @@ pub(crate) fn list_sort_with<'a, 'ctx, 'env>(
|
|||
/// List.map : List before, (before -> after) -> List after
|
||||
pub(crate) fn list_map<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
roc_function_call: RocFunctionCall<'ctx>,
|
||||
list: BasicValueEnum<'ctx>,
|
||||
element_layout: &Layout<'a>,
|
||||
|
@ -440,9 +478,9 @@ pub(crate) fn list_map<'a, 'ctx, 'env>(
|
|||
pass_as_opaque(env, roc_function_call.data),
|
||||
roc_function_call.inc_n_data.into(),
|
||||
roc_function_call.data_is_owned.into(),
|
||||
env.alignment_intvalue(return_layout),
|
||||
layout_width(env, element_layout),
|
||||
layout_width(env, return_layout),
|
||||
env.alignment_intvalue(layout_interner, return_layout),
|
||||
layout_width(env, layout_interner, element_layout),
|
||||
layout_width(env, layout_interner, return_layout),
|
||||
],
|
||||
bitcode::LIST_MAP,
|
||||
)
|
||||
|
@ -450,6 +488,7 @@ pub(crate) fn list_map<'a, 'ctx, 'env>(
|
|||
|
||||
pub(crate) fn list_map2<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
roc_function_call: RocFunctionCall<'ctx>,
|
||||
list1: BasicValueEnum<'ctx>,
|
||||
|
@ -458,8 +497,8 @@ pub(crate) fn list_map2<'a, 'ctx, 'env>(
|
|||
element2_layout: &Layout<'a>,
|
||||
return_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let dec_a = build_dec_wrapper(env, layout_ids, element1_layout);
|
||||
let dec_b = build_dec_wrapper(env, layout_ids, element2_layout);
|
||||
let dec_a = build_dec_wrapper(env, layout_interner, layout_ids, element1_layout);
|
||||
let dec_b = build_dec_wrapper(env, layout_interner, layout_ids, element2_layout);
|
||||
|
||||
call_list_bitcode_fn(
|
||||
env,
|
||||
|
@ -469,10 +508,10 @@ pub(crate) fn list_map2<'a, 'ctx, 'env>(
|
|||
pass_as_opaque(env, roc_function_call.data),
|
||||
roc_function_call.inc_n_data.into(),
|
||||
roc_function_call.data_is_owned.into(),
|
||||
env.alignment_intvalue(return_layout),
|
||||
layout_width(env, element1_layout),
|
||||
layout_width(env, element2_layout),
|
||||
layout_width(env, return_layout),
|
||||
env.alignment_intvalue(layout_interner, return_layout),
|
||||
layout_width(env, layout_interner, element1_layout),
|
||||
layout_width(env, layout_interner, element2_layout),
|
||||
layout_width(env, layout_interner, return_layout),
|
||||
dec_a.as_global_value().as_pointer_value().into(),
|
||||
dec_b.as_global_value().as_pointer_value().into(),
|
||||
],
|
||||
|
@ -483,6 +522,7 @@ pub(crate) fn list_map2<'a, 'ctx, 'env>(
|
|||
|
||||
pub(crate) fn list_map3<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
roc_function_call: RocFunctionCall<'ctx>,
|
||||
list1: BasicValueEnum<'ctx>,
|
||||
|
@ -493,9 +533,9 @@ pub(crate) fn list_map3<'a, 'ctx, 'env>(
|
|||
element3_layout: &Layout<'a>,
|
||||
result_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let dec_a = build_dec_wrapper(env, layout_ids, element1_layout);
|
||||
let dec_b = build_dec_wrapper(env, layout_ids, element2_layout);
|
||||
let dec_c = build_dec_wrapper(env, layout_ids, element3_layout);
|
||||
let dec_a = build_dec_wrapper(env, layout_interner, layout_ids, element1_layout);
|
||||
let dec_b = build_dec_wrapper(env, layout_interner, layout_ids, element2_layout);
|
||||
let dec_c = build_dec_wrapper(env, layout_interner, layout_ids, element3_layout);
|
||||
|
||||
call_list_bitcode_fn(
|
||||
env,
|
||||
|
@ -509,11 +549,11 @@ pub(crate) fn list_map3<'a, 'ctx, 'env>(
|
|||
pass_as_opaque(env, roc_function_call.data),
|
||||
roc_function_call.inc_n_data.into(),
|
||||
roc_function_call.data_is_owned.into(),
|
||||
env.alignment_intvalue(result_layout),
|
||||
layout_width(env, element1_layout),
|
||||
layout_width(env, element2_layout),
|
||||
layout_width(env, element3_layout),
|
||||
layout_width(env, result_layout),
|
||||
env.alignment_intvalue(layout_interner, result_layout),
|
||||
layout_width(env, layout_interner, element1_layout),
|
||||
layout_width(env, layout_interner, element2_layout),
|
||||
layout_width(env, layout_interner, element3_layout),
|
||||
layout_width(env, layout_interner, result_layout),
|
||||
dec_a.as_global_value().as_pointer_value().into(),
|
||||
dec_b.as_global_value().as_pointer_value().into(),
|
||||
dec_c.as_global_value().as_pointer_value().into(),
|
||||
|
@ -525,6 +565,7 @@ pub(crate) fn list_map3<'a, 'ctx, 'env>(
|
|||
|
||||
pub(crate) fn list_map4<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
roc_function_call: RocFunctionCall<'ctx>,
|
||||
list1: BasicValueEnum<'ctx>,
|
||||
|
@ -537,10 +578,10 @@ pub(crate) fn list_map4<'a, 'ctx, 'env>(
|
|||
element4_layout: &Layout<'a>,
|
||||
result_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let dec_a = build_dec_wrapper(env, layout_ids, element1_layout);
|
||||
let dec_b = build_dec_wrapper(env, layout_ids, element2_layout);
|
||||
let dec_c = build_dec_wrapper(env, layout_ids, element3_layout);
|
||||
let dec_d = build_dec_wrapper(env, layout_ids, element4_layout);
|
||||
let dec_a = build_dec_wrapper(env, layout_interner, layout_ids, element1_layout);
|
||||
let dec_b = build_dec_wrapper(env, layout_interner, layout_ids, element2_layout);
|
||||
let dec_c = build_dec_wrapper(env, layout_interner, layout_ids, element3_layout);
|
||||
let dec_d = build_dec_wrapper(env, layout_interner, layout_ids, element4_layout);
|
||||
|
||||
call_list_bitcode_fn(
|
||||
env,
|
||||
|
@ -555,12 +596,12 @@ pub(crate) fn list_map4<'a, 'ctx, 'env>(
|
|||
pass_as_opaque(env, roc_function_call.data),
|
||||
roc_function_call.inc_n_data.into(),
|
||||
roc_function_call.data_is_owned.into(),
|
||||
env.alignment_intvalue(result_layout),
|
||||
layout_width(env, element1_layout),
|
||||
layout_width(env, element2_layout),
|
||||
layout_width(env, element3_layout),
|
||||
layout_width(env, element4_layout),
|
||||
layout_width(env, result_layout),
|
||||
env.alignment_intvalue(layout_interner, result_layout),
|
||||
layout_width(env, layout_interner, element1_layout),
|
||||
layout_width(env, layout_interner, element2_layout),
|
||||
layout_width(env, layout_interner, element3_layout),
|
||||
layout_width(env, layout_interner, element4_layout),
|
||||
layout_width(env, layout_interner, result_layout),
|
||||
dec_a.as_global_value().as_pointer_value().into(),
|
||||
dec_b.as_global_value().as_pointer_value().into(),
|
||||
dec_c.as_global_value().as_pointer_value().into(),
|
||||
|
@ -574,24 +615,27 @@ pub(crate) fn list_map4<'a, 'ctx, 'env>(
|
|||
/// List.concat : List elem, List elem -> List elem
|
||||
pub(crate) fn list_concat<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
list1: BasicValueEnum<'ctx>,
|
||||
list2: BasicValueEnum<'ctx>,
|
||||
element_layout: &Layout<'a>,
|
||||
element_layout: InLayout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let element_layout = layout_interner.get(element_layout);
|
||||
call_list_bitcode_fn(
|
||||
env,
|
||||
&[list1.into_struct_value(), list2.into_struct_value()],
|
||||
&[
|
||||
env.alignment_intvalue(element_layout),
|
||||
layout_width(env, element_layout),
|
||||
env.alignment_intvalue(layout_interner, element_layout),
|
||||
layout_width(env, layout_interner, element_layout),
|
||||
],
|
||||
BitcodeReturns::List,
|
||||
bitcode::LIST_CONCAT,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn incrementing_elem_loop<'a, 'ctx, 'env, LoopFn>(
|
||||
pub(crate) fn incrementing_elem_loop<'a, 'r, 'ctx, 'env, LoopFn>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &'r mut STLayoutInterner<'a>,
|
||||
parent: FunctionValue<'ctx>,
|
||||
element_layout: Layout<'a>,
|
||||
ptr: PointerValue<'ctx>,
|
||||
|
@ -600,36 +644,49 @@ pub(crate) fn incrementing_elem_loop<'a, 'ctx, 'env, LoopFn>(
|
|||
mut loop_fn: LoopFn,
|
||||
) -> PointerValue<'ctx>
|
||||
where
|
||||
LoopFn: FnMut(IntValue<'ctx>, BasicValueEnum<'ctx>),
|
||||
LoopFn: FnMut(&'r mut STLayoutInterner<'a>, IntValue<'ctx>, BasicValueEnum<'ctx>),
|
||||
{
|
||||
let builder = env.builder;
|
||||
|
||||
incrementing_index_loop(env, parent, len, index_name, |index| {
|
||||
// The pointer to the element in the list
|
||||
let element_ptr = unsafe { builder.build_in_bounds_gep(ptr, &[index], "load_index") };
|
||||
let element_type = basic_type_from_layout(env, layout_interner, &element_layout);
|
||||
|
||||
let elem = load_roc_value(
|
||||
env,
|
||||
element_layout,
|
||||
element_ptr,
|
||||
"incrementing_element_loop_load",
|
||||
);
|
||||
incrementing_index_loop(
|
||||
env,
|
||||
layout_interner,
|
||||
parent,
|
||||
len,
|
||||
index_name,
|
||||
|layout_interner, index| {
|
||||
// The pointer to the element in the list
|
||||
let element_ptr = unsafe {
|
||||
builder.new_build_in_bounds_gep(element_type, ptr, &[index], "load_index")
|
||||
};
|
||||
|
||||
loop_fn(index, elem);
|
||||
})
|
||||
let elem = load_roc_value(
|
||||
env,
|
||||
layout_interner,
|
||||
element_layout,
|
||||
element_ptr,
|
||||
"incrementing_element_loop_load",
|
||||
);
|
||||
|
||||
loop_fn(layout_interner, index, elem);
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// This helper simulates a basic for loop, where
|
||||
// and index increments up from 0 to some end value
|
||||
pub(crate) fn incrementing_index_loop<'a, 'ctx, 'env, LoopFn>(
|
||||
pub(crate) fn incrementing_index_loop<'a, 'r, 'ctx, 'env, LoopFn>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &'r mut STLayoutInterner<'a>,
|
||||
parent: FunctionValue<'ctx>,
|
||||
end: IntValue<'ctx>,
|
||||
index_name: &str,
|
||||
mut loop_fn: LoopFn,
|
||||
) -> PointerValue<'ctx>
|
||||
where
|
||||
LoopFn: FnMut(IntValue<'ctx>),
|
||||
LoopFn: FnMut(&'r mut STLayoutInterner<'a>, IntValue<'ctx>),
|
||||
{
|
||||
let ctx = env.context;
|
||||
let builder = env.builder;
|
||||
|
@ -651,12 +708,14 @@ where
|
|||
{
|
||||
builder.position_at_end(loop_bb);
|
||||
|
||||
let current_index = builder.build_load(index_alloca, "index").into_int_value();
|
||||
let current_index = builder
|
||||
.new_build_load(env.ptr_int(), index_alloca, "index")
|
||||
.into_int_value();
|
||||
let next_index = builder.build_int_add(current_index, one, "next_index");
|
||||
builder.build_store(index_alloca, next_index);
|
||||
|
||||
// The body of the loop
|
||||
loop_fn(current_index);
|
||||
loop_fn(layout_interner, current_index);
|
||||
|
||||
// #index < end
|
||||
let loop_end_cond = bounds_check_comparison(builder, next_index, end);
|
||||
|
@ -711,19 +770,20 @@ pub(crate) fn load_list_ptr<'ctx>(
|
|||
|
||||
pub(crate) fn allocate_list<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
elem_layout: &Layout<'a>,
|
||||
number_of_elements: IntValue<'ctx>,
|
||||
) -> PointerValue<'ctx> {
|
||||
let builder = env.builder;
|
||||
|
||||
let len_type = env.ptr_int();
|
||||
let elem_bytes = elem_layout.stack_size(env.layout_interner, env.target_info) as u64;
|
||||
let elem_bytes = elem_layout.stack_size(layout_interner, env.target_info) as u64;
|
||||
let bytes_per_element = len_type.const_int(elem_bytes, false);
|
||||
let number_of_data_bytes =
|
||||
builder.build_int_mul(bytes_per_element, number_of_elements, "data_length");
|
||||
|
||||
let basic_type = basic_type_from_layout(env, elem_layout);
|
||||
let alignment_bytes = elem_layout.alignment_bytes(env.layout_interner, env.target_info);
|
||||
let basic_type = basic_type_from_layout(env, layout_interner, elem_layout);
|
||||
let alignment_bytes = elem_layout.alignment_bytes(layout_interner, env.target_info);
|
||||
allocate_with_refcount_help(env, basic_type, alignment_bytes, number_of_data_bytes)
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ use roc_mono::layout::Layout;
|
|||
use roc_target::PtrWidth;
|
||||
|
||||
use super::bitcode::{call_str_bitcode_fn, BitcodeReturns};
|
||||
use super::build::BuilderExt;
|
||||
|
||||
pub static CHAR_LAYOUT: Layout = Layout::u8();
|
||||
|
||||
|
@ -29,17 +30,18 @@ pub(crate) fn decode_from_utf8_result<'a, 'ctx, 'env>(
|
|||
|
||||
match env.target_info.ptr_width() {
|
||||
PtrWidth::Bytes4 | PtrWidth::Bytes8 => {
|
||||
let result_ptr_cast = env
|
||||
.builder
|
||||
.build_bitcast(
|
||||
pointer,
|
||||
record_type.ptr_type(AddressSpace::Generic),
|
||||
"to_unnamed",
|
||||
)
|
||||
.into_pointer_value();
|
||||
let result_ptr_cast = env.builder.build_pointer_cast(
|
||||
pointer,
|
||||
record_type.ptr_type(AddressSpace::Generic),
|
||||
"to_unnamed",
|
||||
);
|
||||
|
||||
builder
|
||||
.build_load(result_ptr_cast, "load_utf8_validate_bytes_result")
|
||||
.new_build_load(
|
||||
record_type,
|
||||
result_ptr_cast,
|
||||
"load_utf8_validate_bytes_result",
|
||||
)
|
||||
.into_struct_value()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use crate::llvm::build::{get_tag_id, tag_pointer_clear_tag_id, Env, FAST_CALL_CONV};
|
||||
use crate::llvm::build::{
|
||||
get_tag_id, tag_pointer_clear_tag_id, Env, WhenRecursive, 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;
|
||||
|
@ -10,21 +12,17 @@ use inkwell::values::{
|
|||
use inkwell::{AddressSpace, FloatPredicate, IntPredicate};
|
||||
use roc_builtins::bitcode;
|
||||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||
use roc_intern::Interner;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout};
|
||||
use roc_mono::layout::{Builtin, InLayout, Layout, LayoutIds, STLayoutInterner, UnionLayout};
|
||||
|
||||
use super::build::{load_roc_value, use_roc_value};
|
||||
use super::build::{load_roc_value, use_roc_value, BuilderExt};
|
||||
use super::convert::argument_type_from_union_layout;
|
||||
use super::lowlevel::dec_binop_with_unchecked;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum WhenRecursive<'a> {
|
||||
Unreachable,
|
||||
Loop(UnionLayout<'a>),
|
||||
}
|
||||
|
||||
pub fn generic_eq<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
lhs_val: BasicValueEnum<'ctx>,
|
||||
rhs_val: BasicValueEnum<'ctx>,
|
||||
|
@ -33,6 +31,7 @@ pub fn generic_eq<'a, 'ctx, 'env>(
|
|||
) -> BasicValueEnum<'ctx> {
|
||||
build_eq(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
lhs_val,
|
||||
rhs_val,
|
||||
|
@ -44,6 +43,7 @@ pub fn generic_eq<'a, 'ctx, 'env>(
|
|||
|
||||
pub fn generic_neq<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
lhs_val: BasicValueEnum<'ctx>,
|
||||
rhs_val: BasicValueEnum<'ctx>,
|
||||
|
@ -52,6 +52,7 @@ pub fn generic_neq<'a, 'ctx, 'env>(
|
|||
) -> BasicValueEnum<'ctx> {
|
||||
build_neq(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
lhs_val,
|
||||
rhs_val,
|
||||
|
@ -63,6 +64,7 @@ pub fn generic_neq<'a, 'ctx, 'env>(
|
|||
|
||||
fn build_eq_builtin<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
lhs_val: BasicValueEnum<'ctx>,
|
||||
rhs_val: BasicValueEnum<'ctx>,
|
||||
|
@ -115,7 +117,6 @@ fn build_eq_builtin<'a, 'ctx, 'env>(
|
|||
use FloatWidth::*;
|
||||
|
||||
let name = match float_width {
|
||||
F128 => "eq_f128",
|
||||
F64 => "eq_f64",
|
||||
F32 => "eq_f32",
|
||||
};
|
||||
|
@ -129,9 +130,10 @@ fn build_eq_builtin<'a, 'ctx, 'env>(
|
|||
Builtin::Str => str_equal(env, lhs_val, rhs_val),
|
||||
Builtin::List(elem) => build_list_eq(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
&Layout::Builtin(*builtin),
|
||||
elem,
|
||||
*elem,
|
||||
lhs_val.into_struct_value(),
|
||||
rhs_val.into_struct_value(),
|
||||
when_recursive,
|
||||
|
@ -141,6 +143,7 @@ fn build_eq_builtin<'a, 'ctx, 'env>(
|
|||
|
||||
fn build_eq<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
lhs_val: BasicValueEnum<'ctx>,
|
||||
rhs_val: BasicValueEnum<'ctx>,
|
||||
|
@ -148,8 +151,8 @@ fn build_eq<'a, 'ctx, 'env>(
|
|||
rhs_layout: &Layout<'a>,
|
||||
when_recursive: WhenRecursive<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let lhs_layout = &lhs_layout.runtime_representation(env.layout_interner);
|
||||
let rhs_layout = &rhs_layout.runtime_representation(env.layout_interner);
|
||||
let lhs_layout = &lhs_layout.runtime_representation(layout_interner);
|
||||
let rhs_layout = &rhs_layout.runtime_representation(layout_interner);
|
||||
if lhs_layout != rhs_layout {
|
||||
panic!(
|
||||
"Equality of different layouts; did you have a type mismatch?\n{:?} == {:?}",
|
||||
|
@ -158,12 +161,19 @@ fn build_eq<'a, 'ctx, 'env>(
|
|||
}
|
||||
|
||||
match lhs_layout {
|
||||
Layout::Builtin(builtin) => {
|
||||
build_eq_builtin(env, layout_ids, lhs_val, rhs_val, builtin, when_recursive)
|
||||
}
|
||||
Layout::Builtin(builtin) => build_eq_builtin(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
lhs_val,
|
||||
rhs_val,
|
||||
builtin,
|
||||
when_recursive,
|
||||
),
|
||||
|
||||
Layout::Struct { field_layouts, .. } => build_struct_eq(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
field_layouts,
|
||||
when_recursive,
|
||||
|
@ -175,6 +185,7 @@ fn build_eq<'a, 'ctx, 'env>(
|
|||
|
||||
Layout::Union(union_layout) => build_tag_eq(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
when_recursive,
|
||||
union_layout,
|
||||
|
@ -184,10 +195,11 @@ fn build_eq<'a, 'ctx, 'env>(
|
|||
|
||||
Layout::Boxed(inner_layout) => build_box_eq(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
when_recursive,
|
||||
lhs_layout,
|
||||
inner_layout,
|
||||
*inner_layout,
|
||||
lhs_val,
|
||||
rhs_val,
|
||||
),
|
||||
|
@ -200,21 +212,24 @@ fn build_eq<'a, 'ctx, 'env>(
|
|||
WhenRecursive::Loop(union_layout) => {
|
||||
let layout = Layout::Union(union_layout);
|
||||
|
||||
let bt = basic_type_from_layout(env, &layout);
|
||||
let bt = basic_type_from_layout(env, layout_interner, &layout);
|
||||
|
||||
// cast the i64 pointer to a pointer to block of memory
|
||||
let field1_cast = env
|
||||
.builder
|
||||
.build_bitcast(lhs_val, bt, "i64_to_opaque")
|
||||
.into_pointer_value();
|
||||
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_bitcast(rhs_val, bt, "i64_to_opaque")
|
||||
.into_pointer_value();
|
||||
let field2_cast = env.builder.build_pointer_cast(
|
||||
rhs_val.into_pointer_value(),
|
||||
bt.into_pointer_type(),
|
||||
"i64_to_opaque",
|
||||
);
|
||||
|
||||
build_tag_eq(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
WhenRecursive::Loop(union_layout),
|
||||
&union_layout,
|
||||
|
@ -228,6 +243,7 @@ fn build_eq<'a, 'ctx, 'env>(
|
|||
|
||||
fn build_neq_builtin<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
lhs_val: BasicValueEnum<'ctx>,
|
||||
rhs_val: BasicValueEnum<'ctx>,
|
||||
|
@ -280,7 +296,6 @@ fn build_neq_builtin<'a, 'ctx, 'env>(
|
|||
use FloatWidth::*;
|
||||
|
||||
let name = match float_width {
|
||||
F128 => "neq_f128",
|
||||
F64 => "neq_f64",
|
||||
F32 => "neq_f32",
|
||||
};
|
||||
|
@ -300,9 +315,10 @@ fn build_neq_builtin<'a, 'ctx, 'env>(
|
|||
Builtin::List(elem) => {
|
||||
let is_equal = build_list_eq(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
&Layout::Builtin(*builtin),
|
||||
elem,
|
||||
*elem,
|
||||
lhs_val.into_struct_value(),
|
||||
rhs_val.into_struct_value(),
|
||||
when_recursive,
|
||||
|
@ -318,6 +334,7 @@ fn build_neq_builtin<'a, 'ctx, 'env>(
|
|||
|
||||
fn build_neq<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
lhs_val: BasicValueEnum<'ctx>,
|
||||
rhs_val: BasicValueEnum<'ctx>,
|
||||
|
@ -333,13 +350,20 @@ fn build_neq<'a, 'ctx, 'env>(
|
|||
}
|
||||
|
||||
match lhs_layout {
|
||||
Layout::Builtin(builtin) => {
|
||||
build_neq_builtin(env, layout_ids, lhs_val, rhs_val, builtin, when_recursive)
|
||||
}
|
||||
Layout::Builtin(builtin) => build_neq_builtin(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
lhs_val,
|
||||
rhs_val,
|
||||
builtin,
|
||||
when_recursive,
|
||||
),
|
||||
|
||||
Layout::Struct { field_layouts, .. } => {
|
||||
let is_equal = build_struct_eq(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
field_layouts,
|
||||
when_recursive,
|
||||
|
@ -356,6 +380,7 @@ fn build_neq<'a, 'ctx, 'env>(
|
|||
Layout::Union(union_layout) => {
|
||||
let is_equal = build_tag_eq(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
when_recursive,
|
||||
union_layout,
|
||||
|
@ -372,10 +397,11 @@ fn build_neq<'a, 'ctx, 'env>(
|
|||
Layout::Boxed(inner_layout) => {
|
||||
let is_equal = build_box_eq(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
when_recursive,
|
||||
lhs_layout,
|
||||
inner_layout,
|
||||
*inner_layout,
|
||||
lhs_val,
|
||||
rhs_val,
|
||||
)
|
||||
|
@ -395,9 +421,10 @@ fn build_neq<'a, 'ctx, 'env>(
|
|||
|
||||
fn build_list_eq<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
list_layout: &Layout<'a>,
|
||||
element_layout: &Layout<'a>,
|
||||
element_layout: InLayout<'a>,
|
||||
list1: StructValue<'ctx>,
|
||||
list2: StructValue<'ctx>,
|
||||
when_recursive: WhenRecursive<'a>,
|
||||
|
@ -406,14 +433,16 @@ fn build_list_eq<'a, 'ctx, 'env>(
|
|||
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 fn_name = layout_ids
|
||||
.get(symbol, element_layout)
|
||||
.get(symbol, &element_layout)
|
||||
.to_symbol_string(symbol, &env.interns);
|
||||
|
||||
let function = match env.module.get_function(fn_name.as_str()) {
|
||||
Some(function_value) => function_value,
|
||||
None => {
|
||||
let arg_type = basic_type_from_layout(env, list_layout);
|
||||
let arg_type = basic_type_from_layout(env, layout_interner, list_layout);
|
||||
|
||||
let function_value = crate::llvm::refcounting::build_header_help(
|
||||
env,
|
||||
|
@ -424,10 +453,11 @@ fn build_list_eq<'a, 'ctx, 'env>(
|
|||
|
||||
build_list_eq_help(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
when_recursive,
|
||||
function_value,
|
||||
element_layout,
|
||||
&element_layout,
|
||||
);
|
||||
|
||||
function_value
|
||||
|
@ -448,6 +478,7 @@ fn build_list_eq<'a, 'ctx, 'env>(
|
|||
|
||||
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>,
|
||||
|
@ -510,7 +541,7 @@ fn build_list_eq_help<'a, 'ctx, 'env>(
|
|||
env.builder.position_at_end(then_block);
|
||||
|
||||
let builder = env.builder;
|
||||
let element_type = basic_type_from_layout(env, element_layout);
|
||||
let element_type = basic_type_from_layout(env, layout_interner, element_layout);
|
||||
let ptr_type = element_type.ptr_type(AddressSpace::Generic);
|
||||
let ptr1 = load_list_ptr(env.builder, list1, ptr_type);
|
||||
let ptr2 = load_list_ptr(env.builder, list2, ptr_type);
|
||||
|
@ -530,7 +561,9 @@ fn build_list_eq_help<'a, 'ctx, 'env>(
|
|||
builder.build_unconditional_branch(loop_bb);
|
||||
builder.position_at_end(loop_bb);
|
||||
|
||||
let curr_index = builder.build_load(index_alloca, "index").into_int_value();
|
||||
let curr_index = builder
|
||||
.new_build_load(env.ptr_int(), index_alloca, "index")
|
||||
.into_int_value();
|
||||
|
||||
// #index < end
|
||||
let loop_end_cond =
|
||||
|
@ -545,19 +578,22 @@ fn build_list_eq_help<'a, 'ctx, 'env>(
|
|||
builder.position_at_end(body_bb);
|
||||
|
||||
let elem1 = {
|
||||
let elem_ptr =
|
||||
unsafe { builder.build_in_bounds_gep(ptr1, &[curr_index], "load_index") };
|
||||
load_roc_value(env, *element_layout, elem_ptr, "get_elem")
|
||||
let elem_ptr = unsafe {
|
||||
builder.new_build_in_bounds_gep(element_type, ptr1, &[curr_index], "load_index")
|
||||
};
|
||||
load_roc_value(env, layout_interner, *element_layout, elem_ptr, "get_elem")
|
||||
};
|
||||
|
||||
let elem2 = {
|
||||
let elem_ptr =
|
||||
unsafe { builder.build_in_bounds_gep(ptr2, &[curr_index], "load_index") };
|
||||
load_roc_value(env, *element_layout, elem_ptr, "get_elem")
|
||||
let elem_ptr = unsafe {
|
||||
builder.new_build_in_bounds_gep(element_type, ptr2, &[curr_index], "load_index")
|
||||
};
|
||||
load_roc_value(env, layout_interner, *element_layout, elem_ptr, "get_elem")
|
||||
};
|
||||
|
||||
let are_equal = build_eq(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
elem1,
|
||||
elem2,
|
||||
|
@ -602,6 +638,7 @@ fn build_list_eq_help<'a, 'ctx, 'env>(
|
|||
|
||||
fn build_struct_eq<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
field_layouts: &'a [Layout<'a>],
|
||||
when_recursive: WhenRecursive<'a>,
|
||||
|
@ -621,7 +658,7 @@ fn build_struct_eq<'a, 'ctx, 'env>(
|
|||
let function = match env.module.get_function(fn_name.as_str()) {
|
||||
Some(function_value) => function_value,
|
||||
None => {
|
||||
let arg_type = basic_type_from_layout(env, &struct_layout);
|
||||
let arg_type = basic_type_from_layout(env, layout_interner, &struct_layout);
|
||||
|
||||
let function_value = crate::llvm::refcounting::build_header_help(
|
||||
env,
|
||||
|
@ -632,6 +669,7 @@ fn build_struct_eq<'a, 'ctx, 'env>(
|
|||
|
||||
build_struct_eq_help(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
function_value,
|
||||
when_recursive,
|
||||
|
@ -656,6 +694,7 @@ fn build_struct_eq<'a, 'ctx, 'env>(
|
|||
|
||||
fn build_struct_eq_help<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
parent: FunctionValue<'ctx>,
|
||||
when_recursive: WhenRecursive<'a>,
|
||||
|
@ -724,21 +763,24 @@ fn build_struct_eq_help<'a, 'ctx, 'env>(
|
|||
WhenRecursive::Loop(union_layout) => {
|
||||
let field_layout = Layout::Union(*union_layout);
|
||||
|
||||
let bt = basic_type_from_layout(env, &field_layout);
|
||||
let bt = basic_type_from_layout(env, layout_interner, &field_layout);
|
||||
|
||||
// cast the i64 pointer to a pointer to block of memory
|
||||
let field1_cast = env
|
||||
.builder
|
||||
.build_bitcast(field1, bt, "i64_to_opaque")
|
||||
.into_pointer_value();
|
||||
let field1_cast = env.builder.build_pointer_cast(
|
||||
field1.into_pointer_value(),
|
||||
bt.into_pointer_type(),
|
||||
"i64_to_opaque",
|
||||
);
|
||||
|
||||
let field2_cast = env
|
||||
.builder
|
||||
.build_bitcast(field2, bt, "i64_to_opaque")
|
||||
.into_pointer_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(),
|
||||
|
@ -750,14 +792,17 @@ fn build_struct_eq_help<'a, 'ctx, 'env>(
|
|||
}
|
||||
}
|
||||
} else {
|
||||
let lhs = use_roc_value(env, layout_interner, *field_layout, field1, "field1");
|
||||
let rhs = use_roc_value(env, layout_interner, *field_layout, field2, "field2");
|
||||
build_eq(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
use_roc_value(env, *field_layout, field1, "field1"),
|
||||
use_roc_value(env, *field_layout, field2, "field2"),
|
||||
lhs,
|
||||
rhs,
|
||||
field_layout,
|
||||
field_layout,
|
||||
when_recursive.clone(),
|
||||
when_recursive,
|
||||
)
|
||||
.into_int_value()
|
||||
};
|
||||
|
@ -786,6 +831,7 @@ fn build_struct_eq_help<'a, 'ctx, 'env>(
|
|||
|
||||
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>,
|
||||
union_layout: &UnionLayout<'a>,
|
||||
|
@ -804,7 +850,7 @@ fn build_tag_eq<'a, 'ctx, 'env>(
|
|||
let function = match env.module.get_function(fn_name.as_str()) {
|
||||
Some(function_value) => function_value,
|
||||
None => {
|
||||
let arg_type = argument_type_from_union_layout(env, union_layout);
|
||||
let arg_type = argument_type_from_union_layout(env, layout_interner, union_layout);
|
||||
|
||||
let function_value = crate::llvm::refcounting::build_header_help(
|
||||
env,
|
||||
|
@ -815,6 +861,7 @@ fn build_tag_eq<'a, 'ctx, 'env>(
|
|||
|
||||
build_tag_eq_help(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
when_recursive,
|
||||
function_value,
|
||||
|
@ -839,6 +886,7 @@ fn build_tag_eq<'a, 'ctx, 'env>(
|
|||
|
||||
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>,
|
||||
|
@ -919,8 +967,8 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
|
|||
|
||||
env.builder.position_at_end(compare_tag_ids);
|
||||
|
||||
let id1 = get_tag_id(env, parent, union_layout, tag1);
|
||||
let id2 = get_tag_id(env, parent, union_layout, tag2);
|
||||
let id1 = get_tag_id(env, layout_interner, parent, union_layout, tag1);
|
||||
let id2 = get_tag_id(env, layout_interner, parent, union_layout, tag2);
|
||||
|
||||
// clear the tag_id so we get a pointer to the actual data
|
||||
let tag1 = tag1.into_pointer_value();
|
||||
|
@ -947,9 +995,10 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
|
|||
|
||||
let answer = eq_ptr_to_struct(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
union_layout,
|
||||
Some(when_recursive.clone()),
|
||||
Some(when_recursive),
|
||||
field_layouts,
|
||||
tag1,
|
||||
tag2,
|
||||
|
@ -989,8 +1038,8 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
|
|||
|
||||
env.builder.position_at_end(compare_tag_ids);
|
||||
|
||||
let id1 = get_tag_id(env, parent, union_layout, tag1);
|
||||
let id2 = get_tag_id(env, parent, union_layout, tag2);
|
||||
let id1 = get_tag_id(env, layout_interner, parent, union_layout, tag1);
|
||||
let id2 = get_tag_id(env, layout_interner, parent, union_layout, tag2);
|
||||
|
||||
// clear the tag_id so we get a pointer to the actual data
|
||||
let tag1 = tag_pointer_clear_tag_id(env, tag1.into_pointer_value());
|
||||
|
@ -1017,6 +1066,7 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
|
|||
|
||||
let answer = eq_ptr_to_struct(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
union_layout,
|
||||
None,
|
||||
|
@ -1077,6 +1127,7 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
|
|||
|
||||
let answer = eq_ptr_to_struct(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
union_layout,
|
||||
None,
|
||||
|
@ -1145,8 +1196,8 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
|
|||
|
||||
env.builder.position_at_end(compare_other);
|
||||
|
||||
let id1 = get_tag_id(env, parent, union_layout, tag1);
|
||||
let id2 = get_tag_id(env, parent, union_layout, tag2);
|
||||
let id1 = get_tag_id(env, layout_interner, parent, union_layout, tag1);
|
||||
let id2 = get_tag_id(env, layout_interner, parent, union_layout, tag2);
|
||||
|
||||
// clear the tag_id so we get a pointer to the actual data
|
||||
let tag1 = tag_pointer_clear_tag_id(env, tag1.into_pointer_value());
|
||||
|
@ -1174,6 +1225,7 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
|
|||
|
||||
let answer = eq_ptr_to_struct(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
union_layout,
|
||||
None,
|
||||
|
@ -1212,6 +1264,7 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
|
|||
|
||||
let answer = eq_ptr_to_struct(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
union_layout,
|
||||
None,
|
||||
|
@ -1227,6 +1280,7 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
|
|||
|
||||
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>>,
|
||||
|
@ -1236,40 +1290,35 @@ fn eq_ptr_to_struct<'a, 'ctx, 'env>(
|
|||
) -> IntValue<'ctx> {
|
||||
let struct_layout = Layout::struct_no_name_order(field_layouts);
|
||||
|
||||
let wrapper_type = basic_type_from_layout(env, &struct_layout);
|
||||
let wrapper_type = basic_type_from_layout(env, layout_interner, &struct_layout);
|
||||
debug_assert!(wrapper_type.is_struct_type());
|
||||
|
||||
// cast the opaque pointer to a pointer of the correct shape
|
||||
let struct1_ptr = env
|
||||
.builder
|
||||
.build_bitcast(
|
||||
tag1,
|
||||
wrapper_type.ptr_type(AddressSpace::Generic),
|
||||
"opaque_to_correct",
|
||||
)
|
||||
.into_pointer_value();
|
||||
let struct1_ptr = env.builder.build_pointer_cast(
|
||||
tag1,
|
||||
wrapper_type.ptr_type(AddressSpace::Generic),
|
||||
"opaque_to_correct",
|
||||
);
|
||||
|
||||
let struct2_ptr = env
|
||||
.builder
|
||||
.build_bitcast(
|
||||
tag2,
|
||||
wrapper_type.ptr_type(AddressSpace::Generic),
|
||||
"opaque_to_correct",
|
||||
)
|
||||
.into_pointer_value();
|
||||
let struct2_ptr = env.builder.build_pointer_cast(
|
||||
tag2,
|
||||
wrapper_type.ptr_type(AddressSpace::Generic),
|
||||
"opaque_to_correct",
|
||||
);
|
||||
|
||||
let struct1 = env
|
||||
.builder
|
||||
.build_load(struct1_ptr, "load_struct1")
|
||||
.new_build_load(wrapper_type, struct1_ptr, "load_struct1")
|
||||
.into_struct_value();
|
||||
|
||||
let struct2 = env
|
||||
.builder
|
||||
.build_load(struct2_ptr, "load_struct2")
|
||||
.new_build_load(wrapper_type, struct2_ptr, "load_struct2")
|
||||
.into_struct_value();
|
||||
|
||||
build_struct_eq(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
field_layouts,
|
||||
opt_when_recursive.unwrap_or(WhenRecursive::Loop(*union_layout)),
|
||||
|
@ -1283,10 +1332,11 @@ fn eq_ptr_to_struct<'a, 'ctx, 'env>(
|
|||
|
||||
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: &Layout<'a>,
|
||||
inner_layout: &Layout<'a>,
|
||||
inner_layout: InLayout<'a>,
|
||||
tag1: BasicValueEnum<'ctx>,
|
||||
tag2: BasicValueEnum<'ctx>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
|
@ -1301,7 +1351,7 @@ fn build_box_eq<'a, 'ctx, 'env>(
|
|||
let function = match env.module.get_function(fn_name.as_str()) {
|
||||
Some(function_value) => function_value,
|
||||
None => {
|
||||
let arg_type = basic_type_from_layout(env, box_layout);
|
||||
let arg_type = basic_type_from_layout(env, layout_interner, box_layout);
|
||||
|
||||
let function_value = crate::llvm::refcounting::build_header_help(
|
||||
env,
|
||||
|
@ -1312,6 +1362,7 @@ fn build_box_eq<'a, 'ctx, 'env>(
|
|||
|
||||
build_box_eq_help(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
when_recursive,
|
||||
function_value,
|
||||
|
@ -1336,10 +1387,11 @@ fn build_box_eq<'a, 'ctx, 'env>(
|
|||
|
||||
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: &Layout<'a>,
|
||||
inner_layout: InLayout<'a>,
|
||||
) {
|
||||
let ctx = env.context;
|
||||
let builder = env.builder;
|
||||
|
@ -1403,11 +1455,14 @@ fn build_box_eq_help<'a, 'ctx, 'env>(
|
|||
let box1 = box1.into_pointer_value();
|
||||
let box2 = box2.into_pointer_value();
|
||||
|
||||
let value1 = load_roc_value(env, *inner_layout, box1, "load_box1");
|
||||
let value2 = load_roc_value(env, *inner_layout, box2, "load_box2");
|
||||
let inner_layout = layout_interner.get(inner_layout);
|
||||
|
||||
let value1 = load_roc_value(env, layout_interner, *inner_layout, box1, "load_box1");
|
||||
let value2 = load_roc_value(env, layout_interner, *inner_layout, box2, "load_box2");
|
||||
|
||||
let is_equal = build_eq(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
value1,
|
||||
value2,
|
||||
|
|
|
@ -1,21 +1,23 @@
|
|||
use crate::llvm::build::Env;
|
||||
use crate::llvm::build::{BuilderExt, Env};
|
||||
use bumpalo::collections::Vec;
|
||||
use inkwell::context::Context;
|
||||
use inkwell::types::{BasicType, BasicTypeEnum, FloatType, IntType, StructType};
|
||||
use inkwell::values::StructValue;
|
||||
use inkwell::AddressSpace;
|
||||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||
use roc_intern::Interner;
|
||||
use roc_mono::layout::{round_up_to_alignment, Builtin, Layout, STLayoutInterner, UnionLayout};
|
||||
use roc_target::TargetInfo;
|
||||
|
||||
fn basic_type_from_record<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
fields: &[Layout<'_>],
|
||||
) -> BasicTypeEnum<'ctx> {
|
||||
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, field_layout));
|
||||
field_types.push(basic_type_from_layout(env, layout_interner, field_layout));
|
||||
}
|
||||
|
||||
env.context
|
||||
|
@ -25,6 +27,7 @@ fn basic_type_from_record<'a, 'ctx, 'env>(
|
|||
|
||||
pub fn basic_type_from_layout<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &'env mut STLayoutInterner<'a>,
|
||||
layout: &Layout<'_>,
|
||||
) -> BasicTypeEnum<'ctx> {
|
||||
use Layout::*;
|
||||
|
@ -33,16 +36,19 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>(
|
|||
Struct {
|
||||
field_layouts: sorted_fields,
|
||||
..
|
||||
} => basic_type_from_record(env, sorted_fields),
|
||||
LambdaSet(lambda_set) => {
|
||||
basic_type_from_layout(env, &lambda_set.runtime_representation(env.layout_interner))
|
||||
}
|
||||
} => basic_type_from_record(env, layout_interner, sorted_fields),
|
||||
LambdaSet(lambda_set) => basic_type_from_layout(
|
||||
env,
|
||||
layout_interner,
|
||||
&lambda_set.runtime_representation(layout_interner),
|
||||
),
|
||||
Boxed(inner_layout) => {
|
||||
let inner_type = basic_type_from_layout(env, inner_layout);
|
||||
let inner_layout = layout_interner.get(*inner_layout);
|
||||
let inner_type = basic_type_from_layout(env, layout_interner, inner_layout);
|
||||
|
||||
inner_type.ptr_type(AddressSpace::Generic).into()
|
||||
}
|
||||
Union(union_layout) => basic_type_from_union_layout(env, union_layout),
|
||||
Union(union_layout) => basic_type_from_union_layout(env, layout_interner, union_layout),
|
||||
RecursivePointer => env
|
||||
.context
|
||||
.i64_type()
|
||||
|
@ -53,63 +59,59 @@ pub fn basic_type_from_layout<'a, 'ctx, 'env>(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn basic_type_from_union_layout<'a, 'ctx, 'env>(
|
||||
pub fn struct_type_from_union_layout<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
union_layout: &UnionLayout<'_>,
|
||||
) -> BasicTypeEnum<'ctx> {
|
||||
) -> StructType<'ctx> {
|
||||
use UnionLayout::*;
|
||||
|
||||
match union_layout {
|
||||
NonRecursive(tags) => {
|
||||
//
|
||||
RocUnion::tagged_from_slices(env.layout_interner, env.context, tags, env.target_info)
|
||||
RocUnion::tagged_from_slices(layout_interner, env.context, tags, env.target_info)
|
||||
.struct_type()
|
||||
.into()
|
||||
}
|
||||
Recursive(tags)
|
||||
| NullableWrapped {
|
||||
other_tags: tags, ..
|
||||
} => {
|
||||
if union_layout.stores_tag_id_as_data(env.target_info) {
|
||||
RocUnion::tagged_from_slices(
|
||||
env.layout_interner,
|
||||
env.context,
|
||||
tags,
|
||||
env.target_info,
|
||||
)
|
||||
.struct_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.into()
|
||||
RocUnion::tagged_from_slices(layout_interner, env.context, tags, env.target_info)
|
||||
.struct_type()
|
||||
} else {
|
||||
RocUnion::untagged_from_slices(
|
||||
env.layout_interner,
|
||||
env.context,
|
||||
tags,
|
||||
env.target_info,
|
||||
)
|
||||
.struct_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.into()
|
||||
RocUnion::untagged_from_slices(layout_interner, env.context, tags, env.target_info)
|
||||
.struct_type()
|
||||
}
|
||||
}
|
||||
NullableUnwrapped { other_fields, .. } => RocUnion::untagged_from_slices(
|
||||
env.layout_interner,
|
||||
layout_interner,
|
||||
env.context,
|
||||
&[other_fields],
|
||||
env.target_info,
|
||||
)
|
||||
.struct_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.into(),
|
||||
NonNullableUnwrapped(fields) => RocUnion::untagged_from_slices(
|
||||
env.layout_interner,
|
||||
env.context,
|
||||
&[fields],
|
||||
env.target_info,
|
||||
)
|
||||
.struct_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.into(),
|
||||
.struct_type(),
|
||||
NonNullableUnwrapped(fields) => {
|
||||
RocUnion::untagged_from_slices(layout_interner, env.context, &[fields], env.target_info)
|
||||
.struct_type()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn basic_type_from_union_layout<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
union_layout: &UnionLayout<'_>,
|
||||
) -> BasicTypeEnum<'ctx> {
|
||||
use UnionLayout::*;
|
||||
|
||||
let struct_type = struct_type_from_union_layout(env, layout_interner, union_layout);
|
||||
|
||||
match union_layout {
|
||||
NonRecursive(_) => struct_type.into(),
|
||||
Recursive(_)
|
||||
| NonNullableUnwrapped(_)
|
||||
| NullableWrapped { .. }
|
||||
| NullableUnwrapped { .. } => struct_type.ptr_type(AddressSpace::Generic).into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,34 +146,38 @@ pub fn basic_type_from_builtin<'a, 'ctx, 'env>(
|
|||
/// is not currently implemented
|
||||
pub fn argument_type_from_layout<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout: &Layout<'_>,
|
||||
) -> BasicTypeEnum<'ctx> {
|
||||
use Layout::*;
|
||||
|
||||
match layout {
|
||||
LambdaSet(lambda_set) => {
|
||||
argument_type_from_layout(env, &lambda_set.runtime_representation(env.layout_interner))
|
||||
}
|
||||
Union(union_layout) => argument_type_from_union_layout(env, union_layout),
|
||||
LambdaSet(lambda_set) => argument_type_from_layout(
|
||||
env,
|
||||
layout_interner,
|
||||
&lambda_set.runtime_representation(layout_interner),
|
||||
),
|
||||
Union(union_layout) => argument_type_from_union_layout(env, layout_interner, union_layout),
|
||||
Builtin(_) => {
|
||||
let base = basic_type_from_layout(env, layout);
|
||||
let base = basic_type_from_layout(env, layout_interner, layout);
|
||||
|
||||
if layout.is_passed_by_reference(env.layout_interner, env.target_info) {
|
||||
if layout.is_passed_by_reference(layout_interner, env.target_info) {
|
||||
base.ptr_type(AddressSpace::Generic).into()
|
||||
} else {
|
||||
base
|
||||
}
|
||||
}
|
||||
other => basic_type_from_layout(env, other),
|
||||
other => basic_type_from_layout(env, layout_interner, other),
|
||||
}
|
||||
}
|
||||
|
||||
/// Non-recursive tag unions are stored on the stack, but passed by-reference
|
||||
pub fn argument_type_from_union_layout<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
union_layout: &UnionLayout<'_>,
|
||||
) -> BasicTypeEnum<'ctx> {
|
||||
let heap_type = basic_type_from_union_layout(env, union_layout);
|
||||
let heap_type = basic_type_from_union_layout(env, layout_interner, union_layout);
|
||||
|
||||
if let UnionLayout::NonRecursive(_) = union_layout {
|
||||
heap_type.ptr_type(AddressSpace::Generic).into()
|
||||
|
@ -202,7 +208,6 @@ pub fn float_type_from_float_width<'a, 'ctx, 'env>(
|
|||
use FloatWidth::*;
|
||||
|
||||
match float_width {
|
||||
F128 => todo!("F128 is not implemented"),
|
||||
F64 => env.context.f64_type(),
|
||||
F32 => env.context.f32_type(),
|
||||
}
|
||||
|
@ -364,7 +369,12 @@ impl<'ctx> RocUnion<'ctx> {
|
|||
|
||||
let data_buffer = env
|
||||
.builder
|
||||
.build_struct_gep(tag_alloca, Self::TAG_DATA_INDEX, "data_buffer")
|
||||
.new_build_struct_gep(
|
||||
self.struct_type(),
|
||||
tag_alloca,
|
||||
Self::TAG_DATA_INDEX,
|
||||
"data_buffer",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let cast_pointer = env.builder.build_pointer_cast(
|
||||
|
@ -390,7 +400,12 @@ impl<'ctx> RocUnion<'ctx> {
|
|||
|
||||
let tag_id_ptr = env
|
||||
.builder
|
||||
.build_struct_gep(tag_alloca, Self::TAG_ID_INDEX, "tag_id_ptr")
|
||||
.new_build_struct_gep(
|
||||
self.struct_type(),
|
||||
tag_alloca,
|
||||
Self::TAG_ID_INDEX,
|
||||
"tag_id_ptr",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let tag_id = tag_id_type.const_int(tag_id as u64, false);
|
||||
|
@ -399,7 +414,7 @@ impl<'ctx> RocUnion<'ctx> {
|
|||
}
|
||||
|
||||
env.builder
|
||||
.build_load(tag_alloca, "load_tag")
|
||||
.new_build_load(self.struct_type(), tag_alloca, "load_tag")
|
||||
.into_struct_value()
|
||||
}
|
||||
}
|
||||
|
@ -431,6 +446,30 @@ pub fn zig_has_tag_id_type<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> StructT
|
|||
.struct_type(&[env.context.bool_type().into(), u8_ptr_t.into()], false)
|
||||
}
|
||||
|
||||
pub fn zig_num_parse_result_type<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
type_name: &str,
|
||||
) -> StructType<'ctx> {
|
||||
let name = format!("num.NumParseResult({type_name})");
|
||||
|
||||
match env.module.get_struct_type(&name) {
|
||||
Some(zig_type) => zig_type,
|
||||
None => panic!("zig does not define the `{name}` type!"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn zig_to_int_checked_result_type<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
type_name: &str,
|
||||
) -> StructType<'ctx> {
|
||||
let name = format!("num.ToIntCheckedResult({type_name})");
|
||||
|
||||
match env.module.get_struct_type(&name) {
|
||||
Some(zig_type) => zig_type,
|
||||
None => panic!("zig does not define the `{name}` type!"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn zig_with_overflow_roc_dec<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> StructType<'ctx> {
|
||||
env.module
|
||||
.get_struct_type("utils.WithOverflow(dec.RocDec)")
|
||||
|
|
|
@ -5,18 +5,48 @@ use crate::llvm::build_list::{self, incrementing_elem_loop};
|
|||
use crate::llvm::convert::{basic_type_from_layout, RocUnion};
|
||||
use inkwell::builder::Builder;
|
||||
use inkwell::module::Linkage;
|
||||
use inkwell::types::{BasicMetadataTypeEnum, BasicType};
|
||||
use inkwell::types::{BasicMetadataTypeEnum, BasicType, BasicTypeEnum};
|
||||
use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue};
|
||||
use inkwell::AddressSpace;
|
||||
use roc_builtins::bitcode;
|
||||
use roc_intern::Interner;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout};
|
||||
use roc_mono::ir::LookupType;
|
||||
use roc_mono::layout::{Builtin, Layout, LayoutIds, STLayoutInterner, UnionLayout};
|
||||
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,
|
||||
Scope, WhenRecursive,
|
||||
};
|
||||
use super::convert::struct_type_from_union_layout;
|
||||
|
||||
pub(crate) struct SharedMemoryPointer<'ctx>(PointerValue<'ctx>);
|
||||
|
||||
impl<'ctx> SharedMemoryPointer<'ctx> {
|
||||
pub(crate) fn get<'a, 'env>(env: &Env<'a, 'ctx, 'env>) -> Self {
|
||||
let start_function = if let LlvmBackendMode::BinaryDev = env.mode {
|
||||
bitcode::UTILS_EXPECT_FAILED_START_SHARED_FILE
|
||||
} else {
|
||||
bitcode::UTILS_EXPECT_FAILED_START_SHARED_BUFFER
|
||||
};
|
||||
|
||||
let func = env.module.get_function(start_function).unwrap();
|
||||
|
||||
let call_result = env
|
||||
.builder
|
||||
.build_call(func, &[], "call_expect_start_failed");
|
||||
|
||||
let ptr = call_result
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap()
|
||||
.into_pointer_value();
|
||||
|
||||
Self(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct Cursors<'ctx> {
|
||||
|
@ -26,10 +56,11 @@ struct Cursors<'ctx> {
|
|||
|
||||
fn pointer_at_offset<'ctx>(
|
||||
bd: &Builder<'ctx>,
|
||||
element_type: impl BasicType<'ctx>,
|
||||
ptr: PointerValue<'ctx>,
|
||||
offset: IntValue<'ctx>,
|
||||
) -> PointerValue<'ctx> {
|
||||
unsafe { bd.build_gep(ptr, &[offset], "offset_ptr") }
|
||||
unsafe { bd.new_build_in_bounds_gep(element_type, ptr, &[offset], "offset_ptr") }
|
||||
}
|
||||
|
||||
/// Writes the module and region into the buffer
|
||||
|
@ -70,10 +101,12 @@ fn read_state<'a, 'ctx, 'env>(
|
|||
let ptr = env.builder.build_pointer_cast(ptr, ptr_type, "");
|
||||
|
||||
let one = env.ptr_int().const_int(1, false);
|
||||
let offset_ptr = pointer_at_offset(env.builder, ptr, one);
|
||||
let offset_ptr = pointer_at_offset(env.builder, env.ptr_int(), ptr, one);
|
||||
|
||||
let count = env.builder.build_load(ptr, "load_count");
|
||||
let offset = env.builder.build_load(offset_ptr, "load_offset");
|
||||
let count = env.builder.new_build_load(env.ptr_int(), ptr, "load_count");
|
||||
let offset = env
|
||||
.builder
|
||||
.new_build_load(env.ptr_int(), offset_ptr, "load_offset");
|
||||
|
||||
(count.into_int_value(), offset.into_int_value())
|
||||
}
|
||||
|
@ -88,47 +121,61 @@ fn write_state<'a, 'ctx, 'env>(
|
|||
let ptr = env.builder.build_pointer_cast(ptr, ptr_type, "");
|
||||
|
||||
let one = env.ptr_int().const_int(1, false);
|
||||
let offset_ptr = pointer_at_offset(env.builder, ptr, one);
|
||||
let offset_ptr = pointer_at_offset(env.builder, env.ptr_int(), ptr, one);
|
||||
|
||||
env.builder.build_store(ptr, count);
|
||||
env.builder.build_store(offset_ptr, offset);
|
||||
}
|
||||
|
||||
pub(crate) fn finalize(env: &Env) {
|
||||
pub(crate) fn notify_parent_expect(env: &Env, shared_memory: &SharedMemoryPointer) {
|
||||
let func = env
|
||||
.module
|
||||
.get_function(bitcode::UTILS_EXPECT_FAILED_FINALIZE)
|
||||
.get_function(bitcode::NOTIFY_PARENT_EXPECT)
|
||||
.unwrap();
|
||||
|
||||
env.builder
|
||||
.build_call(func, &[], "call_expect_failed_finalize");
|
||||
env.builder.build_call(
|
||||
func,
|
||||
&[shared_memory.0.into()],
|
||||
"call_expect_failed_finalize",
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn notify_parent_dbg(env: &Env, shared_memory: &SharedMemoryPointer) {
|
||||
let func = env.module.get_function(bitcode::NOTIFY_PARENT_DBG).unwrap();
|
||||
|
||||
env.builder.build_call(
|
||||
func,
|
||||
&[shared_memory.0.into()],
|
||||
"call_expect_failed_finalize",
|
||||
);
|
||||
}
|
||||
|
||||
// Shape of expect frame:
|
||||
//
|
||||
// ===
|
||||
// Fixed-size header
|
||||
// ===
|
||||
// /-- ptr_lookup_1 (ptr_size)
|
||||
// | var_lookup_1 (u32)
|
||||
// | ..
|
||||
// | ptr_lookup_n (ptr_size)
|
||||
// | var_lookup_n (u32)
|
||||
// \-> lookup_val_1 (varsize)
|
||||
// ..
|
||||
// lookup_val_n (varsize)
|
||||
//
|
||||
pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
scope: &Scope<'a, 'ctx>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
shared_memory: &SharedMemoryPointer<'ctx>,
|
||||
condition: Symbol,
|
||||
region: Region,
|
||||
lookups: &[Symbol],
|
||||
lookup_variables: &[LookupType],
|
||||
) {
|
||||
let start_function = if let LlvmBackendMode::BinaryDev = env.mode {
|
||||
bitcode::UTILS_EXPECT_FAILED_START_SHARED_FILE
|
||||
} else {
|
||||
bitcode::UTILS_EXPECT_FAILED_START_SHARED_BUFFER
|
||||
};
|
||||
|
||||
let func = env.module.get_function(start_function).unwrap();
|
||||
|
||||
let call_result = env
|
||||
.builder
|
||||
.build_call(func, &[], "call_expect_start_failed");
|
||||
|
||||
let original_ptr = call_result
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap()
|
||||
.into_pointer_value();
|
||||
let original_ptr = shared_memory.0;
|
||||
|
||||
let (count, mut offset) = read_state(env, original_ptr);
|
||||
|
||||
|
@ -136,9 +183,11 @@ pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
|
|||
|
||||
let after_header = offset;
|
||||
|
||||
let space_for_offsets = env
|
||||
.ptr_int()
|
||||
.const_int((lookups.len() * env.target_info.ptr_size()) as _, false);
|
||||
let space_for_offsets = env.ptr_int().const_int(
|
||||
(lookups.len() * env.target_info.ptr_size() + lookups.len() * std::mem::size_of::<u32>())
|
||||
as _,
|
||||
false,
|
||||
);
|
||||
|
||||
let mut lookup_starts = bumpalo::collections::Vec::with_capacity_in(lookups.len(), env.arena);
|
||||
|
||||
|
@ -152,7 +201,7 @@ pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
|
|||
let (value, layout) = load_symbol_and_layout(scope, lookup);
|
||||
|
||||
let stack_size = env.ptr_int().const_int(
|
||||
layout.stack_size(env.layout_interner, env.target_info) as u64,
|
||||
layout.stack_size(layout_interner, env.target_info) as u64,
|
||||
false,
|
||||
);
|
||||
|
||||
|
@ -165,6 +214,7 @@ pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
|
|||
|
||||
extra_offset = build_clone(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
original_ptr,
|
||||
cursors,
|
||||
|
@ -179,14 +229,47 @@ pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
|
|||
{
|
||||
let mut offset = after_header;
|
||||
|
||||
for lookup_start in lookup_starts {
|
||||
build_copy(env, original_ptr, offset, lookup_start.into());
|
||||
for (lookup_start, lookup_var) in lookup_starts.into_iter().zip(lookup_variables) {
|
||||
// Store the pointer to the value
|
||||
{
|
||||
build_copy(env, original_ptr, offset, lookup_start.into());
|
||||
|
||||
let ptr_width = env
|
||||
.ptr_int()
|
||||
.const_int(env.target_info.ptr_size() as _, false);
|
||||
let ptr_width = env
|
||||
.ptr_int()
|
||||
.const_int(env.target_info.ptr_size() as _, false);
|
||||
|
||||
offset = env.builder.build_int_add(offset, ptr_width, "offset")
|
||||
offset = env.builder.build_int_add(offset, ptr_width, "offset");
|
||||
}
|
||||
|
||||
// Store the specialized variable of the value
|
||||
{
|
||||
let ptr = unsafe {
|
||||
env.builder.new_build_in_bounds_gep(
|
||||
env.context.i8_type(),
|
||||
original_ptr,
|
||||
&[offset],
|
||||
"at_current_offset",
|
||||
)
|
||||
};
|
||||
|
||||
let u32_ptr = env.context.i32_type().ptr_type(AddressSpace::Generic);
|
||||
let ptr = env
|
||||
.builder
|
||||
.build_pointer_cast(ptr, u32_ptr, "cast_ptr_type");
|
||||
|
||||
let var_value = env
|
||||
.context
|
||||
.i32_type()
|
||||
.const_int(lookup_var.index() as _, false);
|
||||
|
||||
env.builder.build_store(ptr, var_value);
|
||||
|
||||
let var_size = env
|
||||
.ptr_int()
|
||||
.const_int(std::mem::size_of::<u32>() as _, false);
|
||||
|
||||
offset = env.builder.build_int_add(offset, var_size, "offset");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -195,16 +278,9 @@ pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
|
|||
write_state(env, original_ptr, new_count, offset)
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Copy)]
|
||||
enum WhenRecursive<'a> {
|
||||
Unreachable,
|
||||
#[allow(dead_code)]
|
||||
Loop(UnionLayout<'a>),
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn build_clone<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
ptr: PointerValue<'ctx>,
|
||||
cursors: Cursors<'ctx>,
|
||||
|
@ -215,6 +291,7 @@ fn build_clone<'a, 'ctx, 'env>(
|
|||
match layout {
|
||||
Layout::Builtin(builtin) => build_clone_builtin(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
ptr,
|
||||
cursors,
|
||||
|
@ -225,6 +302,7 @@ fn build_clone<'a, 'ctx, 'env>(
|
|||
|
||||
Layout::Struct { field_layouts, .. } => build_clone_struct(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
ptr,
|
||||
cursors,
|
||||
|
@ -238,10 +316,14 @@ fn build_clone<'a, 'ctx, 'env>(
|
|||
Layout::LambdaSet(_) => cursors.extra_offset,
|
||||
|
||||
Layout::Union(union_layout) => {
|
||||
if layout.safe_to_memcpy(env.layout_interner) {
|
||||
if layout.safe_to_memcpy(layout_interner) {
|
||||
let ptr = unsafe {
|
||||
env.builder
|
||||
.build_in_bounds_gep(ptr, &[cursors.offset], "at_current_offset")
|
||||
env.builder.new_build_in_bounds_gep(
|
||||
env.context.i8_type(),
|
||||
ptr,
|
||||
&[cursors.offset],
|
||||
"at_current_offset",
|
||||
)
|
||||
};
|
||||
|
||||
let ptr_type = value.get_type().ptr_type(AddressSpace::Generic);
|
||||
|
@ -249,12 +331,13 @@ fn build_clone<'a, 'ctx, 'env>(
|
|||
.builder
|
||||
.build_pointer_cast(ptr, ptr_type, "cast_ptr_type");
|
||||
|
||||
store_roc_value(env, layout, ptr, value);
|
||||
store_roc_value(env, layout_interner, layout, ptr, value);
|
||||
|
||||
cursors.extra_offset
|
||||
} else {
|
||||
build_clone_tag(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
ptr,
|
||||
cursors,
|
||||
|
@ -270,10 +353,11 @@ fn build_clone<'a, 'ctx, 'env>(
|
|||
build_copy(env, ptr, cursors.offset, cursors.extra_offset.into());
|
||||
|
||||
let source = value.into_pointer_value();
|
||||
let value = load_roc_value(env, *inner_layout, source, "inner");
|
||||
let inner_layout = layout_interner.get(inner_layout);
|
||||
let value = load_roc_value(env, layout_interner, *inner_layout, source, "inner");
|
||||
|
||||
let inner_width = env.ptr_int().const_int(
|
||||
inner_layout.stack_size(env.layout_interner, env.target_info) as u64,
|
||||
inner_layout.stack_size(layout_interner, env.target_info) as u64,
|
||||
false,
|
||||
);
|
||||
|
||||
|
@ -288,6 +372,7 @@ fn build_clone<'a, 'ctx, 'env>(
|
|||
|
||||
build_clone(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
ptr,
|
||||
cursors,
|
||||
|
@ -305,17 +390,22 @@ fn build_clone<'a, 'ctx, 'env>(
|
|||
WhenRecursive::Loop(union_layout) => {
|
||||
let layout = Layout::Union(union_layout);
|
||||
|
||||
let bt = basic_type_from_layout(env, &layout);
|
||||
let bt = basic_type_from_layout(env, layout_interner, &layout);
|
||||
|
||||
// cast the i64 pointer to a pointer to block of memory
|
||||
let field1_cast = env.builder.build_bitcast(value, bt, "i64_to_opaque");
|
||||
let field1_cast = env.builder.build_pointer_cast(
|
||||
value.into_pointer_value(),
|
||||
bt.into_pointer_type(),
|
||||
"i64_to_opaque",
|
||||
);
|
||||
|
||||
build_clone_tag(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
ptr,
|
||||
cursors,
|
||||
field1_cast,
|
||||
field1_cast.into(),
|
||||
union_layout,
|
||||
WhenRecursive::Loop(union_layout),
|
||||
)
|
||||
|
@ -324,9 +414,9 @@ fn build_clone<'a, 'ctx, 'env>(
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn build_clone_struct<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
ptr: PointerValue<'ctx>,
|
||||
cursors: Cursors<'ctx>,
|
||||
|
@ -336,7 +426,7 @@ fn build_clone_struct<'a, 'ctx, 'env>(
|
|||
) -> IntValue<'ctx> {
|
||||
let layout = Layout::struct_no_name_order(field_layouts);
|
||||
|
||||
if layout.safe_to_memcpy(env.layout_interner) {
|
||||
if layout.safe_to_memcpy(layout_interner) {
|
||||
build_copy(env, ptr, cursors.offset, value)
|
||||
} else {
|
||||
let mut cursors = cursors;
|
||||
|
@ -349,10 +439,11 @@ fn build_clone_struct<'a, 'ctx, 'env>(
|
|||
.build_extract_value(structure, i as _, "extract")
|
||||
.unwrap();
|
||||
|
||||
let field = use_roc_value(env, *field_layout, field, "field");
|
||||
let field = use_roc_value(env, layout_interner, *field_layout, field, "field");
|
||||
|
||||
let new_extra = build_clone(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
ptr,
|
||||
cursors,
|
||||
|
@ -362,7 +453,7 @@ fn build_clone_struct<'a, 'ctx, 'env>(
|
|||
);
|
||||
|
||||
let field_width = env.ptr_int().const_int(
|
||||
field_layout.stack_size(env.layout_interner, env.target_info) as u64,
|
||||
field_layout.stack_size(layout_interner, env.target_info) as u64,
|
||||
false,
|
||||
);
|
||||
|
||||
|
@ -376,9 +467,9 @@ fn build_clone_struct<'a, 'ctx, 'env>(
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn build_clone_tag<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
ptr: PointerValue<'ctx>,
|
||||
cursors: Cursors<'ctx>,
|
||||
|
@ -421,6 +512,7 @@ fn build_clone_tag<'a, 'ctx, 'env>(
|
|||
|
||||
build_clone_tag_help(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
union_layout,
|
||||
when_recursive,
|
||||
|
@ -453,9 +545,37 @@ fn build_clone_tag<'a, 'ctx, 'env>(
|
|||
result.into_int_value()
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn load_tag_data<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
union_layout: UnionLayout<'a>,
|
||||
tag_value: PointerValue<'ctx>,
|
||||
tag_type: BasicTypeEnum<'ctx>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let union_struct_type = struct_type_from_union_layout(env, layout_interner, &union_layout);
|
||||
|
||||
let raw_data_ptr = env
|
||||
.builder
|
||||
.new_build_struct_gep(
|
||||
union_struct_type,
|
||||
tag_value,
|
||||
RocUnion::TAG_DATA_INDEX,
|
||||
"tag_data",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let data_ptr = env.builder.build_pointer_cast(
|
||||
raw_data_ptr,
|
||||
tag_type.ptr_type(AddressSpace::Generic),
|
||||
"data_ptr",
|
||||
);
|
||||
|
||||
env.builder.new_build_load(tag_type, data_ptr, "load_data")
|
||||
}
|
||||
|
||||
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>,
|
||||
|
@ -501,7 +621,7 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
|||
env.builder.build_unreachable();
|
||||
}
|
||||
NonRecursive(tags) => {
|
||||
let id = get_tag_id(env, parent, &union_layout, tag_value);
|
||||
let id = get_tag_id(env, layout_interner, parent, &union_layout, tag_value);
|
||||
|
||||
let switch_block = env.context.append_basic_block(parent, "switch_block");
|
||||
env.builder.build_unconditional_branch(switch_block);
|
||||
|
@ -512,31 +632,30 @@ 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 raw_data_ptr = env
|
||||
.builder
|
||||
.build_struct_gep(
|
||||
tag_value.into_pointer_value(),
|
||||
RocUnion::TAG_DATA_INDEX,
|
||||
"tag_data",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let layout = Layout::struct_no_name_order(field_layouts);
|
||||
let layout = Layout::struct_no_name_order(
|
||||
env.arena.alloc([layout, union_layout.tag_id_layout()]),
|
||||
);
|
||||
let basic_type = basic_type_from_layout(env, &layout);
|
||||
|
||||
let data_ptr = env.builder.build_pointer_cast(
|
||||
raw_data_ptr,
|
||||
basic_type.ptr_type(AddressSpace::Generic),
|
||||
"data_ptr",
|
||||
let basic_type = basic_type_from_layout(env, layout_interner, &layout);
|
||||
let data = load_tag_data(
|
||||
env,
|
||||
layout_interner,
|
||||
union_layout,
|
||||
tag_value.into_pointer_value(),
|
||||
basic_type,
|
||||
);
|
||||
|
||||
let data = env.builder.build_load(data_ptr, "load_data");
|
||||
|
||||
let answer =
|
||||
build_clone(env, layout_ids, ptr, cursors, data, layout, when_recursive);
|
||||
let answer = build_clone(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
ptr,
|
||||
cursors,
|
||||
data,
|
||||
layout,
|
||||
when_recursive,
|
||||
);
|
||||
|
||||
env.builder.build_return(Some(&answer));
|
||||
|
||||
|
@ -556,7 +675,7 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
|||
}
|
||||
}
|
||||
Recursive(tags) => {
|
||||
let id = get_tag_id(env, parent, &union_layout, tag_value);
|
||||
let id = get_tag_id(env, layout_interner, parent, &union_layout, tag_value);
|
||||
|
||||
let switch_block = env.context.append_basic_block(parent, "switch_block");
|
||||
env.builder.build_unconditional_branch(switch_block);
|
||||
|
@ -572,11 +691,6 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
|||
|
||||
let tag_value = tag_pointer_clear_tag_id(env, tag_value.into_pointer_value());
|
||||
|
||||
let raw_data_ptr = env
|
||||
.builder
|
||||
.build_struct_gep(tag_value, RocUnion::TAG_DATA_INDEX, "tag_data")
|
||||
.unwrap();
|
||||
|
||||
let layout = Layout::struct_no_name_order(field_layouts);
|
||||
let layout = if union_layout.stores_tag_id_in_pointer(env.target_info) {
|
||||
layout
|
||||
|
@ -585,18 +699,12 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
|||
env.arena.alloc([layout, union_layout.tag_id_layout()]),
|
||||
)
|
||||
};
|
||||
let basic_type = basic_type_from_layout(env, &layout);
|
||||
|
||||
let data_ptr = env.builder.build_pointer_cast(
|
||||
raw_data_ptr,
|
||||
basic_type.ptr_type(AddressSpace::Generic),
|
||||
"data_ptr",
|
||||
);
|
||||
|
||||
let data = env.builder.build_load(data_ptr, "load_data");
|
||||
let basic_type = basic_type_from_layout(env, layout_interner, &layout);
|
||||
let data = load_tag_data(env, layout_interner, union_layout, tag_value, basic_type);
|
||||
|
||||
let (width, _) =
|
||||
union_layout.data_size_and_alignment(env.layout_interner, env.target_info);
|
||||
union_layout.data_size_and_alignment(layout_interner, env.target_info);
|
||||
|
||||
let cursors = Cursors {
|
||||
offset: extra_offset,
|
||||
|
@ -608,8 +716,16 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
|||
};
|
||||
|
||||
let when_recursive = WhenRecursive::Loop(union_layout);
|
||||
let answer =
|
||||
build_clone(env, layout_ids, ptr, cursors, data, layout, when_recursive);
|
||||
let answer = build_clone(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
ptr,
|
||||
cursors,
|
||||
data,
|
||||
layout,
|
||||
when_recursive,
|
||||
);
|
||||
|
||||
env.builder.build_return(Some(&answer));
|
||||
|
||||
|
@ -629,17 +745,14 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
|||
}
|
||||
}
|
||||
NonNullableUnwrapped(fields) => {
|
||||
//
|
||||
|
||||
let tag_value = tag_value.into_pointer_value();
|
||||
|
||||
build_copy(env, ptr, offset, extra_offset.into());
|
||||
|
||||
let layout = Layout::struct_no_name_order(fields);
|
||||
let basic_type = basic_type_from_layout(env, &layout);
|
||||
let basic_type = basic_type_from_layout(env, layout_interner, &layout);
|
||||
|
||||
let (width, _) =
|
||||
union_layout.data_size_and_alignment(env.layout_interner, env.target_info);
|
||||
let (width, _) = union_layout.data_size_and_alignment(layout_interner, env.target_info);
|
||||
|
||||
let cursors = Cursors {
|
||||
offset: extra_offset,
|
||||
|
@ -650,21 +763,19 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
|||
),
|
||||
};
|
||||
|
||||
let raw_data_ptr = env
|
||||
.builder
|
||||
.build_struct_gep(tag_value, RocUnion::TAG_DATA_INDEX, "tag_data")
|
||||
.unwrap();
|
||||
|
||||
let data_ptr = env.builder.build_pointer_cast(
|
||||
raw_data_ptr,
|
||||
basic_type.ptr_type(AddressSpace::Generic),
|
||||
"data_ptr",
|
||||
);
|
||||
|
||||
let data = env.builder.build_load(data_ptr, "load_data");
|
||||
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_ids, ptr, cursors, data, layout, when_recursive);
|
||||
let answer = build_clone(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
ptr,
|
||||
cursors,
|
||||
data,
|
||||
layout,
|
||||
when_recursive,
|
||||
);
|
||||
|
||||
env.builder.build_return(Some(&answer));
|
||||
}
|
||||
|
@ -675,7 +786,7 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
|||
let switch_block = env.context.append_basic_block(parent, "switch_block");
|
||||
let null_block = env.context.append_basic_block(parent, "null_block");
|
||||
|
||||
let id = get_tag_id(env, parent, &union_layout, tag_value);
|
||||
let id = get_tag_id(env, layout_interner, parent, &union_layout, tag_value);
|
||||
|
||||
let comparison = env
|
||||
.builder
|
||||
|
@ -705,10 +816,10 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
|||
};
|
||||
|
||||
let layout = Layout::struct_no_name_order(fields);
|
||||
let basic_type = basic_type_from_layout(env, &layout);
|
||||
let basic_type = basic_type_from_layout(env, layout_interner, &layout);
|
||||
|
||||
let (width, _) =
|
||||
union_layout.data_size_and_alignment(env.layout_interner, env.target_info);
|
||||
union_layout.data_size_and_alignment(layout_interner, env.target_info);
|
||||
|
||||
let cursors = Cursors {
|
||||
offset: extra_offset,
|
||||
|
@ -720,23 +831,20 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
|||
};
|
||||
|
||||
let tag_value = tag_pointer_clear_tag_id(env, tag_value.into_pointer_value());
|
||||
|
||||
let raw_data_ptr = env
|
||||
.builder
|
||||
.build_struct_gep(tag_value, RocUnion::TAG_DATA_INDEX, "tag_data")
|
||||
.unwrap();
|
||||
|
||||
let data_ptr = env.builder.build_pointer_cast(
|
||||
raw_data_ptr,
|
||||
basic_type.ptr_type(AddressSpace::Generic),
|
||||
"data_ptr",
|
||||
);
|
||||
|
||||
let data = env.builder.build_load(data_ptr, "load_data");
|
||||
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_ids, ptr, cursors, data, layout, when_recursive);
|
||||
let answer = build_clone(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
ptr,
|
||||
cursors,
|
||||
data,
|
||||
layout,
|
||||
when_recursive,
|
||||
);
|
||||
|
||||
env.builder.build_return(Some(&answer));
|
||||
|
||||
|
@ -792,40 +900,39 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
|||
build_copy(env, ptr, offset, extra_offset.into());
|
||||
|
||||
let layout = Layout::struct_no_name_order(other_fields);
|
||||
let basic_type = basic_type_from_layout(env, &layout);
|
||||
let basic_type = basic_type_from_layout(env, layout_interner, &layout);
|
||||
|
||||
let cursors = Cursors {
|
||||
offset: extra_offset,
|
||||
extra_offset: env.builder.build_int_add(
|
||||
extra_offset,
|
||||
env.ptr_int().const_int(
|
||||
layout.stack_size(env.layout_interner, env.target_info) as _,
|
||||
layout.stack_size(layout_interner, env.target_info) as _,
|
||||
false,
|
||||
),
|
||||
"new_offset",
|
||||
),
|
||||
};
|
||||
|
||||
let raw_data_ptr = env
|
||||
.builder
|
||||
.build_struct_gep(
|
||||
tag_value.into_pointer_value(),
|
||||
RocUnion::TAG_DATA_INDEX,
|
||||
"tag_data",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let data_ptr = env.builder.build_pointer_cast(
|
||||
raw_data_ptr,
|
||||
basic_type.ptr_type(AddressSpace::Generic),
|
||||
"data_ptr",
|
||||
let data = load_tag_data(
|
||||
env,
|
||||
layout_interner,
|
||||
union_layout,
|
||||
tag_value.into_pointer_value(),
|
||||
basic_type,
|
||||
);
|
||||
|
||||
let data = env.builder.build_load(data_ptr, "load_data");
|
||||
|
||||
let when_recursive = WhenRecursive::Loop(union_layout);
|
||||
let answer =
|
||||
build_clone(env, layout_ids, ptr, cursors, data, layout, when_recursive);
|
||||
let answer = build_clone(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
ptr,
|
||||
cursors,
|
||||
data,
|
||||
layout,
|
||||
when_recursive,
|
||||
);
|
||||
|
||||
env.builder.build_return(Some(&answer));
|
||||
}
|
||||
|
@ -868,8 +975,12 @@ fn build_copy<'a, 'ctx, 'env>(
|
|||
value: BasicValueEnum<'ctx>,
|
||||
) -> IntValue<'ctx> {
|
||||
let ptr = unsafe {
|
||||
env.builder
|
||||
.build_in_bounds_gep(ptr, &[offset], "at_current_offset")
|
||||
env.builder.new_build_in_bounds_gep(
|
||||
env.context.i8_type(),
|
||||
ptr,
|
||||
&[offset],
|
||||
"at_current_offset",
|
||||
)
|
||||
};
|
||||
|
||||
let ptr_type = value.get_type().ptr_type(AddressSpace::Generic);
|
||||
|
@ -883,9 +994,9 @@ fn build_copy<'a, 'ctx, 'env>(
|
|||
env.builder.build_int_add(offset, width, "new_offset")
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn build_clone_builtin<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
ptr: PointerValue<'ctx>,
|
||||
cursors: Cursors<'ctx>,
|
||||
|
@ -931,15 +1042,16 @@ fn build_clone_builtin<'a, 'ctx, 'env>(
|
|||
offset = build_copy(env, ptr, offset, len.into());
|
||||
offset = build_copy(env, ptr, offset, len.into());
|
||||
|
||||
let elem = layout_interner.get(elem);
|
||||
let (element_width, _element_align) =
|
||||
elem.stack_size_and_alignment(env.layout_interner, env.target_info);
|
||||
elem.stack_size_and_alignment(layout_interner, env.target_info);
|
||||
let element_width = env.ptr_int().const_int(element_width as _, false);
|
||||
|
||||
let elements_width = bd.build_int_mul(element_width, len, "elements_width");
|
||||
|
||||
if elem.safe_to_memcpy(env.layout_interner) {
|
||||
if elem.safe_to_memcpy(layout_interner) {
|
||||
// NOTE we are not actually sure the dest is properly aligned
|
||||
let dest = pointer_at_offset(bd, ptr, offset);
|
||||
let dest = pointer_at_offset(bd, env.context.i8_type(), ptr, offset);
|
||||
let src = bd.build_pointer_cast(
|
||||
elements,
|
||||
env.context.i8_type().ptr_type(AddressSpace::Generic),
|
||||
|
@ -952,7 +1064,7 @@ fn build_clone_builtin<'a, 'ctx, 'env>(
|
|||
// We cloned the elements into the extra_offset address.
|
||||
let elements_start_offset = cursors.extra_offset;
|
||||
|
||||
let element_type = basic_type_from_layout(env, elem);
|
||||
let element_type = basic_type_from_layout(env, layout_interner, elem);
|
||||
let elements = bd.build_pointer_cast(
|
||||
elements,
|
||||
element_type.ptr_type(AddressSpace::Generic),
|
||||
|
@ -963,7 +1075,7 @@ fn build_clone_builtin<'a, 'ctx, 'env>(
|
|||
let rest_offset = bd.build_alloca(env.ptr_int(), "rest_offset");
|
||||
|
||||
let element_stack_size = env.ptr_int().const_int(
|
||||
elem.stack_size(env.layout_interner, env.target_info) as u64,
|
||||
elem.stack_size(layout_interner, env.target_info) as u64,
|
||||
false,
|
||||
);
|
||||
let rest_start_offset = bd.build_int_add(
|
||||
|
@ -973,12 +1085,13 @@ fn build_clone_builtin<'a, 'ctx, 'env>(
|
|||
);
|
||||
bd.build_store(rest_offset, rest_start_offset);
|
||||
|
||||
let body = |index, element| {
|
||||
let body = |layout_interner, index, element| {
|
||||
let current_offset =
|
||||
bd.build_int_mul(element_stack_size, index, "current_offset");
|
||||
let current_offset =
|
||||
bd.build_int_add(elements_start_offset, current_offset, "current_offset");
|
||||
let current_extra_offset = bd.build_load(rest_offset, "element_offset");
|
||||
let current_extra_offset =
|
||||
bd.new_build_load(env.ptr_int(), rest_offset, "element_offset");
|
||||
|
||||
let offset = current_offset;
|
||||
let extra_offset = current_extra_offset.into_int_value();
|
||||
|
@ -990,6 +1103,7 @@ fn build_clone_builtin<'a, 'ctx, 'env>(
|
|||
|
||||
let new_offset = build_clone(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
ptr,
|
||||
cursors,
|
||||
|
@ -1007,9 +1121,18 @@ fn build_clone_builtin<'a, 'ctx, 'env>(
|
|||
.and_then(|b| b.get_parent())
|
||||
.unwrap();
|
||||
|
||||
incrementing_elem_loop(env, parent, *elem, elements, len, "index", body);
|
||||
incrementing_elem_loop(
|
||||
env,
|
||||
layout_interner,
|
||||
parent,
|
||||
*elem,
|
||||
elements,
|
||||
len,
|
||||
"index",
|
||||
body,
|
||||
);
|
||||
|
||||
bd.build_load(rest_offset, "rest_start_offset")
|
||||
bd.new_build_load(env.ptr_int(), rest_offset, "rest_start_offset")
|
||||
.into_int_value()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::llvm::bitcode::call_void_bitcode_fn;
|
||||
use crate::llvm::build::{add_func, get_panic_msg_ptr, C_CALL_CONV};
|
||||
use crate::llvm::build::{add_func, get_panic_msg_ptr, get_panic_tag_ptr, BuilderExt, C_CALL_CONV};
|
||||
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;
|
||||
|
@ -158,7 +159,6 @@ pub fn add_default_roc_externs(env: &Env<'_, '_, '_>) {
|
|||
|
||||
unreachable_function(env, "roc_getppid");
|
||||
unreachable_function(env, "roc_mmap");
|
||||
unreachable_function(env, "roc_send_signal");
|
||||
unreachable_function(env, "roc_shm_open");
|
||||
|
||||
add_sjlj_roc_panic(env)
|
||||
|
@ -168,7 +168,10 @@ pub fn add_default_roc_externs(env: &Env<'_, '_, '_>) {
|
|||
fn unreachable_function(env: &Env, name: &str) {
|
||||
// The type of this function (but not the implementation) should have
|
||||
// already been defined by the builtins, which rely on it.
|
||||
let fn_val = env.module.get_function(name).unwrap();
|
||||
let fn_val = match env.module.get_function(name) {
|
||||
Some(f) => f,
|
||||
None => panic!("extern function {name} is not defined by the builtins"),
|
||||
};
|
||||
|
||||
// Add a basic block for the entry point
|
||||
let entry = env.context.append_basic_block(fn_val, "entry");
|
||||
|
@ -193,10 +196,9 @@ pub fn add_sjlj_roc_panic(env: &Env<'_, '_, '_>) {
|
|||
// already been defined by the builtins, which rely on it.
|
||||
let fn_val = module.get_function("roc_panic").unwrap();
|
||||
let mut params = fn_val.get_param_iter();
|
||||
let ptr_arg = params.next().unwrap();
|
||||
let roc_str_arg = params.next().unwrap();
|
||||
|
||||
// in debug mode, this is assumed to be NullTerminatedString
|
||||
let _tag_id_arg = params.next().unwrap();
|
||||
let tag_id_arg = params.next().unwrap();
|
||||
|
||||
debug_assert!(params.next().is_none());
|
||||
|
||||
|
@ -210,8 +212,43 @@ pub fn add_sjlj_roc_panic(env: &Env<'_, '_, '_>) {
|
|||
|
||||
builder.position_at_end(entry);
|
||||
|
||||
// write our error message pointer
|
||||
env.builder.build_store(get_panic_msg_ptr(env), ptr_arg);
|
||||
// write our error message to the RocStr pointer
|
||||
{
|
||||
let loaded_roc_str = match env.target_info.ptr_width() {
|
||||
roc_target::PtrWidth::Bytes4 => roc_str_arg,
|
||||
// On 64-bit we pass RocStrs by reference internally
|
||||
roc_target::PtrWidth::Bytes8 => {
|
||||
let str_typ = zig_str_type(env);
|
||||
builder.new_build_load(
|
||||
str_typ,
|
||||
roc_str_arg.into_pointer_value(),
|
||||
"load_roc_str",
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
env.builder
|
||||
.build_store(get_panic_msg_ptr(env), loaded_roc_str);
|
||||
}
|
||||
|
||||
// write the panic tag.
|
||||
// increment by 1, since the tag we'll get from the Roc program is 0-based,
|
||||
// but we use 0 for marking a successful call.
|
||||
{
|
||||
let cast_tag_id = builder.build_int_z_extend(
|
||||
tag_id_arg.into_int_value(),
|
||||
env.context.i64_type(),
|
||||
"zext_panic_tag",
|
||||
);
|
||||
|
||||
let inc_tag_id = builder.build_int_add(
|
||||
cast_tag_id,
|
||||
env.context.i64_type().const_int(1, false),
|
||||
"inc_panic_tag",
|
||||
);
|
||||
|
||||
env.builder.build_store(get_panic_tag_ptr(env), inc_tag_id);
|
||||
}
|
||||
|
||||
build_longjmp_call(env);
|
||||
|
||||
|
@ -232,11 +269,11 @@ pub fn build_longjmp_call(env: &Env) {
|
|||
call_void_bitcode_fn(env, &[jmp_buf.into(), tag.into()], bitcode::UTILS_LONGJMP);
|
||||
} else {
|
||||
// Call the LLVM-intrinsic longjmp: `void @llvm.eh.sjlj.longjmp(i8* %setjmp_buf)`
|
||||
let jmp_buf_i8p = env.builder.build_bitcast(
|
||||
let jmp_buf_i8p = env.builder.build_pointer_cast(
|
||||
jmp_buf,
|
||||
env.context.i8_type().ptr_type(AddressSpace::Generic),
|
||||
"jmp_buf i8*",
|
||||
);
|
||||
let _call = env.build_intrinsic_call(LLVM_LONGJMP, &[jmp_buf_i8p]);
|
||||
let _call = env.build_intrinsic_call(LLVM_LONGJMP, &[jmp_buf_i8p.into()]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,6 @@ fn add_float_intrinsic<'ctx, F>(
|
|||
|
||||
check!(FloatWidth::F32, ctx.f32_type());
|
||||
check!(FloatWidth::F64, ctx.f64_type());
|
||||
// check!(IntWidth::F128, ctx.i128_type());
|
||||
}
|
||||
|
||||
fn add_int_intrinsic<'ctx, F>(
|
||||
|
|
|
@ -9,10 +9,11 @@ use inkwell::{
|
|||
use morphic_lib::{FuncSpec, UpdateMode};
|
||||
use roc_builtins::bitcode::{self, FloatWidth, IntWidth};
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_intern::Interner;
|
||||
use roc_module::{low_level::LowLevel, symbol::Symbol};
|
||||
use roc_mono::{
|
||||
ir::HigherOrderLowLevel,
|
||||
layout::{Builtin, LambdaSet, Layout, LayoutIds},
|
||||
layout::{Builtin, LambdaSet, Layout, LayoutIds, STLayoutInterner},
|
||||
};
|
||||
use roc_target::PtrWidth;
|
||||
|
||||
|
@ -24,7 +25,7 @@ use crate::llvm::{
|
|||
},
|
||||
build::{
|
||||
complex_bitcast_check_size, create_entry_block_alloca, function_value_by_func_spec,
|
||||
load_roc_value, roc_function_call, RocReturn,
|
||||
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,
|
||||
|
@ -33,7 +34,9 @@ use crate::llvm::{
|
|||
pass_update_mode,
|
||||
},
|
||||
compare::{generic_eq, generic_neq},
|
||||
convert::{self, basic_type_from_layout},
|
||||
convert::{
|
||||
self, basic_type_from_layout, zig_num_parse_result_type, zig_to_int_checked_result_type,
|
||||
},
|
||||
intrinsics::{
|
||||
LLVM_ADD_SATURATED, LLVM_ADD_WITH_OVERFLOW, LLVM_CEILING, LLVM_COS, LLVM_FABS, LLVM_FLOOR,
|
||||
LLVM_LOG, LLVM_MUL_WITH_OVERFLOW, LLVM_POW, LLVM_ROUND, LLVM_SIN, LLVM_SQRT,
|
||||
|
@ -41,24 +44,24 @@ use crate::llvm::{
|
|||
},
|
||||
};
|
||||
|
||||
use super::convert::zig_with_overflow_roc_dec;
|
||||
use super::{build::throw_internal_exception, convert::zig_with_overflow_roc_dec};
|
||||
use super::{
|
||||
build::{load_symbol, load_symbol_and_layout, throw_exception, Env, Scope},
|
||||
build::{load_symbol, load_symbol_and_layout, Env, Scope},
|
||||
convert::zig_dec_type,
|
||||
};
|
||||
|
||||
macro_rules! list_element_layout {
|
||||
($list_layout:expr) => {
|
||||
match $list_layout {
|
||||
Layout::Builtin(Builtin::List(list_layout)) => *list_layout,
|
||||
Layout::Builtin(Builtin::List(list_layout)) => list_layout,
|
||||
_ => unreachable!("invalid list layout"),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
scope: &Scope<'a, 'ctx>,
|
||||
parent: FunctionValue<'ctx>,
|
||||
|
@ -225,14 +228,23 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
|||
intrinsic,
|
||||
),
|
||||
None => {
|
||||
let return_type = zig_function_type.get_param_types()[0]
|
||||
.into_pointer_type()
|
||||
.get_element_type()
|
||||
.into_struct_type()
|
||||
.into();
|
||||
let return_type_name = match number_layout {
|
||||
Layout::Builtin(Builtin::Int(int_width)) => int_width.type_name(),
|
||||
Layout::Builtin(Builtin::Decimal) => {
|
||||
// zig picks 128 for dec.RocDec
|
||||
"i128"
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let zig_return_alloca =
|
||||
create_entry_block_alloca(env, parent, return_type, "str_to_num");
|
||||
let return_type = zig_num_parse_result_type(env, return_type_name);
|
||||
|
||||
let zig_return_alloca = create_entry_block_alloca(
|
||||
env,
|
||||
parent,
|
||||
return_type.into(),
|
||||
"str_to_num",
|
||||
);
|
||||
|
||||
let (a, b) =
|
||||
pass_list_or_string_to_zig_32bit(env, string.into_struct_value());
|
||||
|
@ -244,7 +256,8 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
|||
);
|
||||
|
||||
let roc_return_type =
|
||||
basic_type_from_layout(env, layout).ptr_type(AddressSpace::Generic);
|
||||
basic_type_from_layout(env, layout_interner, layout)
|
||||
.ptr_type(AddressSpace::Generic);
|
||||
|
||||
let roc_return_alloca = env.builder.build_pointer_cast(
|
||||
zig_return_alloca,
|
||||
|
@ -252,17 +265,48 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
|||
"cast_to_roc",
|
||||
);
|
||||
|
||||
load_roc_value(env, *layout, roc_return_alloca, "str_to_num_result")
|
||||
load_roc_value(
|
||||
env,
|
||||
layout_interner,
|
||||
*layout,
|
||||
roc_return_alloca,
|
||||
"str_to_num_result",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
PtrWidth::Bytes8 => {
|
||||
call_bitcode_fn_fixing_for_convention(env, &[string], layout, intrinsic)
|
||||
let cc_return_by_pointer = match number_layout {
|
||||
Layout::Builtin(Builtin::Int(int_width)) => {
|
||||
(int_width.stack_size() as usize > env.target_info.ptr_size())
|
||||
.then_some(int_width.type_name())
|
||||
}
|
||||
Layout::Builtin(Builtin::Decimal) => {
|
||||
// zig picks 128 for dec.RocDec
|
||||
Some("i128")
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
if let Some(type_name) = cc_return_by_pointer {
|
||||
let bitcode_return_type = zig_num_parse_result_type(env, type_name);
|
||||
|
||||
call_bitcode_fn_fixing_for_convention(
|
||||
env,
|
||||
layout_interner,
|
||||
bitcode_return_type,
|
||||
&[string],
|
||||
layout,
|
||||
intrinsic,
|
||||
)
|
||||
} else {
|
||||
call_bitcode_fn(env, &[string], intrinsic)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// zig passes the result as a packed integer sometimes, instead of a struct. So we cast
|
||||
let expected_type = basic_type_from_layout(env, layout);
|
||||
let expected_type = basic_type_from_layout(env, layout_interner, layout);
|
||||
let actual_type = result.get_type();
|
||||
|
||||
if expected_type != actual_type {
|
||||
|
@ -389,7 +433,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
|||
&[string, delimiter],
|
||||
&[],
|
||||
BitcodeReturns::List,
|
||||
bitcode::STR_STR_SPLIT,
|
||||
bitcode::STR_SPLIT,
|
||||
)
|
||||
}
|
||||
StrIsEmpty => {
|
||||
|
@ -438,16 +482,10 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
|||
use roc_target::OperatingSystem::*;
|
||||
match env.target_info.operating_system {
|
||||
Windows => {
|
||||
// we have to go digging to find the return type
|
||||
let function = env
|
||||
.module
|
||||
.get_function(bitcode::STR_GET_SCALAR_UNSAFE)
|
||||
.unwrap();
|
||||
|
||||
let return_type = function.get_type().get_param_types()[0]
|
||||
.into_pointer_type()
|
||||
.get_element_type()
|
||||
.into_struct_type();
|
||||
let return_type = env.context.struct_type(
|
||||
&[env.ptr_int().into(), env.context.i32_type().into()],
|
||||
false,
|
||||
);
|
||||
|
||||
let result = env.builder.build_alloca(return_type, "result");
|
||||
|
||||
|
@ -457,14 +495,15 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
|||
bitcode::STR_GET_SCALAR_UNSAFE,
|
||||
);
|
||||
|
||||
let return_type = basic_type_from_layout(env, layout);
|
||||
let return_type = basic_type_from_layout(env, layout_interner, layout);
|
||||
let cast_result = env.builder.build_pointer_cast(
|
||||
result,
|
||||
return_type.ptr_type(AddressSpace::Generic),
|
||||
"cast",
|
||||
);
|
||||
|
||||
env.builder.build_load(cast_result, "load_result")
|
||||
env.builder
|
||||
.new_build_load(return_type, cast_result, "load_result")
|
||||
}
|
||||
Unix => {
|
||||
let result = call_str_bitcode_fn(
|
||||
|
@ -479,7 +518,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
|||
match env.target_info.ptr_width() {
|
||||
PtrWidth::Bytes8 => result,
|
||||
PtrWidth::Bytes4 => {
|
||||
let to = basic_type_from_layout(env, layout);
|
||||
let to = basic_type_from_layout(env, layout_interner, layout);
|
||||
complex_bitcast_check_size(env, result, to, "to_roc_record")
|
||||
}
|
||||
}
|
||||
|
@ -614,8 +653,9 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
|||
let result_layout = *layout;
|
||||
list_with_capacity(
|
||||
env,
|
||||
layout_interner,
|
||||
list_len.into_int_value(),
|
||||
&list_element_layout!(result_layout),
|
||||
list_element_layout!(result_layout),
|
||||
)
|
||||
}
|
||||
ListConcat => {
|
||||
|
@ -627,7 +667,13 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
|||
|
||||
let element_layout = list_element_layout!(list_layout);
|
||||
|
||||
list_concat(env, first_list, second_list, element_layout)
|
||||
list_concat(
|
||||
env,
|
||||
layout_interner,
|
||||
first_list,
|
||||
second_list,
|
||||
*element_layout,
|
||||
)
|
||||
}
|
||||
ListAppendUnsafe => {
|
||||
// List.appendUnsafe : List elem, elem -> List elem
|
||||
|
@ -636,7 +682,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
|||
let original_wrapper = load_symbol(scope, &args[0]).into_struct_value();
|
||||
let (elem, elem_layout) = load_symbol_and_layout(scope, &args[1]);
|
||||
|
||||
list_append_unsafe(env, original_wrapper, elem, elem_layout)
|
||||
list_append_unsafe(env, layout_interner, original_wrapper, elem, elem_layout)
|
||||
}
|
||||
ListPrepend => {
|
||||
// List.prepend : List elem, elem -> List elem
|
||||
|
@ -645,7 +691,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
|||
let original_wrapper = load_symbol(scope, &args[0]).into_struct_value();
|
||||
let (elem, elem_layout) = load_symbol_and_layout(scope, &args[1]);
|
||||
|
||||
list_prepend(env, original_wrapper, elem, elem_layout)
|
||||
list_prepend(env, layout_interner, original_wrapper, elem, elem_layout)
|
||||
}
|
||||
ListReserve => {
|
||||
// List.reserve : List elem, Nat -> List elem
|
||||
|
@ -655,7 +701,14 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
|||
let element_layout = list_element_layout!(list_layout);
|
||||
let spare = load_symbol(scope, &args[1]);
|
||||
|
||||
list_reserve(env, list, spare, element_layout, update_mode)
|
||||
list_reserve(
|
||||
env,
|
||||
layout_interner,
|
||||
list,
|
||||
spare,
|
||||
*element_layout,
|
||||
update_mode,
|
||||
)
|
||||
}
|
||||
ListSwap => {
|
||||
// List.swap : List elem, Nat, Nat -> List elem
|
||||
|
@ -670,10 +723,11 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
|||
let element_layout = list_element_layout!(list_layout);
|
||||
list_swap(
|
||||
env,
|
||||
layout_interner,
|
||||
original_wrapper,
|
||||
index_1.into_int_value(),
|
||||
index_2.into_int_value(),
|
||||
element_layout,
|
||||
*element_layout,
|
||||
update_mode,
|
||||
)
|
||||
}
|
||||
|
@ -689,11 +743,12 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
|||
let element_layout = list_element_layout!(list_layout);
|
||||
list_sublist(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
original_wrapper,
|
||||
start.into_int_value(),
|
||||
len.into_int_value(),
|
||||
element_layout,
|
||||
*element_layout,
|
||||
)
|
||||
}
|
||||
ListDropAt => {
|
||||
|
@ -708,10 +763,11 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
|||
let element_layout = list_element_layout!(list_layout);
|
||||
list_drop_at(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
original_wrapper,
|
||||
count.into_int_value(),
|
||||
element_layout,
|
||||
*element_layout,
|
||||
)
|
||||
}
|
||||
StrGetUnsafe => {
|
||||
|
@ -732,8 +788,9 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
|||
|
||||
list_get_unsafe(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
list_element_layout!(list_layout),
|
||||
*list_element_layout!(list_layout),
|
||||
element_index.into_int_value(),
|
||||
wrapper_struct.into_struct_value(),
|
||||
)
|
||||
|
@ -743,6 +800,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
|||
|
||||
list_replace_unsafe(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
list,
|
||||
index.into_int_value(),
|
||||
|
@ -813,6 +871,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
|||
let int_type = convert::int_type_from_int_width(env, *int_width);
|
||||
build_int_unary_op(
|
||||
env,
|
||||
layout_interner,
|
||||
parent,
|
||||
arg.into_int_value(),
|
||||
*int_width,
|
||||
|
@ -1002,7 +1061,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
|||
NumIntCast => {
|
||||
arguments!(arg);
|
||||
|
||||
let to = basic_type_from_layout(env, layout).into_int_type();
|
||||
let to = basic_type_from_layout(env, layout_interner, layout).into_int_type();
|
||||
let to_signed = intwidth_from_layout(*layout).is_signed();
|
||||
|
||||
env.builder
|
||||
|
@ -1016,7 +1075,8 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
|||
Layout::Builtin(Builtin::Int(width)) => {
|
||||
// Converting from int to float
|
||||
let int_val = arg.into_int_value();
|
||||
let dest = basic_type_from_layout(env, layout).into_float_type();
|
||||
let dest =
|
||||
basic_type_from_layout(env, layout_interner, layout).into_float_type();
|
||||
|
||||
if width.is_signed() {
|
||||
env.builder
|
||||
|
@ -1030,7 +1090,8 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
|||
}
|
||||
Layout::Builtin(Builtin::Float(_)) => {
|
||||
// Converting from float to float - e.g. F64 to F32, or vice versa
|
||||
let dest = basic_type_from_layout(env, layout).into_float_type();
|
||||
let dest =
|
||||
basic_type_from_layout(env, layout_interner, layout).into_float_type();
|
||||
|
||||
env.builder
|
||||
.build_float_cast(arg.into_float_value(), dest, "cast_float_to_float")
|
||||
|
@ -1052,12 +1113,28 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
|||
Eq => {
|
||||
arguments_with_layouts!((lhs_arg, lhs_layout), (rhs_arg, rhs_layout));
|
||||
|
||||
generic_eq(env, layout_ids, lhs_arg, rhs_arg, lhs_layout, rhs_layout)
|
||||
generic_eq(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
lhs_arg,
|
||||
rhs_arg,
|
||||
lhs_layout,
|
||||
rhs_layout,
|
||||
)
|
||||
}
|
||||
NotEq => {
|
||||
arguments_with_layouts!((lhs_arg, lhs_layout), (rhs_arg, rhs_layout));
|
||||
|
||||
generic_neq(env, layout_ids, lhs_arg, rhs_arg, lhs_layout, rhs_layout)
|
||||
generic_neq(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
lhs_arg,
|
||||
rhs_arg,
|
||||
lhs_layout,
|
||||
rhs_layout,
|
||||
)
|
||||
}
|
||||
And => {
|
||||
// The (&&) operator
|
||||
|
@ -1106,13 +1183,13 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
|||
unreachable!("Not used in LLVM backend: {:?}", op);
|
||||
}
|
||||
|
||||
Unreachable => match RocReturn::from_layout(env, layout) {
|
||||
Unreachable => match RocReturn::from_layout(env, layout_interner, layout) {
|
||||
RocReturn::Return => {
|
||||
let basic_type = basic_type_from_layout(env, layout);
|
||||
let basic_type = basic_type_from_layout(env, layout_interner, layout);
|
||||
basic_type.const_zero()
|
||||
}
|
||||
RocReturn::ByPointer => {
|
||||
let basic_type = basic_type_from_layout(env, layout);
|
||||
let basic_type = basic_type_from_layout(env, layout_interner, layout);
|
||||
let ptr = env.builder.build_alloca(basic_type, "unreachable_alloca");
|
||||
env.builder.build_store(ptr, basic_type.const_zero());
|
||||
|
||||
|
@ -1536,7 +1613,7 @@ fn throw_on_overflow<'a, 'ctx, 'env>(
|
|||
|
||||
bd.position_at_end(throw_block);
|
||||
|
||||
throw_exception(env, message);
|
||||
throw_internal_exception(env, parent, message);
|
||||
|
||||
bd.position_at_end(then_block);
|
||||
|
||||
|
@ -1663,7 +1740,7 @@ fn dec_binop_with_overflow<'a, 'ctx, 'env>(
|
|||
}
|
||||
|
||||
env.builder
|
||||
.build_load(return_alloca, "load_dec")
|
||||
.new_build_load(return_type, return_alloca, "load_dec")
|
||||
.into_struct_value()
|
||||
}
|
||||
|
||||
|
@ -1786,6 +1863,7 @@ fn int_type_signed_min(int_type: IntType) -> IntValue {
|
|||
|
||||
fn build_int_unary_op<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
parent: FunctionValue<'ctx>,
|
||||
arg: IntValue<'ctx>,
|
||||
arg_width: IntWidth,
|
||||
|
@ -1856,8 +1934,8 @@ fn build_int_unary_op<'a, 'ctx, 'env>(
|
|||
|| // Or if the two types are the same, they trivially fit.
|
||||
arg_width == target_int_width;
|
||||
|
||||
let return_type =
|
||||
convert::basic_type_from_layout(env, return_layout).into_struct_type();
|
||||
let return_type = convert::basic_type_from_layout(env, layout_interner, return_layout)
|
||||
.into_struct_type();
|
||||
|
||||
if arg_always_fits_in_target {
|
||||
// This is guaranteed to succeed so we can just make it an int cast and let LLVM
|
||||
|
@ -1909,16 +1987,15 @@ fn build_int_unary_op<'a, 'ctx, 'env>(
|
|||
intrinsic,
|
||||
),
|
||||
None => {
|
||||
let return_type = zig_function_type.get_param_types()[0]
|
||||
.into_pointer_type()
|
||||
.get_element_type()
|
||||
.into_struct_type()
|
||||
.into();
|
||||
let return_type = zig_to_int_checked_result_type(
|
||||
env,
|
||||
target_int_width.type_name(),
|
||||
);
|
||||
|
||||
let zig_return_alloca = create_entry_block_alloca(
|
||||
env,
|
||||
parent,
|
||||
return_type,
|
||||
return_type.into(),
|
||||
"num_to_int",
|
||||
);
|
||||
|
||||
|
@ -1928,8 +2005,9 @@ fn build_int_unary_op<'a, 'ctx, 'env>(
|
|||
intrinsic,
|
||||
);
|
||||
|
||||
let roc_return_type = basic_type_from_layout(env, return_layout)
|
||||
.ptr_type(AddressSpace::Generic);
|
||||
let roc_return_type =
|
||||
basic_type_from_layout(env, layout_interner, return_layout)
|
||||
.ptr_type(AddressSpace::Generic);
|
||||
|
||||
let roc_return_alloca = env.builder.build_pointer_cast(
|
||||
zig_return_alloca,
|
||||
|
@ -1937,19 +2015,32 @@ fn build_int_unary_op<'a, 'ctx, 'env>(
|
|||
"cast_to_roc",
|
||||
);
|
||||
|
||||
load_roc_value(env, *return_layout, roc_return_alloca, "num_to_int")
|
||||
load_roc_value(
|
||||
env,
|
||||
layout_interner,
|
||||
*return_layout,
|
||||
roc_return_alloca,
|
||||
"num_to_int",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
PtrWidth::Bytes8 => {
|
||||
// call_bitcode_fn_fixing_for_convention(env, &[string], layout, intrinsic)
|
||||
if target_int_width.stack_size() as usize > env.target_info.ptr_size() {
|
||||
let bitcode_return_type =
|
||||
zig_to_int_checked_result_type(env, target_int_width.type_name());
|
||||
|
||||
call_bitcode_fn_fixing_for_convention(
|
||||
env,
|
||||
&[arg.into()],
|
||||
return_layout,
|
||||
intrinsic,
|
||||
)
|
||||
call_bitcode_fn_fixing_for_convention(
|
||||
env,
|
||||
layout_interner,
|
||||
bitcode_return_type,
|
||||
&[arg.into()],
|
||||
return_layout,
|
||||
intrinsic,
|
||||
)
|
||||
} else {
|
||||
call_bitcode_fn(env, &[arg.into()], intrinsic)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1982,8 +2073,9 @@ fn int_neg_raise_on_overflow<'a, 'ctx, 'env>(
|
|||
|
||||
builder.position_at_end(then_block);
|
||||
|
||||
throw_exception(
|
||||
throw_internal_exception(
|
||||
env,
|
||||
parent,
|
||||
"integer negation overflowed because its argument is the minimum value",
|
||||
);
|
||||
|
||||
|
@ -2012,8 +2104,9 @@ fn int_abs_raise_on_overflow<'a, 'ctx, 'env>(
|
|||
|
||||
builder.position_at_end(then_block);
|
||||
|
||||
throw_exception(
|
||||
throw_internal_exception(
|
||||
env,
|
||||
parent,
|
||||
"integer absolute overflowed because its argument is the minimum value",
|
||||
);
|
||||
|
||||
|
@ -2050,15 +2143,19 @@ fn int_abs_with_overflow<'a, 'ctx, 'env>(
|
|||
|
||||
let xored_arg = bd.build_xor(
|
||||
arg,
|
||||
bd.build_load(shifted_alloca, shifted_name).into_int_value(),
|
||||
bd.new_build_load(int_type, shifted_alloca, shifted_name)
|
||||
.into_int_value(),
|
||||
"xor_arg_shifted",
|
||||
);
|
||||
|
||||
BasicValueEnum::IntValue(bd.build_int_sub(
|
||||
xored_arg,
|
||||
bd.build_load(shifted_alloca, shifted_name).into_int_value(),
|
||||
"sub_xored_shifted",
|
||||
))
|
||||
BasicValueEnum::IntValue(
|
||||
bd.build_int_sub(
|
||||
xored_arg,
|
||||
bd.new_build_load(int_type, shifted_alloca, shifted_name)
|
||||
.into_int_value(),
|
||||
"sub_xored_shifted",
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fn build_float_unary_op<'a, 'ctx, 'env>(
|
||||
|
@ -2098,13 +2195,6 @@ fn build_float_unary_op<'a, 'ctx, 'env>(
|
|||
"f64_to_f32",
|
||||
),
|
||||
(FloatWidth::F64, FloatWidth::F64) => arg.into(),
|
||||
(FloatWidth::F128, FloatWidth::F128) => arg.into(),
|
||||
(FloatWidth::F128, _) => {
|
||||
unimplemented!("I cannot handle F128 with Num.toFrac yet")
|
||||
}
|
||||
(_, FloatWidth::F128) => {
|
||||
unimplemented!("I cannot handle F128 with Num.toFrac yet")
|
||||
}
|
||||
}
|
||||
}
|
||||
NumCeiling => {
|
||||
|
@ -2183,9 +2273,9 @@ fn build_float_unary_op<'a, 'ctx, 'env>(
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
scope: &Scope<'a, 'ctx>,
|
||||
return_layout: &Layout<'a>,
|
||||
|
@ -2218,7 +2308,7 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
|||
func_spec,
|
||||
function_name.name(),
|
||||
argument_layouts,
|
||||
function_name.captures_niche(),
|
||||
function_name.niche(),
|
||||
return_layout,
|
||||
);
|
||||
|
||||
|
@ -2241,20 +2331,31 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
|||
Layout::Builtin(Builtin::List(element_layout)),
|
||||
Layout::Builtin(Builtin::List(result_layout)),
|
||||
) => {
|
||||
let argument_layouts = &[**element_layout];
|
||||
let element_layout = layout_interner.get(*element_layout);
|
||||
let result_layout = layout_interner.get(*result_layout);
|
||||
|
||||
let argument_layouts = &[*element_layout];
|
||||
|
||||
let roc_function_call = roc_function_call(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
function,
|
||||
closure,
|
||||
closure_layout,
|
||||
function_owns_closure_data,
|
||||
argument_layouts,
|
||||
**result_layout,
|
||||
*result_layout,
|
||||
);
|
||||
|
||||
list_map(env, roc_function_call, list, element_layout, result_layout)
|
||||
list_map(
|
||||
env,
|
||||
layout_interner,
|
||||
roc_function_call,
|
||||
list,
|
||||
element_layout,
|
||||
result_layout,
|
||||
)
|
||||
}
|
||||
_ => unreachable!("invalid list layout"),
|
||||
}
|
||||
|
@ -2271,21 +2372,27 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
|||
Layout::Builtin(Builtin::List(element2_layout)),
|
||||
Layout::Builtin(Builtin::List(result_layout)),
|
||||
) => {
|
||||
let argument_layouts = &[**element1_layout, **element2_layout];
|
||||
let element1_layout = layout_interner.get(*element1_layout);
|
||||
let element2_layout = layout_interner.get(*element2_layout);
|
||||
let result_layout = layout_interner.get(*result_layout);
|
||||
|
||||
let argument_layouts = &[*element1_layout, *element2_layout];
|
||||
|
||||
let roc_function_call = roc_function_call(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
function,
|
||||
closure,
|
||||
closure_layout,
|
||||
function_owns_closure_data,
|
||||
argument_layouts,
|
||||
**result_layout,
|
||||
*result_layout,
|
||||
);
|
||||
|
||||
list_map2(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
roc_function_call,
|
||||
list1,
|
||||
|
@ -2312,22 +2419,28 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
|||
Layout::Builtin(Builtin::List(element3_layout)),
|
||||
Layout::Builtin(Builtin::List(result_layout)),
|
||||
) => {
|
||||
let argument_layouts =
|
||||
&[**element1_layout, **element2_layout, **element3_layout];
|
||||
let element1_layout = layout_interner.get(*element1_layout);
|
||||
let element2_layout = layout_interner.get(*element2_layout);
|
||||
let element3_layout = layout_interner.get(*element3_layout);
|
||||
let result_layout = layout_interner.get(*result_layout);
|
||||
|
||||
let argument_layouts = &[*element1_layout, *element2_layout, *element3_layout];
|
||||
|
||||
let roc_function_call = roc_function_call(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
function,
|
||||
closure,
|
||||
closure_layout,
|
||||
function_owns_closure_data,
|
||||
argument_layouts,
|
||||
**result_layout,
|
||||
*result_layout,
|
||||
);
|
||||
|
||||
list_map3(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
roc_function_call,
|
||||
list1,
|
||||
|
@ -2364,26 +2477,34 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
|||
Layout::Builtin(Builtin::List(element4_layout)),
|
||||
Layout::Builtin(Builtin::List(result_layout)),
|
||||
) => {
|
||||
let element1_layout = layout_interner.get(*element1_layout);
|
||||
let element2_layout = layout_interner.get(*element2_layout);
|
||||
let element3_layout = layout_interner.get(*element3_layout);
|
||||
let element4_layout = layout_interner.get(*element4_layout);
|
||||
let result_layout = layout_interner.get(*result_layout);
|
||||
|
||||
let argument_layouts = &[
|
||||
**element1_layout,
|
||||
**element2_layout,
|
||||
**element3_layout,
|
||||
**element4_layout,
|
||||
*element1_layout,
|
||||
*element2_layout,
|
||||
*element3_layout,
|
||||
*element4_layout,
|
||||
];
|
||||
|
||||
let roc_function_call = roc_function_call(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
function,
|
||||
closure,
|
||||
closure_layout,
|
||||
function_owns_closure_data,
|
||||
argument_layouts,
|
||||
**result_layout,
|
||||
*result_layout,
|
||||
);
|
||||
|
||||
list_map4(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
roc_function_call,
|
||||
list1,
|
||||
|
@ -2410,15 +2531,23 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
|||
Layout::Builtin(Builtin::List(element_layout)) => {
|
||||
use crate::llvm::bitcode::build_compare_wrapper;
|
||||
|
||||
let argument_layouts = &[**element_layout, **element_layout];
|
||||
let element_layout = layout_interner.get(*element_layout);
|
||||
|
||||
let compare_wrapper =
|
||||
build_compare_wrapper(env, function, closure_layout, element_layout)
|
||||
.as_global_value()
|
||||
.as_pointer_value();
|
||||
let argument_layouts = &[*element_layout, *element_layout];
|
||||
|
||||
let compare_wrapper = build_compare_wrapper(
|
||||
env,
|
||||
layout_interner,
|
||||
function,
|
||||
closure_layout,
|
||||
element_layout,
|
||||
)
|
||||
.as_global_value()
|
||||
.as_pointer_value();
|
||||
|
||||
let roc_function_call = roc_function_call(
|
||||
env,
|
||||
layout_interner,
|
||||
layout_ids,
|
||||
function,
|
||||
closure,
|
||||
|
@ -2430,6 +2559,7 @@ pub(crate) fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
|||
|
||||
list_sort_with(
|
||||
env,
|
||||
layout_interner,
|
||||
roc_function_call,
|
||||
compare_wrapper,
|
||||
list,
|
||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue