Merge remote-tracking branch 'origin/main' into glue-getters-rtfeldman

This commit is contained in:
Folkert 2023-01-04 20:45:01 +01:00
commit 1c1112ec35
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
1136 changed files with 39670 additions and 19058 deletions

View file

@ -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

View file

@ -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);
}

View file

@ -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)
}

View file

@ -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()
}
}

View file

@ -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,

View file

@ -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)")

View file

@ -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()
}
}

View file

@ -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()]);
}
}

View file

@ -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>(

View file

@ -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