mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
Merge pull request #4793 from roc-lang/llvm-15-zig-10-round-2
Prepare Llvm 15 update
This commit is contained in:
commit
ec80161824
10 changed files with 462 additions and 190 deletions
|
@ -19,7 +19,8 @@ use roc_error_macros::internal_error;
|
|||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::{Builtin, LambdaSet, Layout, LayoutIds};
|
||||
|
||||
use super::build::create_entry_block_alloca;
|
||||
use super::build::{create_entry_block_alloca, BuilderExt};
|
||||
use super::convert::zig_list_type;
|
||||
|
||||
use std::convert::TryInto;
|
||||
|
||||
|
@ -139,7 +140,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 {
|
||||
|
@ -392,8 +395,8 @@ fn build_rc_wrapper<'a, 'ctx, 'env>(
|
|||
|
||||
generic_value_ptr.set_name(Symbol::ARG_1.as_str(&env.interns));
|
||||
|
||||
let value_ptr_type =
|
||||
basic_type_from_layout(env, layout).ptr_type(AddressSpace::Generic);
|
||||
let value_type = basic_type_from_layout(env, layout);
|
||||
let value_ptr_type = value_type.ptr_type(AddressSpace::Generic);
|
||||
let value_ptr =
|
||||
env.builder
|
||||
.build_pointer_cast(generic_value_ptr, value_ptr_type, "load_opaque");
|
||||
|
@ -404,7 +407,8 @@ fn build_rc_wrapper<'a, 'ctx, 'env>(
|
|||
let value = if layout.is_passed_by_reference(env.layout_interner, env.target_info) {
|
||||
value_ptr.into()
|
||||
} else {
|
||||
env.builder.build_load(value_ptr, "load_opaque")
|
||||
env.builder
|
||||
.new_build_load(value_type, value_ptr, "load_opaque")
|
||||
};
|
||||
|
||||
match rc_operation {
|
||||
|
@ -573,8 +577,12 @@ pub fn build_compare_wrapper<'a, 'ctx, 'env>(
|
|||
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()];
|
||||
|
||||
|
@ -596,7 +604,9 @@ pub fn build_compare_wrapper<'a, 'ctx, 'env>(
|
|||
"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()])
|
||||
|
@ -644,7 +654,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);
|
||||
|
|
|
@ -53,13 +53,82 @@ use std::convert::TryInto;
|
|||
use std::path::Path;
|
||||
use target_lexicon::{Architecture, OperatingSystem, Triple};
|
||||
|
||||
use super::convert::RocUnion;
|
||||
use super::convert::{struct_type_from_union_layout, RocUnion};
|
||||
use super::intrinsics::{
|
||||
add_intrinsics, LLVM_FRAME_ADDRESS, LLVM_MEMSET_I32, LLVM_MEMSET_I64, LLVM_SETJMP,
|
||||
LLVM_STACK_SAVE,
|
||||
};
|
||||
use super::lowlevel::run_higher_order_low_level;
|
||||
|
||||
pub(crate) trait BuilderExt<'ctx> {
|
||||
fn new_build_struct_gep(
|
||||
&self,
|
||||
struct_type: StructType<'ctx>,
|
||||
ptr: PointerValue<'ctx>,
|
||||
index: u32,
|
||||
name: &str,
|
||||
) -> Result<PointerValue<'ctx>, ()>;
|
||||
|
||||
fn new_build_load(
|
||||
&self,
|
||||
element_type: impl BasicType<'ctx>,
|
||||
ptr: PointerValue<'ctx>,
|
||||
name: &str,
|
||||
) -> BasicValueEnum<'ctx>;
|
||||
|
||||
unsafe fn new_build_in_bounds_gep(
|
||||
&self,
|
||||
element_type: impl BasicType<'ctx>,
|
||||
ptr: PointerValue<'ctx>,
|
||||
ordered_indexes: &[IntValue<'ctx>],
|
||||
name: &str,
|
||||
) -> PointerValue<'ctx>;
|
||||
}
|
||||
|
||||
impl<'ctx> BuilderExt<'ctx> for Builder<'ctx> {
|
||||
fn new_build_struct_gep(
|
||||
&self,
|
||||
struct_type: StructType<'ctx>,
|
||||
ptr: PointerValue<'ctx>,
|
||||
index: u32,
|
||||
name: &str,
|
||||
) -> Result<PointerValue<'ctx>, ()> {
|
||||
debug_assert_eq!(
|
||||
ptr.get_type().get_element_type().into_struct_type(),
|
||||
struct_type
|
||||
);
|
||||
self.build_struct_gep(ptr, index, name)
|
||||
}
|
||||
|
||||
fn new_build_load(
|
||||
&self,
|
||||
element_type: impl BasicType<'ctx>,
|
||||
ptr: PointerValue<'ctx>,
|
||||
name: &str,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
debug_assert_eq!(
|
||||
ptr.get_type().get_element_type(),
|
||||
element_type.as_any_type_enum()
|
||||
);
|
||||
self.build_load(ptr, name)
|
||||
}
|
||||
|
||||
unsafe fn new_build_in_bounds_gep(
|
||||
&self,
|
||||
element_type: impl BasicType<'ctx>,
|
||||
ptr: PointerValue<'ctx>,
|
||||
ordered_indexes: &[IntValue<'ctx>],
|
||||
name: &str,
|
||||
) -> PointerValue<'ctx> {
|
||||
debug_assert_eq!(
|
||||
ptr.get_type().get_element_type(),
|
||||
element_type.as_any_type_enum()
|
||||
);
|
||||
|
||||
self.build_in_bounds_gep(ptr, ordered_indexes, name)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn print_fn_verification_output() -> bool {
|
||||
dbg_do!(ROC_PRINT_LLVM_FN_VERIFICATION, {
|
||||
|
@ -773,7 +842,10 @@ fn build_string_literal<'a, 'ctx, 'env>(
|
|||
let alloca = const_str_alloca_ptr(env, parent, ptr, number_of_elements, number_of_elements);
|
||||
|
||||
match env.target_info.ptr_width() {
|
||||
PtrWidth::Bytes4 => env.builder.build_load(alloca, "load_const_str"),
|
||||
PtrWidth::Bytes4 => {
|
||||
env.builder
|
||||
.new_build_load(zig_str_type(env), alloca, "load_const_str")
|
||||
}
|
||||
PtrWidth::Bytes8 => alloca.into(),
|
||||
}
|
||||
}
|
||||
|
@ -977,7 +1049,7 @@ fn struct_pointer_from_fields<'a, 'ctx, 'env, I>(
|
|||
for (index, (field_layout, field_value)) in values {
|
||||
let field_ptr = env
|
||||
.builder
|
||||
.build_struct_gep(struct_ptr, index as u32, "field_struct_gep")
|
||||
.new_build_struct_gep(struct_type, struct_ptr, index as u32, "field_struct_gep")
|
||||
.unwrap();
|
||||
|
||||
store_roc_value(env, field_layout, field_ptr, field_value);
|
||||
|
@ -1157,30 +1229,6 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
|
|||
let field_layout = field_layouts[*index as usize];
|
||||
use_roc_value(env, field_layout, field_value, "struct_field_tag")
|
||||
}
|
||||
(
|
||||
PointerValue(argument),
|
||||
Layout::Union(UnionLayout::NonNullableUnwrapped(fields)),
|
||||
) => {
|
||||
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_pointer_cast(
|
||||
argument,
|
||||
struct_type.ptr_type(AddressSpace::Generic),
|
||||
"cast_rosetree_like",
|
||||
);
|
||||
|
||||
let ptr = env
|
||||
.builder
|
||||
.build_struct_gep(
|
||||
cast_argument,
|
||||
*index as u32,
|
||||
env.arena.alloc(format!("non_nullable_unwrapped_{}", index)),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
env.builder.build_load(ptr, "load_rosetree_like")
|
||||
}
|
||||
(other, layout) => {
|
||||
// potential cause: indexing into an unwrapped 1-element record/tag?
|
||||
unreachable!(
|
||||
|
@ -1202,7 +1250,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
|
|||
union_layout,
|
||||
} => {
|
||||
// cast the argument bytes into the desired shape for this tag
|
||||
let (argument, _structure_layout) = load_symbol_and_layout(scope, structure);
|
||||
let (argument, structure_layout) = load_symbol_and_layout(scope, structure);
|
||||
|
||||
match union_layout {
|
||||
UnionLayout::NonRecursive(tag_layouts) => {
|
||||
|
@ -1215,7 +1263,8 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
|
|||
|
||||
let opaque_data_ptr = env
|
||||
.builder
|
||||
.build_struct_gep(
|
||||
.new_build_struct_gep(
|
||||
basic_type_from_layout(env, structure_layout).into_struct_type(),
|
||||
argument.into_pointer_value(),
|
||||
RocUnion::TAG_DATA_INDEX,
|
||||
"get_opaque_data_ptr",
|
||||
|
@ -1230,7 +1279,12 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
|
|||
|
||||
let element_ptr = env
|
||||
.builder
|
||||
.build_struct_gep(data_ptr, *index as _, "get_opaque_data_ptr")
|
||||
.new_build_struct_gep(
|
||||
struct_type.into_struct_type(),
|
||||
data_ptr,
|
||||
*index as _,
|
||||
"get_opaque_data_ptr",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
load_roc_value(
|
||||
|
@ -1336,13 +1390,20 @@ fn build_wrapped_tag<'a, 'ctx, 'env>(
|
|||
|
||||
let (field_types, field_values) = build_tag_fields(env, scope, tag_field_layouts, arguments);
|
||||
|
||||
let union_struct_type = struct_type_from_union_layout(env, union_layout);
|
||||
|
||||
// Create the struct_type
|
||||
let raw_data_ptr = allocate_tag(env, parent, reuse_allocation, union_layout, tags);
|
||||
let struct_type = env.context.struct_type(&field_types, false);
|
||||
|
||||
if union_layout.stores_tag_id_as_data(env.target_info) {
|
||||
let tag_id_ptr = builder
|
||||
.build_struct_gep(raw_data_ptr, RocUnion::TAG_ID_INDEX, "tag_id_index")
|
||||
.new_build_struct_gep(
|
||||
union_struct_type,
|
||||
raw_data_ptr,
|
||||
RocUnion::TAG_ID_INDEX,
|
||||
"tag_id_index",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let tag_id_type = basic_type_from_layout(env, &tag_id_layout).into_int_type();
|
||||
|
@ -1351,7 +1412,12 @@ fn build_wrapped_tag<'a, 'ctx, 'env>(
|
|||
.build_store(tag_id_ptr, tag_id_type.const_int(tag_id as u64, false));
|
||||
|
||||
let opaque_struct_ptr = builder
|
||||
.build_struct_gep(raw_data_ptr, RocUnion::TAG_DATA_INDEX, "tag_data_index")
|
||||
.new_build_struct_gep(
|
||||
union_struct_type,
|
||||
raw_data_ptr,
|
||||
RocUnion::TAG_DATA_INDEX,
|
||||
"tag_data_index",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
struct_pointer_from_fields(
|
||||
|
@ -1464,12 +1530,15 @@ fn build_struct<'a, 'ctx, 'env>(
|
|||
// The layout of the struct expects them to be dropped!
|
||||
let (field_expr, field_layout) = load_symbol_and_layout(scope, symbol);
|
||||
if !field_layout.is_dropped_because_empty() {
|
||||
field_types.push(basic_type_from_layout(env, field_layout));
|
||||
let field_type = basic_type_from_layout(env, field_layout);
|
||||
field_types.push(field_type);
|
||||
|
||||
if field_layout.is_passed_by_reference(env.layout_interner, env.target_info) {
|
||||
let field_value = env
|
||||
.builder
|
||||
.build_load(field_expr.into_pointer_value(), "load_tag_to_put_in_struct");
|
||||
let field_value = env.builder.new_build_load(
|
||||
field_type,
|
||||
field_expr.into_pointer_value(),
|
||||
"load_tag_to_put_in_struct",
|
||||
);
|
||||
|
||||
field_vals.push(field_value);
|
||||
} else {
|
||||
|
@ -1762,13 +1831,13 @@ pub fn get_tag_id<'a, 'ctx, 'env>(
|
|||
debug_assert!(argument.is_pointer_value(), "{:?}", argument);
|
||||
|
||||
let argument_ptr = argument.into_pointer_value();
|
||||
get_tag_id_wrapped(env, argument_ptr)
|
||||
get_tag_id_wrapped(env, *union_layout, argument_ptr)
|
||||
}
|
||||
UnionLayout::Recursive(_) => {
|
||||
let argument_ptr = argument.into_pointer_value();
|
||||
|
||||
if union_layout.stores_tag_id_as_data(env.target_info) {
|
||||
get_tag_id_wrapped(env, argument_ptr)
|
||||
get_tag_id_wrapped(env, *union_layout, argument_ptr)
|
||||
} else {
|
||||
tag_pointer_read_tag_id(env, argument_ptr)
|
||||
}
|
||||
|
@ -1799,7 +1868,7 @@ pub fn get_tag_id<'a, 'ctx, 'env>(
|
|||
env.builder.position_at_end(else_block);
|
||||
|
||||
let tag_id = if union_layout.stores_tag_id_as_data(env.target_info) {
|
||||
get_tag_id_wrapped(env, argument_ptr)
|
||||
get_tag_id_wrapped(env, *union_layout, argument_ptr)
|
||||
} else {
|
||||
tag_pointer_read_tag_id(env, argument_ptr)
|
||||
};
|
||||
|
@ -1810,7 +1879,7 @@ pub fn get_tag_id<'a, 'ctx, 'env>(
|
|||
env.builder.position_at_end(cont_block);
|
||||
|
||||
env.builder
|
||||
.build_load(result, "load_result")
|
||||
.new_build_load(tag_id_int_type, result, "load_result")
|
||||
.into_int_value()
|
||||
}
|
||||
UnionLayout::NullableUnwrapped { nullable_id, .. } => {
|
||||
|
@ -1844,7 +1913,7 @@ fn lookup_at_index_ptr<'a, 'ctx, 'env>(
|
|||
);
|
||||
|
||||
let elem_ptr = builder
|
||||
.build_struct_gep(ptr, index as u32, "at_index_struct_gep")
|
||||
.new_build_struct_gep(struct_type, ptr, index as u32, "at_index_struct_gep")
|
||||
.unwrap();
|
||||
|
||||
let field_layout = field_layouts[index];
|
||||
|
@ -1878,7 +1947,7 @@ fn lookup_at_index_ptr2<'a, 'ctx, 'env>(
|
|||
let builder = env.builder;
|
||||
|
||||
let struct_layout = Layout::struct_no_name_order(field_layouts);
|
||||
let struct_type = basic_type_from_layout(env, &struct_layout);
|
||||
let struct_type = basic_type_from_layout(env, &struct_layout).into_struct_type();
|
||||
|
||||
let data_ptr = env.builder.build_pointer_cast(
|
||||
value,
|
||||
|
@ -1887,7 +1956,12 @@ fn lookup_at_index_ptr2<'a, 'ctx, 'env>(
|
|||
);
|
||||
|
||||
let elem_ptr = builder
|
||||
.build_struct_gep(data_ptr, index as u32, "at_index_struct_gep_data")
|
||||
.new_build_struct_gep(
|
||||
struct_type,
|
||||
data_ptr,
|
||||
index as u32,
|
||||
"at_index_struct_gep_data",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let field_layout = field_layouts[index];
|
||||
|
@ -2096,8 +2170,12 @@ fn list_literal<'a, 'ctx, 'env>(
|
|||
let offset = env.ptr_int().const_int(zero_elements as _, false);
|
||||
|
||||
let ptr = unsafe {
|
||||
env.builder
|
||||
.build_in_bounds_gep(global, &[zero, offset], "first_element_pointer")
|
||||
env.builder.new_build_in_bounds_gep(
|
||||
element_type,
|
||||
global,
|
||||
&[zero, offset],
|
||||
"first_element_pointer",
|
||||
)
|
||||
};
|
||||
|
||||
super::build_list::store_list(env, ptr, list_length_intval).into()
|
||||
|
@ -2119,7 +2197,9 @@ fn list_literal<'a, 'ctx, 'env>(
|
|||
// then replace the `undef`s with the values that we evaluate at runtime
|
||||
for (index, val) in runtime_evaluated_elements {
|
||||
let index_val = ctx.i64_type().const_int(index as u64, false);
|
||||
let elem_ptr = unsafe { builder.build_in_bounds_gep(ptr, &[index_val], "index") };
|
||||
let elem_ptr = unsafe {
|
||||
builder.new_build_in_bounds_gep(element_type, ptr, &[index_val], "index")
|
||||
};
|
||||
|
||||
builder.build_store(elem_ptr, val);
|
||||
}
|
||||
|
@ -2138,7 +2218,9 @@ fn list_literal<'a, 'ctx, 'env>(
|
|||
ListLiteralElement::Symbol(symbol) => load_symbol(scope, symbol),
|
||||
};
|
||||
let index_val = ctx.i64_type().const_int(index as u64, false);
|
||||
let elem_ptr = unsafe { builder.build_in_bounds_gep(ptr, &[index_val], "index") };
|
||||
let elem_ptr = unsafe {
|
||||
builder.new_build_in_bounds_gep(element_type, ptr, &[index_val], "index")
|
||||
};
|
||||
|
||||
store_roc_value(env, *element_layout, elem_ptr, val);
|
||||
}
|
||||
|
@ -2153,14 +2235,16 @@ pub fn load_roc_value<'a, 'ctx, 'env>(
|
|||
source: PointerValue<'ctx>,
|
||||
name: &str,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let basic_type = basic_type_from_layout(env, &layout);
|
||||
|
||||
if layout.is_passed_by_reference(env.layout_interner, env.target_info) {
|
||||
let alloca = entry_block_alloca_zerofill(env, basic_type_from_layout(env, &layout), name);
|
||||
let alloca = entry_block_alloca_zerofill(env, basic_type, name);
|
||||
|
||||
store_roc_value(env, layout, alloca, source.into());
|
||||
|
||||
alloca.into()
|
||||
} else {
|
||||
env.builder.build_load(source, name)
|
||||
env.builder.new_build_load(basic_type, source, name)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2907,7 +2991,7 @@ fn complex_bitcast_from_bigger_than_to<'ctx>(
|
|||
name,
|
||||
);
|
||||
|
||||
builder.build_load(to_type_pointer, "cast_value")
|
||||
builder.new_build_load(to_type, to_type_pointer, "cast_value")
|
||||
}
|
||||
|
||||
fn complex_bitcast_to_bigger_than_from<'ctx>(
|
||||
|
@ -2934,21 +3018,30 @@ fn complex_bitcast_to_bigger_than_from<'ctx>(
|
|||
builder.build_store(from_type_pointer, from_value);
|
||||
|
||||
// then read it back as a different type
|
||||
builder.build_load(storage, "cast_value")
|
||||
builder.new_build_load(to_type, storage, "cast_value")
|
||||
}
|
||||
|
||||
/// get the tag id out of a pointer to a wrapped (i.e. stores the tag id at runtime) layout
|
||||
fn get_tag_id_wrapped<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
union_layout: UnionLayout<'a>,
|
||||
from_value: PointerValue<'ctx>,
|
||||
) -> IntValue<'ctx> {
|
||||
let union_struct_type = struct_type_from_union_layout(env, &union_layout);
|
||||
let tag_id_type = basic_type_from_layout(env, &union_layout.tag_id_layout());
|
||||
|
||||
let tag_id_ptr = env
|
||||
.builder
|
||||
.build_struct_gep(from_value, RocUnion::TAG_ID_INDEX, "tag_id_ptr")
|
||||
.new_build_struct_gep(
|
||||
union_struct_type,
|
||||
from_value,
|
||||
RocUnion::TAG_ID_INDEX,
|
||||
"tag_id_ptr",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
env.builder
|
||||
.build_load(tag_id_ptr, "load_tag_id")
|
||||
.new_build_load(tag_id_type, tag_id_ptr, "load_tag_id")
|
||||
.into_int_value()
|
||||
}
|
||||
|
||||
|
@ -3325,7 +3418,9 @@ fn expose_function_to_host_help_c_abi_generic<'a, 'ctx, 'env>(
|
|||
"bitcast_arg",
|
||||
);
|
||||
|
||||
let loaded = env.builder.build_load(fastcc_ptr, "load_arg");
|
||||
let loaded = env
|
||||
.builder
|
||||
.new_build_load(fastcc_type, fastcc_ptr, "load_arg");
|
||||
arguments_for_call.push(loaded);
|
||||
} else {
|
||||
let as_cc_type = env.builder.build_pointer_cast(
|
||||
|
@ -3441,9 +3536,11 @@ fn expose_function_to_host_help_c_abi_gen_test<'a, 'ctx, 'env>(
|
|||
} else {
|
||||
match layout {
|
||||
Layout::Builtin(Builtin::List(_)) => {
|
||||
let loaded = env
|
||||
.builder
|
||||
.build_load(arg.into_pointer_value(), "load_list_pointer");
|
||||
let loaded = env.builder.new_build_load(
|
||||
arg_type,
|
||||
arg.into_pointer_value(),
|
||||
"load_list_pointer",
|
||||
);
|
||||
let cast =
|
||||
complex_bitcast_check_size(env, loaded, fastcc_type, "to_fastcc_type_1");
|
||||
arguments_for_call.push(cast);
|
||||
|
@ -3651,7 +3748,8 @@ fn expose_function_to_host_help_c_abi_v2<'a, 'ctx, 'env>(
|
|||
"bitcast_arg",
|
||||
);
|
||||
|
||||
env.builder.build_load(fastcc_ptr, "load_arg")
|
||||
env.builder
|
||||
.new_build_load(*fastcc_type, fastcc_ptr, "load_arg")
|
||||
} else {
|
||||
complex_bitcast_check_size(env, *arg, *fastcc_type, "to_fastcc_type_2")
|
||||
}
|
||||
|
@ -3668,9 +3766,11 @@ fn expose_function_to_host_help_c_abi_v2<'a, 'ctx, 'env>(
|
|||
env.builder.build_return(Some(&value));
|
||||
}
|
||||
RocReturn::ByPointer => {
|
||||
let loaded = env
|
||||
.builder
|
||||
.build_load(value.into_pointer_value(), "load_result");
|
||||
let loaded = env.builder.new_build_load(
|
||||
return_type,
|
||||
value.into_pointer_value(),
|
||||
"load_result",
|
||||
);
|
||||
env.builder.build_return(Some(&loaded));
|
||||
}
|
||||
},
|
||||
|
@ -3684,9 +3784,11 @@ fn expose_function_to_host_help_c_abi_v2<'a, 'ctx, 'env>(
|
|||
// TODO: ideally, in this case, we should pass the C return pointer directly
|
||||
// into the call_roc_function rather than forcing an extra alloca, load, and
|
||||
// store!
|
||||
let value = env
|
||||
.builder
|
||||
.build_load(value.into_pointer_value(), "load_roc_result");
|
||||
let value = env.builder.new_build_load(
|
||||
return_type,
|
||||
value.into_pointer_value(),
|
||||
"load_roc_result",
|
||||
);
|
||||
env.builder.build_store(out_ptr, value);
|
||||
}
|
||||
}
|
||||
|
@ -3823,13 +3925,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 buf_type = env
|
||||
.context
|
||||
.i8_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.array_type(5);
|
||||
|
||||
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),
|
||||
buf_type.ptr_type(AddressSpace::Generic),
|
||||
"jmp_buf [5 x i8*]",
|
||||
);
|
||||
|
||||
|
@ -3842,7 +3946,8 @@ pub fn build_setjmp_call<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> BasicValu
|
|||
let zero = env.context.i32_type().const_zero();
|
||||
let fa_index = env.context.i32_type().const_zero();
|
||||
let fa = unsafe {
|
||||
env.builder.build_in_bounds_gep(
|
||||
env.builder.new_build_in_bounds_gep(
|
||||
buf_type,
|
||||
jmp_buf_i8p_arr,
|
||||
&[zero, fa_index],
|
||||
"frame address index",
|
||||
|
@ -3855,8 +3960,12 @@ pub fn build_setjmp_call<'a, 'ctx, 'env>(env: &Env<'a, 'ctx, 'env>) -> BasicValu
|
|||
// usage. But for whatever reason, on x86, it appears we need a stacksave in those words.
|
||||
let ss_index = env.context.i32_type().const_int(2, false);
|
||||
let ss = unsafe {
|
||||
env.builder
|
||||
.build_in_bounds_gep(jmp_buf_i8p_arr, &[zero, ss_index], "name")
|
||||
env.builder.new_build_in_bounds_gep(
|
||||
buf_type,
|
||||
jmp_buf_i8p_arr,
|
||||
&[zero, ss_index],
|
||||
"name",
|
||||
)
|
||||
};
|
||||
let stack_save = env.call_intrinsic(LLVM_STACK_SAVE, &[]);
|
||||
env.builder.build_store(ss, stack_save);
|
||||
|
@ -3957,7 +4066,8 @@ fn set_jump_and_catch_long_jump<'a, 'ctx, 'env>(
|
|||
let v1 = call_result_type.const_zero();
|
||||
|
||||
// tag must be non-zero, indicating failure
|
||||
let tag = builder.build_load(error_tag_ptr, "load_panic_tag");
|
||||
let tag =
|
||||
builder.new_build_load(env.context.i64_type(), error_tag_ptr, "load_panic_tag");
|
||||
|
||||
let v2 = builder.build_insert_value(v1, tag, 0, "set_error").unwrap();
|
||||
|
||||
|
@ -3974,7 +4084,11 @@ fn set_jump_and_catch_long_jump<'a, 'ctx, 'env>(
|
|||
|
||||
env.builder.position_at_end(cont_block);
|
||||
|
||||
builder.build_load(result_alloca, "set_jump_and_catch_long_jump_load_result")
|
||||
builder.new_build_load(
|
||||
call_result_type,
|
||||
result_alloca,
|
||||
"set_jump_and_catch_long_jump_load_result",
|
||||
)
|
||||
}
|
||||
|
||||
fn make_exception_catcher<'a, 'ctx, 'env>(
|
||||
|
@ -4024,6 +4138,8 @@ fn make_good_roc_result<'a, 'ctx, 'env>(
|
|||
let context = env.context;
|
||||
let builder = env.builder;
|
||||
|
||||
let return_type = basic_type_from_layout(env, &return_layout);
|
||||
|
||||
let v1 = roc_call_result_type(env, basic_type_from_layout(env, &return_layout)).const_zero();
|
||||
|
||||
let v2 = builder
|
||||
|
@ -4031,7 +4147,8 @@ fn make_good_roc_result<'a, 'ctx, 'env>(
|
|||
.unwrap();
|
||||
|
||||
let v3 = if return_layout.is_passed_by_reference(env.layout_interner, env.target_info) {
|
||||
let loaded = env.builder.build_load(
|
||||
let loaded = env.builder.new_build_load(
|
||||
return_type,
|
||||
return_value.into_pointer_value(),
|
||||
"load_call_result_passed_by_ptr",
|
||||
);
|
||||
|
@ -4622,7 +4739,8 @@ fn build_closure_caller<'a, 'ctx, 'env>(
|
|||
if param.is_pointer_value()
|
||||
&& !layout.is_passed_by_reference(env.layout_interner, env.target_info)
|
||||
{
|
||||
*param = builder.build_load(param.into_pointer_value(), "load_param");
|
||||
let basic_type = basic_type_from_layout(env, layout);
|
||||
*param = builder.new_build_load(basic_type, param.into_pointer_value(), "load_param");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4922,7 +5040,8 @@ pub fn call_roc_function<'a, 'ctx, 'env>(
|
|||
debug_assert_eq!(roc_function.get_call_conventions(), FAST_CALL_CONV);
|
||||
call.set_call_convention(FAST_CALL_CONV);
|
||||
|
||||
env.builder.build_load(result_alloca, "load_result")
|
||||
env.builder
|
||||
.new_build_load(result_type, result_alloca, "load_result")
|
||||
}
|
||||
RocReturn::ByPointer => {
|
||||
let it = arguments.iter().map(|x| (*x).into());
|
||||
|
@ -4946,8 +5065,11 @@ pub fn call_roc_function<'a, 'ctx, 'env>(
|
|||
if result_layout.is_passed_by_reference(env.layout_interner, env.target_info) {
|
||||
result_alloca.into()
|
||||
} else {
|
||||
env.builder
|
||||
.build_load(result_alloca, "return_by_pointer_load_result")
|
||||
env.builder.new_build_load(
|
||||
result_type,
|
||||
result_alloca,
|
||||
"return_by_pointer_load_result",
|
||||
)
|
||||
}
|
||||
}
|
||||
RocReturn::Return => {
|
||||
|
@ -5424,9 +5546,11 @@ fn build_foreign_symbol<'a, 'ctx, 'env>(
|
|||
let return_value = match cc_return {
|
||||
CCReturn::Return => call.try_as_basic_value().left().unwrap(),
|
||||
|
||||
CCReturn::ByPointer => {
|
||||
env.builder.build_load(return_pointer, "read_result")
|
||||
}
|
||||
CCReturn::ByPointer => env.builder.new_build_load(
|
||||
return_type,
|
||||
return_pointer,
|
||||
"read_result",
|
||||
),
|
||||
CCReturn::Void => return_type.const_zero(),
|
||||
};
|
||||
|
||||
|
@ -5472,7 +5596,8 @@ fn define_global_str_literal_ptr<'a, 'ctx, 'env>(
|
|||
|
||||
// a pointer to the first actual data (skipping over the refcount)
|
||||
let ptr = unsafe {
|
||||
env.builder.build_in_bounds_gep(
|
||||
env.builder.new_build_in_bounds_gep(
|
||||
env.context.i8_type(),
|
||||
ptr,
|
||||
&[env
|
||||
.ptr_int()
|
||||
|
@ -5611,7 +5736,7 @@ pub fn add_func<'ctx>(
|
|||
fn_val
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub(crate) enum WhenRecursive<'a> {
|
||||
Unreachable,
|
||||
Loop(UnionLayout<'a>),
|
||||
|
|
|
@ -17,6 +17,7 @@ use roc_mono::layout::{Builtin, Layout, LayoutIds};
|
|||
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;
|
||||
|
||||
|
@ -138,8 +139,14 @@ pub(crate) fn list_get_unsafe<'a, 'ctx, 'env>(
|
|||
|
||||
// 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");
|
||||
|
||||
|
@ -319,7 +326,9 @@ 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.
|
||||
|
@ -608,9 +617,12 @@ where
|
|||
{
|
||||
let builder = env.builder;
|
||||
|
||||
let element_type = basic_type_from_layout(env, &element_layout);
|
||||
|
||||
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_ptr =
|
||||
unsafe { builder.new_build_in_bounds_gep(element_type, ptr, &[index], "load_index") };
|
||||
|
||||
let elem = load_roc_value(
|
||||
env,
|
||||
|
@ -655,7 +667,9 @@ 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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
@ -36,7 +37,11 @@ pub(crate) fn decode_from_utf8_result<'a, 'ctx, 'env>(
|
|||
);
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
|||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::{Builtin, Layout, LayoutIds, 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;
|
||||
|
||||
|
@ -527,7 +527,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 =
|
||||
|
@ -542,14 +544,16 @@ 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") };
|
||||
let elem_ptr = unsafe {
|
||||
builder.new_build_in_bounds_gep(element_type, ptr1, &[curr_index], "load_index")
|
||||
};
|
||||
load_roc_value(env, *element_layout, elem_ptr, "get_elem")
|
||||
};
|
||||
|
||||
let elem2 = {
|
||||
let elem_ptr =
|
||||
unsafe { builder.build_in_bounds_gep(ptr2, &[curr_index], "load_index") };
|
||||
let elem_ptr = unsafe {
|
||||
builder.new_build_in_bounds_gep(element_type, ptr2, &[curr_index], "load_index")
|
||||
};
|
||||
load_roc_value(env, *element_layout, elem_ptr, "get_elem")
|
||||
};
|
||||
|
||||
|
@ -756,7 +760,7 @@ fn build_struct_eq_help<'a, 'ctx, 'env>(
|
|||
use_roc_value(env, *field_layout, field2, "field2"),
|
||||
field_layout,
|
||||
field_layout,
|
||||
when_recursive.clone(),
|
||||
when_recursive,
|
||||
)
|
||||
.into_int_value()
|
||||
};
|
||||
|
@ -948,7 +952,7 @@ fn build_tag_eq_help<'a, 'ctx, 'env>(
|
|||
env,
|
||||
layout_ids,
|
||||
union_layout,
|
||||
Some(when_recursive.clone()),
|
||||
Some(when_recursive),
|
||||
field_layouts,
|
||||
tag1,
|
||||
tag2,
|
||||
|
@ -1253,12 +1257,12 @@ fn eq_ptr_to_struct<'a, 'ctx, 'env>(
|
|||
|
||||
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(
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
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};
|
||||
|
@ -53,18 +53,16 @@ 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>,
|
||||
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)
|
||||
.struct_type()
|
||||
.into()
|
||||
}
|
||||
Recursive(tags)
|
||||
| NullableWrapped {
|
||||
|
@ -78,8 +76,6 @@ pub fn basic_type_from_union_layout<'a, 'ctx, 'env>(
|
|||
env.target_info,
|
||||
)
|
||||
.struct_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.into()
|
||||
} else {
|
||||
RocUnion::untagged_from_slices(
|
||||
env.layout_interner,
|
||||
|
@ -88,8 +84,6 @@ pub fn basic_type_from_union_layout<'a, 'ctx, 'env>(
|
|||
env.target_info,
|
||||
)
|
||||
.struct_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
NullableUnwrapped { other_fields, .. } => RocUnion::untagged_from_slices(
|
||||
|
@ -98,18 +92,31 @@ pub fn basic_type_from_union_layout<'a, 'ctx, 'env>(
|
|||
&[other_fields],
|
||||
env.target_info,
|
||||
)
|
||||
.struct_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.into(),
|
||||
.struct_type(),
|
||||
NonNullableUnwrapped(fields) => RocUnion::untagged_from_slices(
|
||||
env.layout_interner,
|
||||
env.context,
|
||||
&[fields],
|
||||
env.target_info,
|
||||
)
|
||||
.struct_type()
|
||||
.ptr_type(AddressSpace::Generic)
|
||||
.into(),
|
||||
.struct_type(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn basic_type_from_union_layout<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
union_layout: &UnionLayout<'_>,
|
||||
) -> BasicTypeEnum<'ctx> {
|
||||
use UnionLayout::*;
|
||||
|
||||
let struct_type = struct_type_from_union_layout(env, union_layout);
|
||||
|
||||
match union_layout {
|
||||
NonRecursive(_) => struct_type.into(),
|
||||
Recursive(_)
|
||||
| NonNullableUnwrapped(_)
|
||||
| NullableWrapped { .. }
|
||||
| NullableUnwrapped { .. } => struct_type.ptr_type(AddressSpace::Generic).into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -363,7 +370,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(
|
||||
|
@ -389,7 +401,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);
|
||||
|
@ -398,7 +415,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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,10 +14,12 @@ use roc_mono::ir::LookupType;
|
|||
use roc_mono::layout::{Builtin, Layout, LayoutIds, 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>);
|
||||
|
||||
|
@ -53,10 +55,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
|
||||
|
@ -97,10 +100,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())
|
||||
}
|
||||
|
@ -115,7 +120,7 @@ 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);
|
||||
|
@ -237,8 +242,12 @@ pub(crate) fn clone_to_shared_memory<'a, 'ctx, 'env>(
|
|||
// Store the specialized variable of the value
|
||||
{
|
||||
let ptr = unsafe {
|
||||
env.builder
|
||||
.build_in_bounds_gep(original_ptr, &[offset], "at_current_offset")
|
||||
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);
|
||||
|
@ -267,13 +276,6 @@ 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>,
|
||||
|
@ -312,8 +314,12 @@ fn build_clone<'a, 'ctx, 'env>(
|
|||
Layout::Union(union_layout) => {
|
||||
if layout.safe_to_memcpy(env.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);
|
||||
|
@ -531,12 +537,20 @@ fn build_clone_tag<'a, 'ctx, 'env>(
|
|||
|
||||
fn load_tag_data<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
union_layout: UnionLayout<'a>,
|
||||
tag_value: PointerValue<'ctx>,
|
||||
tag_type: BasicTypeEnum<'ctx>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let union_struct_type = struct_type_from_union_layout(env, &union_layout);
|
||||
|
||||
let raw_data_ptr = env
|
||||
.builder
|
||||
.build_struct_gep(tag_value, RocUnion::TAG_DATA_INDEX, "tag_data")
|
||||
.new_build_struct_gep(
|
||||
union_struct_type,
|
||||
tag_value,
|
||||
RocUnion::TAG_DATA_INDEX,
|
||||
"tag_data",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let data_ptr = env.builder.build_pointer_cast(
|
||||
|
@ -545,7 +559,7 @@ fn load_tag_data<'a, 'ctx, 'env>(
|
|||
"data_ptr",
|
||||
);
|
||||
|
||||
env.builder.build_load(data_ptr, "load_data")
|
||||
env.builder.new_build_load(tag_type, data_ptr, "load_data")
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
|
@ -613,7 +627,12 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
|||
);
|
||||
|
||||
let basic_type = basic_type_from_layout(env, &layout);
|
||||
let data = load_tag_data(env, tag_value.into_pointer_value(), basic_type);
|
||||
let data = load_tag_data(
|
||||
env,
|
||||
union_layout,
|
||||
tag_value.into_pointer_value(),
|
||||
basic_type,
|
||||
);
|
||||
|
||||
let answer =
|
||||
build_clone(env, layout_ids, ptr, cursors, data, layout, when_recursive);
|
||||
|
@ -662,7 +681,7 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
|||
};
|
||||
|
||||
let basic_type = basic_type_from_layout(env, &layout);
|
||||
let data = load_tag_data(env, tag_value, basic_type);
|
||||
let data = load_tag_data(env, union_layout, tag_value, basic_type);
|
||||
|
||||
let (width, _) =
|
||||
union_layout.data_size_and_alignment(env.layout_interner, env.target_info);
|
||||
|
@ -717,7 +736,7 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
|||
),
|
||||
};
|
||||
|
||||
let data = load_tag_data(env, tag_value, basic_type);
|
||||
let data = load_tag_data(env, 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);
|
||||
|
@ -776,7 +795,7 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
|||
};
|
||||
|
||||
let tag_value = tag_pointer_clear_tag_id(env, tag_value.into_pointer_value());
|
||||
let data = load_tag_data(env, tag_value, basic_type);
|
||||
let data = load_tag_data(env, union_layout, tag_value, basic_type);
|
||||
|
||||
let when_recursive = WhenRecursive::Loop(union_layout);
|
||||
let answer =
|
||||
|
@ -850,7 +869,12 @@ fn build_clone_tag_help<'a, 'ctx, 'env>(
|
|||
),
|
||||
};
|
||||
|
||||
let data = load_tag_data(env, tag_value.into_pointer_value(), basic_type);
|
||||
let data = load_tag_data(
|
||||
env,
|
||||
union_layout,
|
||||
tag_value.into_pointer_value(),
|
||||
basic_type,
|
||||
);
|
||||
|
||||
let when_recursive = WhenRecursive::Loop(union_layout);
|
||||
let answer =
|
||||
|
@ -897,8 +921,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);
|
||||
|
@ -968,7 +996,7 @@ fn build_clone_builtin<'a, 'ctx, 'env>(
|
|||
|
||||
if elem.safe_to_memcpy(env.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),
|
||||
|
@ -1007,7 +1035,8 @@ fn build_clone_builtin<'a, 'ctx, 'env>(
|
|||
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();
|
||||
|
@ -1038,7 +1067,7 @@ fn build_clone_builtin<'a, 'ctx, 'env>(
|
|||
|
||||
incrementing_elem_loop(env, parent, *elem, elements, len, "index", body);
|
||||
|
||||
bd.build_load(rest_offset, "rest_start_offset")
|
||||
bd.new_build_load(env.ptr_int(), rest_offset, "rest_start_offset")
|
||||
.into_int_value()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::llvm::bitcode::call_void_bitcode_fn;
|
||||
use crate::llvm::build::{add_func, get_panic_msg_ptr, get_panic_tag_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;
|
||||
|
@ -217,7 +218,12 @@ pub fn add_sjlj_roc_panic(env: &Env<'_, '_, '_>) {
|
|||
roc_target::PtrWidth::Bytes4 => roc_str_arg,
|
||||
// On 64-bit we pass RocStrs by reference internally
|
||||
roc_target::PtrWidth::Bytes8 => {
|
||||
builder.build_load(roc_str_arg.into_pointer_value(), "load_roc_str")
|
||||
let str_typ = zig_str_type(env);
|
||||
builder.new_build_load(
|
||||
str_typ,
|
||||
roc_str_arg.into_pointer_value(),
|
||||
"load_roc_str",
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -24,7 +24,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,
|
||||
|
@ -464,7 +464,8 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
|
|||
"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(
|
||||
|
@ -1693,7 +1694,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()
|
||||
}
|
||||
|
||||
|
@ -2082,15 +2083,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>(
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
use crate::debug_info_init;
|
||||
use crate::llvm::bitcode::call_void_bitcode_fn;
|
||||
use crate::llvm::build::BuilderExt;
|
||||
use crate::llvm::build::{
|
||||
add_func, cast_basic_basic, get_tag_id, tag_pointer_clear_tag_id, use_roc_value, Env,
|
||||
WhenRecursive, FAST_CALL_CONV,
|
||||
};
|
||||
use crate::llvm::build_list::{incrementing_elem_loop, list_len, load_list};
|
||||
use crate::llvm::convert::{basic_type_from_layout, RocUnion};
|
||||
use crate::llvm::convert::{basic_type_from_layout, zig_str_type, RocUnion};
|
||||
use bumpalo::collections::Vec;
|
||||
use inkwell::basic_block::BasicBlock;
|
||||
use inkwell::module::Linkage;
|
||||
|
@ -59,7 +60,12 @@ impl<'ctx> PointerToRefcount<'ctx> {
|
|||
// get a pointer to index -1
|
||||
let index_intvalue = refcount_type.const_int(-1_i64 as u64, false);
|
||||
let refcount_ptr = unsafe {
|
||||
builder.build_in_bounds_gep(ptr_as_usize_ptr, &[index_intvalue], "get_rc_ptr")
|
||||
builder.new_build_in_bounds_gep(
|
||||
env.ptr_int(),
|
||||
ptr_as_usize_ptr,
|
||||
&[index_intvalue],
|
||||
"get_rc_ptr",
|
||||
)
|
||||
};
|
||||
|
||||
Self {
|
||||
|
@ -94,7 +100,7 @@ impl<'ctx> PointerToRefcount<'ctx> {
|
|||
|
||||
fn get_refcount<'a, 'env>(&self, env: &Env<'a, 'ctx, 'env>) -> IntValue<'ctx> {
|
||||
env.builder
|
||||
.build_load(self.value, "get_refcount")
|
||||
.new_build_load(env.ptr_int(), self.value, "get_refcount")
|
||||
.into_int_value()
|
||||
}
|
||||
|
||||
|
@ -541,7 +547,7 @@ fn modify_refcount_layout_build_function<'a, 'ctx, 'env>(
|
|||
|
||||
NonRecursive(tags) => {
|
||||
let function =
|
||||
modify_refcount_union(env, layout_ids, mode, when_recursive, tags);
|
||||
modify_refcount_nonrecursive(env, layout_ids, mode, when_recursive, tags);
|
||||
|
||||
Some(function)
|
||||
}
|
||||
|
@ -798,8 +804,9 @@ fn modify_refcount_str_help<'a, 'ctx, 'env>(
|
|||
let arg_val = if Layout::Builtin(Builtin::Str)
|
||||
.is_passed_by_reference(env.layout_interner, env.target_info)
|
||||
{
|
||||
let str_type = zig_str_type(env);
|
||||
env.builder
|
||||
.build_load(arg_val.into_pointer_value(), "load_str_to_stack")
|
||||
.new_build_load(str_type, arg_val.into_pointer_value(), "load_str_to_stack")
|
||||
} else {
|
||||
// it's already a struct, just do nothing
|
||||
debug_assert!(arg_val.is_struct_value());
|
||||
|
@ -1226,12 +1233,19 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>(
|
|||
// this field has type `*i64`, but is really a pointer to the data we want
|
||||
let elem_pointer = env
|
||||
.builder
|
||||
.build_struct_gep(struct_ptr, i as u32, "gep_recursive_pointer")
|
||||
.new_build_struct_gep(
|
||||
wrapper_type.into_struct_type(),
|
||||
struct_ptr,
|
||||
i as u32,
|
||||
"gep_recursive_pointer",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let ptr_as_i64_ptr = env
|
||||
.builder
|
||||
.build_load(elem_pointer, "load_recursive_pointer");
|
||||
let ptr_as_i64_ptr = env.builder.new_build_load(
|
||||
env.context.i64_type().ptr_type(AddressSpace::Generic),
|
||||
elem_pointer,
|
||||
"load_recursive_pointer",
|
||||
);
|
||||
|
||||
debug_assert!(ptr_as_i64_ptr.is_pointer_value());
|
||||
|
||||
|
@ -1243,7 +1257,12 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>(
|
|||
} else if field_layout.contains_refcounted(env.layout_interner) {
|
||||
let elem_pointer = env
|
||||
.builder
|
||||
.build_struct_gep(struct_ptr, i as u32, "gep_recursive_pointer")
|
||||
.new_build_struct_gep(
|
||||
wrapper_type.into_struct_type(),
|
||||
struct_ptr,
|
||||
i as u32,
|
||||
"gep_recursive_pointer",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let field =
|
||||
|
@ -1499,7 +1518,7 @@ fn function_name_from_mode<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
fn modify_refcount_union<'a, 'ctx, 'env>(
|
||||
fn modify_refcount_nonrecursive<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
mode: Mode,
|
||||
|
@ -1527,7 +1546,7 @@ fn modify_refcount_union<'a, 'ctx, 'env>(
|
|||
let basic_type = argument_type_from_union_layout(env, &union_layout);
|
||||
let function_value = build_header(env, basic_type, mode, &fn_name);
|
||||
|
||||
modify_refcount_union_help(
|
||||
modify_refcount_nonrecursive_help(
|
||||
env,
|
||||
layout_ids,
|
||||
mode,
|
||||
|
@ -1547,7 +1566,7 @@ fn modify_refcount_union<'a, 'ctx, 'env>(
|
|||
function
|
||||
}
|
||||
|
||||
fn modify_refcount_union_help<'a, 'ctx, 'env>(
|
||||
fn modify_refcount_nonrecursive_help<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
mode: Mode,
|
||||
|
@ -1577,15 +1596,28 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>(
|
|||
|
||||
let before_block = env.builder.get_insert_block().expect("to be in a function");
|
||||
|
||||
let union_layout = UnionLayout::NonRecursive(tags);
|
||||
let layout = Layout::Union(union_layout);
|
||||
let union_struct_type = basic_type_from_layout(env, &layout).into_struct_type();
|
||||
|
||||
// read the tag_id
|
||||
let tag_id_ptr = env
|
||||
.builder
|
||||
.build_struct_gep(arg_ptr, RocUnion::TAG_ID_INDEX, "tag_id_ptr")
|
||||
.new_build_struct_gep(
|
||||
union_struct_type,
|
||||
arg_ptr,
|
||||
RocUnion::TAG_ID_INDEX,
|
||||
"tag_id_ptr",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let tag_id = env
|
||||
.builder
|
||||
.build_load(tag_id_ptr, "load_tag_id")
|
||||
.new_build_load(
|
||||
basic_type_from_layout(env, &union_layout.tag_id_layout()),
|
||||
tag_id_ptr,
|
||||
"load_tag_id",
|
||||
)
|
||||
.into_int_value();
|
||||
|
||||
let tag_id_u8 =
|
||||
|
@ -1611,18 +1643,24 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>(
|
|||
let block = env.context.append_basic_block(parent, "tag_id_modify");
|
||||
env.builder.position_at_end(block);
|
||||
|
||||
let wrapper_type =
|
||||
let data_struct_type =
|
||||
basic_type_from_layout(env, &Layout::struct_no_name_order(field_layouts));
|
||||
|
||||
debug_assert!(wrapper_type.is_struct_type());
|
||||
debug_assert!(data_struct_type.is_struct_type());
|
||||
let data_struct_type = data_struct_type.into_struct_type();
|
||||
let opaque_tag_data_ptr = env
|
||||
.builder
|
||||
.build_struct_gep(arg_ptr, RocUnion::TAG_DATA_INDEX, "field_ptr")
|
||||
.new_build_struct_gep(
|
||||
union_struct_type,
|
||||
arg_ptr,
|
||||
RocUnion::TAG_DATA_INDEX,
|
||||
"field_ptr",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let cast_tag_data_pointer = env.builder.build_pointer_cast(
|
||||
opaque_tag_data_ptr,
|
||||
wrapper_type.ptr_type(AddressSpace::Generic),
|
||||
data_struct_type.ptr_type(AddressSpace::Generic),
|
||||
"cast_to_concrete_tag",
|
||||
);
|
||||
|
||||
|
@ -1638,11 +1676,20 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>(
|
|||
// This field is a pointer to the recursive pointer.
|
||||
let field_ptr = env
|
||||
.builder
|
||||
.build_struct_gep(cast_tag_data_pointer, i as u32, "modify_tag_field")
|
||||
.new_build_struct_gep(
|
||||
data_struct_type,
|
||||
cast_tag_data_pointer,
|
||||
i as u32,
|
||||
"modify_tag_field",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// This is the actual pointer to the recursive data.
|
||||
let field_value = env.builder.build_load(field_ptr, "load_recursive_pointer");
|
||||
let field_value = env.builder.new_build_load(
|
||||
env.context.i64_type().ptr_type(AddressSpace::Generic),
|
||||
field_ptr,
|
||||
"load_recursive_pointer",
|
||||
);
|
||||
|
||||
debug_assert!(field_value.is_pointer_value());
|
||||
|
||||
|
@ -1663,14 +1710,23 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>(
|
|||
} else if field_layout.contains_refcounted(env.layout_interner) {
|
||||
let field_ptr = env
|
||||
.builder
|
||||
.build_struct_gep(cast_tag_data_pointer, i as u32, "modify_tag_field")
|
||||
.new_build_struct_gep(
|
||||
data_struct_type,
|
||||
cast_tag_data_pointer,
|
||||
i as u32,
|
||||
"modify_tag_field",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let field_value =
|
||||
if field_layout.is_passed_by_reference(env.layout_interner, env.target_info) {
|
||||
field_ptr.into()
|
||||
} else {
|
||||
env.builder.build_load(field_ptr, "field_value")
|
||||
env.builder.new_build_load(
|
||||
basic_type_from_layout(env, field_layout),
|
||||
field_ptr,
|
||||
"field_value",
|
||||
)
|
||||
};
|
||||
|
||||
modify_refcount_layout_help(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue