mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 21:39:07 +00:00
convert to pointer_cast where we can
This commit is contained in:
parent
8e36456765
commit
3720c38e2b
9 changed files with 213 additions and 1064 deletions
|
@ -270,10 +270,9 @@ fn build_transform_caller_help<'a, 'ctx, 'env>(
|
|||
(true, layout) => {
|
||||
let closure_type = basic_type_from_layout(env, &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");
|
||||
|
||||
|
@ -486,13 +485,11 @@ pub fn build_eq_wrapper<'a, 'ctx, 'env>(
|
|||
|
||||
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");
|
||||
|
@ -568,15 +565,13 @@ pub fn build_compare_wrapper<'a, 'ctx, 'env>(
|
|||
let value_type = basic_type_from_layout(env, 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");
|
||||
|
@ -595,10 +590,11 @@ pub fn build_compare_wrapper<'a, 'ctx, 'env>(
|
|||
let closure_type = basic_type_from_layout(env, &other);
|
||||
let closure_ptr_type = closure_type.ptr_type(AddressSpace::Generic);
|
||||
|
||||
let closure_cast = env
|
||||
.builder
|
||||
.build_bitcast(closure_ptr, closure_ptr_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");
|
||||
|
||||
|
|
|
@ -1164,14 +1164,11 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
|
|||
let struct_layout = Layout::struct_no_name_order(fields);
|
||||
let struct_type = basic_type_from_layout(env, &struct_layout);
|
||||
|
||||
let cast_argument = env
|
||||
.builder
|
||||
.build_bitcast(
|
||||
argument,
|
||||
struct_type.ptr_type(AddressSpace::Generic),
|
||||
"cast_rosetree_like",
|
||||
)
|
||||
.into_pointer_value();
|
||||
let cast_argument = env.builder.build_pointer_cast(
|
||||
argument,
|
||||
struct_type.ptr_type(AddressSpace::Generic),
|
||||
"cast_rosetree_like",
|
||||
);
|
||||
|
||||
let ptr = env
|
||||
.builder
|
||||
|
@ -1401,11 +1398,13 @@ fn build_tag_field_value<'a, 'ctx, 'env>(
|
|||
debug_assert!(value.is_pointer_value());
|
||||
|
||||
// we store recursive pointers as `i64*`
|
||||
env.builder.build_bitcast(
|
||||
value,
|
||||
env.context.i64_type().ptr_type(AddressSpace::Generic),
|
||||
"cast_recursive_pointer",
|
||||
)
|
||||
env.builder
|
||||
.build_pointer_cast(
|
||||
value.into_pointer_value(),
|
||||
env.context.i64_type().ptr_type(AddressSpace::Generic),
|
||||
"cast_recursive_pointer",
|
||||
)
|
||||
.into()
|
||||
} else if tag_field_layout.is_passed_by_reference(env.layout_interner, env.target_info) {
|
||||
debug_assert!(value.is_pointer_value());
|
||||
|
||||
|
@ -1838,14 +1837,11 @@ fn lookup_at_index_ptr<'a, 'ctx, 'env>(
|
|||
) -> BasicValueEnum<'ctx> {
|
||||
let builder = env.builder;
|
||||
|
||||
let ptr = env
|
||||
.builder
|
||||
.build_bitcast(
|
||||
value,
|
||||
struct_type.ptr_type(AddressSpace::Generic),
|
||||
"cast_lookup_at_index_ptr",
|
||||
)
|
||||
.into_pointer_value();
|
||||
let ptr = env.builder.build_pointer_cast(
|
||||
value,
|
||||
struct_type.ptr_type(AddressSpace::Generic),
|
||||
"cast_lookup_at_index_ptr",
|
||||
);
|
||||
|
||||
let elem_ptr = builder
|
||||
.build_struct_gep(ptr, index as u32, "at_index_struct_gep")
|
||||
|
@ -1860,11 +1856,13 @@ fn lookup_at_index_ptr<'a, 'ctx, 'env>(
|
|||
let actual_type = basic_type_from_layout(env, &Layout::Union(*union_layout));
|
||||
debug_assert!(actual_type.is_pointer_type());
|
||||
|
||||
builder.build_bitcast(
|
||||
result,
|
||||
actual_type,
|
||||
"cast_rec_pointer_lookup_at_index_ptr_old",
|
||||
)
|
||||
builder
|
||||
.build_pointer_cast(
|
||||
result.into_pointer_value(),
|
||||
actual_type.into_pointer_type(),
|
||||
"cast_rec_pointer_lookup_at_index_ptr_old",
|
||||
)
|
||||
.into()
|
||||
} else {
|
||||
result
|
||||
}
|
||||
|
@ -1882,14 +1880,11 @@ fn lookup_at_index_ptr2<'a, 'ctx, 'env>(
|
|||
let struct_layout = Layout::struct_no_name_order(field_layouts);
|
||||
let struct_type = basic_type_from_layout(env, &struct_layout);
|
||||
|
||||
let data_ptr = env
|
||||
.builder
|
||||
.build_bitcast(
|
||||
value,
|
||||
struct_type.ptr_type(AddressSpace::Generic),
|
||||
"cast_lookup_at_index_ptr",
|
||||
)
|
||||
.into_pointer_value();
|
||||
let data_ptr = env.builder.build_pointer_cast(
|
||||
value,
|
||||
struct_type.ptr_type(AddressSpace::Generic),
|
||||
"cast_lookup_at_index_ptr",
|
||||
);
|
||||
|
||||
let elem_ptr = builder
|
||||
.build_struct_gep(data_ptr, index as u32, "at_index_struct_gep_data")
|
||||
|
@ -1905,11 +1900,13 @@ fn lookup_at_index_ptr2<'a, 'ctx, 'env>(
|
|||
let actual_type = basic_type_from_layout(env, &Layout::Union(*union_layout));
|
||||
debug_assert!(actual_type.is_pointer_type());
|
||||
|
||||
builder.build_bitcast(
|
||||
result,
|
||||
actual_type,
|
||||
"cast_rec_pointer_lookup_at_index_ptr_new",
|
||||
)
|
||||
builder
|
||||
.build_pointer_cast(
|
||||
result.into_pointer_value(),
|
||||
actual_type.into_pointer_type(),
|
||||
"cast_rec_pointer_lookup_at_index_ptr_new",
|
||||
)
|
||||
.into()
|
||||
} else {
|
||||
result
|
||||
}
|
||||
|
@ -1993,8 +1990,7 @@ pub fn allocate_with_refcount_help<'a, 'ctx, 'env>(
|
|||
let ptr_type = value_type.ptr_type(AddressSpace::Generic);
|
||||
|
||||
env.builder
|
||||
.build_bitcast(ptr, ptr_type, "alloc_cast_to_desired")
|
||||
.into_pointer_value()
|
||||
.build_pointer_cast(ptr, ptr_type, "alloc_cast_to_desired")
|
||||
}
|
||||
|
||||
fn list_literal<'a, 'ctx, 'env>(
|
||||
|
@ -2816,7 +2812,13 @@ pub fn complex_bitcast<'ctx>(
|
|||
// we can't use the more straightforward bitcast in all cases
|
||||
// it seems like a bitcast only works on integers and pointers
|
||||
// and crucially does not work not on arrays
|
||||
return builder.build_bitcast(from_value, to_type, name);
|
||||
return builder
|
||||
.build_pointer_cast(
|
||||
from_value.into_pointer_value(),
|
||||
to_type.into_pointer_type(),
|
||||
name,
|
||||
)
|
||||
.into();
|
||||
}
|
||||
|
||||
complex_bitcast_from_bigger_than_to(builder, from_value, to_type, name)
|
||||
|
@ -2836,7 +2838,14 @@ pub fn complex_bitcast_check_size<'a, 'ctx, 'env>(
|
|||
// we can't use the more straightforward bitcast in all cases
|
||||
// it seems like a bitcast only works on integers and pointers
|
||||
// and crucially does not work not on arrays
|
||||
return env.builder.build_bitcast(from_value, to_type, name);
|
||||
return env
|
||||
.builder
|
||||
.build_pointer_cast(
|
||||
from_value.into_pointer_value(),
|
||||
to_type.into_pointer_type(),
|
||||
name,
|
||||
)
|
||||
.into();
|
||||
}
|
||||
|
||||
let block = env.builder.get_insert_block().expect("to be in a function");
|
||||
|
@ -2892,13 +2901,11 @@ fn complex_bitcast_from_bigger_than_to<'ctx>(
|
|||
builder.build_store(argument_pointer, from_value);
|
||||
|
||||
// then read it back as a different type
|
||||
let to_type_pointer = builder
|
||||
.build_bitcast(
|
||||
argument_pointer,
|
||||
to_type.ptr_type(inkwell::AddressSpace::Generic),
|
||||
name,
|
||||
)
|
||||
.into_pointer_value();
|
||||
let to_type_pointer = builder.build_pointer_cast(
|
||||
argument_pointer,
|
||||
to_type.ptr_type(inkwell::AddressSpace::Generic),
|
||||
name,
|
||||
);
|
||||
|
||||
builder.build_load(to_type_pointer, "cast_value")
|
||||
}
|
||||
|
@ -2915,15 +2922,13 @@ fn complex_bitcast_to_bigger_than_from<'ctx>(
|
|||
let storage = builder.build_alloca(to_type, "cast_alloca");
|
||||
|
||||
// then cast the pointer to our desired type
|
||||
let from_type_pointer = builder
|
||||
.build_bitcast(
|
||||
storage,
|
||||
from_value
|
||||
.get_type()
|
||||
.ptr_type(inkwell::AddressSpace::Generic),
|
||||
name,
|
||||
)
|
||||
.into_pointer_value();
|
||||
let from_type_pointer = builder.build_pointer_cast(
|
||||
storage,
|
||||
from_value
|
||||
.get_type()
|
||||
.ptr_type(inkwell::AddressSpace::Generic),
|
||||
name,
|
||||
);
|
||||
|
||||
// store the value in memory
|
||||
builder.build_store(from_type_pointer, from_value);
|
||||
|
@ -3314,14 +3319,11 @@ fn expose_function_to_host_help_c_abi_generic<'a, 'ctx, 'env>(
|
|||
// not pretty, but seems to cover all our current cases
|
||||
if arg_type.is_pointer_type() && !fastcc_type.is_pointer_type() {
|
||||
// bitcast the ptr
|
||||
let fastcc_ptr = env
|
||||
.builder
|
||||
.build_bitcast(
|
||||
*arg,
|
||||
fastcc_type.ptr_type(AddressSpace::Generic),
|
||||
"bitcast_arg",
|
||||
)
|
||||
.into_pointer_value();
|
||||
let fastcc_ptr = env.builder.build_pointer_cast(
|
||||
arg.into_pointer_value(),
|
||||
fastcc_type.ptr_type(AddressSpace::Generic),
|
||||
"bitcast_arg",
|
||||
);
|
||||
|
||||
let loaded = env.builder.build_load(fastcc_ptr, "load_arg");
|
||||
arguments_for_call.push(loaded);
|
||||
|
@ -3643,14 +3645,11 @@ fn expose_function_to_host_help_c_abi_v2<'a, 'ctx, 'env>(
|
|||
c_function.add_attribute(AttributeLoc::Param(param_index), nonnull);
|
||||
}
|
||||
// bitcast the ptr
|
||||
let fastcc_ptr = env
|
||||
.builder
|
||||
.build_bitcast(
|
||||
*arg,
|
||||
fastcc_type.ptr_type(AddressSpace::Generic),
|
||||
"bitcast_arg",
|
||||
)
|
||||
.into_pointer_value();
|
||||
let fastcc_ptr = env.builder.build_pointer_cast(
|
||||
arg.into_pointer_value(),
|
||||
fastcc_type.ptr_type(AddressSpace::Generic),
|
||||
"bitcast_arg",
|
||||
);
|
||||
|
||||
env.builder.build_load(fastcc_ptr, "load_arg")
|
||||
} else {
|
||||
|
@ -3808,13 +3807,11 @@ pub fn get_sjlj_buffer<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> PointerValu
|
|||
|
||||
global.set_initializer(&type_.const_zero());
|
||||
|
||||
env.builder
|
||||
.build_bitcast(
|
||||
global.as_pointer_value(),
|
||||
env.context.i32_type().ptr_type(AddressSpace::Generic),
|
||||
"cast_sjlj_buffer",
|
||||
)
|
||||
.into_pointer_value()
|
||||
env.builder.build_pointer_cast(
|
||||
global.as_pointer_value(),
|
||||
env.context.i32_type().ptr_type(AddressSpace::Generic),
|
||||
"cast_sjlj_buffer",
|
||||
)
|
||||
}
|
||||
|
||||
pub fn build_setjmp_call<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> BasicValueEnum<'ctx> {
|
||||
|
@ -3826,18 +3823,15 @@ pub fn build_setjmp_call<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> BasicValu
|
|||
// Anywhere else, use the LLVM intrinsic.
|
||||
// https://llvm.org/docs/ExceptionHandling.html#llvm-eh-sjlj-setjmp
|
||||
|
||||
let jmp_buf_i8p_arr = env
|
||||
.builder
|
||||
.build_bitcast(
|
||||
jmp_buf,
|
||||
env.context
|
||||
.i8_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.array_type(5)
|
||||
.ptr_type(AddressSpace::Generic),
|
||||
"jmp_buf [5 x i8*]",
|
||||
)
|
||||
.into_pointer_value();
|
||||
let jmp_buf_i8p_arr = env.builder.build_pointer_cast(
|
||||
jmp_buf,
|
||||
env.context
|
||||
.i8_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.array_type(5)
|
||||
.ptr_type(AddressSpace::Generic),
|
||||
"jmp_buf [5 x i8*]",
|
||||
);
|
||||
|
||||
// LLVM asks us to please store the frame pointer in the first word.
|
||||
let frame_address = env.call_intrinsic(
|
||||
|
@ -3867,11 +3861,14 @@ pub fn build_setjmp_call<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> BasicValu
|
|||
let stack_save = env.call_intrinsic(LLVM_STACK_SAVE, &[]);
|
||||
env.builder.build_store(ss, stack_save);
|
||||
|
||||
let jmp_buf_i8p = env.builder.build_bitcast(
|
||||
jmp_buf,
|
||||
env.context.i8_type().ptr_type(AddressSpace::Generic),
|
||||
"jmp_buf i8*",
|
||||
);
|
||||
let jmp_buf_i8p = env
|
||||
.builder
|
||||
.build_pointer_cast(
|
||||
jmp_buf,
|
||||
env.context.i8_type().ptr_type(AddressSpace::Generic),
|
||||
"jmp_buf i8*",
|
||||
)
|
||||
.into();
|
||||
env.call_intrinsic(LLVM_SETJMP, &[jmp_buf_i8p])
|
||||
}
|
||||
}
|
||||
|
@ -5397,7 +5394,7 @@ fn build_foreign_symbol<'a, 'ctx, 'env>(
|
|||
env.builder.build_alloca(param.get_type(), "param_alloca");
|
||||
env.builder.build_store(param_alloca, param);
|
||||
|
||||
let as_cc_type = env.builder.build_bitcast(
|
||||
let as_cc_type = env.builder.build_pointer_cast(
|
||||
param_alloca,
|
||||
cc_type.into_pointer_type(),
|
||||
"to_cc_type_ptr",
|
||||
|
@ -5467,14 +5464,11 @@ fn define_global_str_literal_ptr<'a, 'ctx, 'env>(
|
|||
) -> PointerValue<'ctx> {
|
||||
let global = define_global_str_literal(env, message);
|
||||
|
||||
let ptr = env
|
||||
.builder
|
||||
.build_bitcast(
|
||||
global,
|
||||
env.context.i8_type().ptr_type(AddressSpace::Generic),
|
||||
"to_opaque",
|
||||
)
|
||||
.into_pointer_value();
|
||||
let ptr = env.builder.build_pointer_cast(
|
||||
global.as_pointer_value(),
|
||||
env.context.i8_type().ptr_type(AddressSpace::Generic),
|
||||
"to_opaque",
|
||||
);
|
||||
|
||||
// a pointer to the first actual data (skipping over the refcount)
|
||||
let ptr = unsafe {
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -70,11 +70,13 @@ fn pass_element_as_opaque<'a, 'ctx, 'env>(
|
|||
.build_alloca(element_type, "element_to_pass_as_opaque");
|
||||
store_roc_value(env, 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>(
|
||||
|
@ -93,11 +95,13 @@ 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>(
|
||||
|
|
|
@ -29,14 +29,11 @@ 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")
|
||||
|
|
|
@ -198,15 +198,17 @@ fn build_eq<'a, 'ctx, 'env>(
|
|||
let bt = basic_type_from_layout(env, &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,
|
||||
|
@ -722,15 +724,17 @@ fn build_struct_eq_help<'a, 'ctx, 'env>(
|
|||
let bt = basic_type_from_layout(env, &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,
|
||||
|
@ -1235,23 +1239,17 @@ fn eq_ptr_to_struct<'a, 'ctx, 'env>(
|
|||
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
|
||||
|
|
|
@ -380,14 +380,18 @@ fn build_clone<'a, 'ctx, 'env>(
|
|||
let bt = basic_type_from_layout(env, &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_ids,
|
||||
ptr,
|
||||
cursors,
|
||||
field1_cast,
|
||||
field1_cast.into(),
|
||||
union_layout,
|
||||
WhenRecursive::Loop(union_layout),
|
||||
)
|
||||
|
|
|
@ -263,11 +263,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()]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,14 +35,11 @@ impl<'ctx> PointerToRefcount<'ctx> {
|
|||
// must make sure it's a pointer to usize
|
||||
let refcount_type = env.ptr_int();
|
||||
|
||||
let value = env
|
||||
.builder
|
||||
.build_bitcast(
|
||||
ptr,
|
||||
refcount_type.ptr_type(AddressSpace::Generic),
|
||||
"to_refcount_ptr",
|
||||
)
|
||||
.into_pointer_value();
|
||||
let value = env.builder.build_pointer_cast(
|
||||
ptr,
|
||||
refcount_type.ptr_type(AddressSpace::Generic),
|
||||
"to_refcount_ptr",
|
||||
);
|
||||
|
||||
Self { value }
|
||||
}
|
||||
|
@ -56,9 +53,8 @@ impl<'ctx> PointerToRefcount<'ctx> {
|
|||
let refcount_type = env.ptr_int();
|
||||
let refcount_ptr_type = refcount_type.ptr_type(AddressSpace::Generic);
|
||||
|
||||
let ptr_as_usize_ptr = builder
|
||||
.build_bitcast(data_ptr, refcount_ptr_type, "as_usize_ptr")
|
||||
.into_pointer_value();
|
||||
let ptr_as_usize_ptr =
|
||||
builder.build_pointer_cast(data_ptr, refcount_ptr_type, "as_usize_ptr");
|
||||
|
||||
// get a pointer to index -1
|
||||
let index_intvalue = refcount_type.const_int(-1_i64 as u64, false);
|
||||
|
@ -203,11 +199,13 @@ fn incref_pointer<'a, 'ctx, 'env>(
|
|||
call_void_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
env.builder.build_bitcast(
|
||||
pointer,
|
||||
env.ptr_int().ptr_type(AddressSpace::Generic),
|
||||
"to_isize_ptr",
|
||||
),
|
||||
env.builder
|
||||
.build_pointer_cast(
|
||||
pointer,
|
||||
env.ptr_int().ptr_type(AddressSpace::Generic),
|
||||
"to_isize_ptr",
|
||||
)
|
||||
.into(),
|
||||
amount.into(),
|
||||
],
|
||||
roc_builtins::bitcode::UTILS_INCREF,
|
||||
|
@ -223,11 +221,13 @@ fn decref_pointer<'a, 'ctx, 'env>(
|
|||
call_void_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
env.builder.build_bitcast(
|
||||
pointer,
|
||||
env.ptr_int().ptr_type(AddressSpace::Generic),
|
||||
"to_isize_ptr",
|
||||
),
|
||||
env.builder
|
||||
.build_pointer_cast(
|
||||
pointer,
|
||||
env.ptr_int().ptr_type(AddressSpace::Generic),
|
||||
"to_isize_ptr",
|
||||
)
|
||||
.into(),
|
||||
alignment.into(),
|
||||
],
|
||||
roc_builtins::bitcode::UTILS_DECREF,
|
||||
|
@ -244,11 +244,13 @@ pub fn decref_pointer_check_null<'a, 'ctx, 'env>(
|
|||
call_void_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
env.builder.build_bitcast(
|
||||
pointer,
|
||||
env.context.i8_type().ptr_type(AddressSpace::Generic),
|
||||
"to_i8_ptr",
|
||||
),
|
||||
env.builder
|
||||
.build_pointer_cast(
|
||||
pointer,
|
||||
env.context.i8_type().ptr_type(AddressSpace::Generic),
|
||||
"to_i8_ptr",
|
||||
)
|
||||
.into(),
|
||||
alignment.into(),
|
||||
],
|
||||
roc_builtins::bitcode::UTILS_DECREF_CHECK_NULL,
|
||||
|
@ -466,10 +468,11 @@ fn modify_refcount_layout_help<'a, 'ctx, 'env>(
|
|||
let bt = basic_type_from_layout(env, &layout);
|
||||
|
||||
// cast the i64 pointer to a pointer to block of memory
|
||||
let field_cast = env
|
||||
.builder
|
||||
.build_bitcast(value, bt, "i64_to_opaque")
|
||||
.into_pointer_value();
|
||||
let field_cast = env.builder.build_pointer_cast(
|
||||
value.into_pointer_value(),
|
||||
bt.into_pointer_type(),
|
||||
"i64_to_opaque",
|
||||
);
|
||||
|
||||
call_help(env, function, call_mode, field_cast.into());
|
||||
}
|
||||
|
@ -1207,14 +1210,11 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>(
|
|||
basic_type_from_layout(env, &Layout::struct_no_name_order(field_layouts));
|
||||
|
||||
// cast the opaque pointer to a pointer of the correct shape
|
||||
let struct_ptr = env
|
||||
.builder
|
||||
.build_bitcast(
|
||||
value_ptr,
|
||||
wrapper_type.ptr_type(AddressSpace::Generic),
|
||||
"opaque_to_correct_recursive_decrement",
|
||||
)
|
||||
.into_pointer_value();
|
||||
let struct_ptr = env.builder.build_pointer_cast(
|
||||
value_ptr,
|
||||
wrapper_type.ptr_type(AddressSpace::Generic),
|
||||
"opaque_to_correct_recursive_decrement",
|
||||
);
|
||||
|
||||
// defer actually performing the refcount modifications until after the current cell has
|
||||
// been decremented, see below
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue