Merge remote-tracking branch 'origin/trunk' into builtins-in-roc

This commit is contained in:
Folkert 2022-04-08 15:47:11 +02:00
commit 1d0f9e9192
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
178 changed files with 5342 additions and 3304 deletions

View file

@ -16,6 +16,8 @@ use roc_error_macros::internal_error;
use roc_module::symbol::Symbol;
use roc_mono::layout::{LambdaSet, Layout, LayoutIds, UnionLayout};
use super::build::create_entry_block_alloca;
use std::convert::TryInto;
pub fn call_bitcode_fn<'a, 'ctx, 'env>(
@ -39,15 +41,24 @@ pub fn call_list_bitcode_fn<'a, 'ctx, 'env>(
args: &[BasicValueEnum<'ctx>],
fn_name: &str,
) -> BasicValueEnum<'ctx> {
call_bitcode_fn_help(env, args, fn_name)
.try_as_basic_value()
.left()
.unwrap_or_else(|| {
panic!(
"LLVM error: Did not get return value from bitcode function {:?}",
fn_name
)
})
use bumpalo::collections::Vec;
let parent = env
.builder
.get_insert_block()
.and_then(|b| b.get_parent())
.unwrap();
let list_type = super::convert::zig_list_type(env);
let result = create_entry_block_alloca(env, parent, list_type.into(), "list_alloca");
let mut arguments: Vec<BasicValueEnum> = Vec::with_capacity_in(args.len() + 1, env.arena);
arguments.push(result.into());
arguments.extend(args);
call_void_bitcode_fn(env, &arguments, fn_name);
env.builder.build_load(result, "load_list")
}
pub fn call_str_bitcode_fn<'a, 'ctx, 'env>(
@ -55,15 +66,35 @@ pub fn call_str_bitcode_fn<'a, 'ctx, 'env>(
args: &[BasicValueEnum<'ctx>],
fn_name: &str,
) -> BasicValueEnum<'ctx> {
call_bitcode_fn_help(env, args, fn_name)
.try_as_basic_value()
.left()
.unwrap_or_else(|| {
panic!(
"LLVM error: Did not get return value from bitcode function {:?}",
fn_name
)
})
use bumpalo::collections::Vec;
let parent = env
.builder
.get_insert_block()
.and_then(|b| b.get_parent())
.unwrap();
let str_type = super::convert::zig_str_type(env);
match env.target_info.ptr_width() {
roc_target::PtrWidth::Bytes4 => {
// 3 machine words actually fit into 2 registers
call_bitcode_fn(env, args, fn_name)
}
roc_target::PtrWidth::Bytes8 => {
let result =
create_entry_block_alloca(env, parent, str_type.into(), "return_str_alloca");
let mut arguments: Vec<BasicValueEnum> =
Vec::with_capacity_in(args.len() + 1, env.arena);
arguments.push(result.into());
arguments.extend(args);
call_void_bitcode_fn(env, &arguments, fn_name);
result.into()
}
}
}
pub fn call_void_bitcode_fn<'a, 'ctx, 'env>(
@ -92,6 +123,31 @@ fn call_bitcode_fn_help<'a, 'ctx, 'env>(
let call = env.builder.build_call(fn_val, &arguments, "call_builtin");
// Attributes that we propagate from the zig builtin parameters, to the arguments we give to the
// call. It is undefined behavior in LLVM to have an attribute on a parameter, and then call
// the function where that parameter is not present. For many (e.g. nonnull) it can be inferred
// but e.g. byval and sret cannot and must be explicitly provided.
let propagate = [
Attribute::get_named_enum_kind_id("nonnull"),
Attribute::get_named_enum_kind_id("nocapture"),
Attribute::get_named_enum_kind_id("readonly"),
Attribute::get_named_enum_kind_id("noalias"),
Attribute::get_named_enum_kind_id("sret"),
Attribute::get_named_enum_kind_id("byval"),
];
for i in 0..fn_val.count_params() {
let attributes = fn_val.attributes(AttributeLoc::Param(i));
for attribute in attributes {
let kind_id = attribute.get_enum_kind_id();
if propagate.contains(&kind_id) {
call.add_attribute(AttributeLoc::Param(i), attribute)
}
}
}
call.set_call_convention(fn_val.get_call_conventions());
call
}
@ -357,7 +413,7 @@ fn build_transform_caller_help<'a, 'ctx, 'env>(
for (argument_ptr, layout) in arguments.iter().zip(argument_layouts) {
let basic_type = basic_type_from_layout(env, layout).ptr_type(AddressSpace::Generic);
let argument = if layout.is_passed_by_reference() {
let argument = if layout.is_passed_by_reference(env.target_info) {
env.builder
.build_pointer_cast(
argument_ptr.into_pointer_value(),
@ -511,7 +567,7 @@ fn build_rc_wrapper<'a, 'ctx, 'env>(
let value_type = basic_type_from_layout(env, layout).ptr_type(AddressSpace::Generic);
let value = if layout.is_passed_by_reference() {
let value = if layout.is_passed_by_reference(env.target_info) {
env.builder
.build_pointer_cast(value_ptr, value_type, "cast_ptr_to_tag_build_rc_wrapper")
.into()

File diff suppressed because it is too large Load diff

View file

@ -7,7 +7,7 @@ use crate::llvm::build::{
Scope,
};
use crate::llvm::build_list::{layout_width, pass_as_opaque};
use crate::llvm::convert::{basic_type_from_layout, zig_dict_type, zig_list_type};
use crate::llvm::convert::{basic_type_from_layout, zig_dict_type};
use crate::llvm::refcounting::Mode;
use inkwell::attributes::{Attribute, AttributeLoc};
use inkwell::context::Context;
@ -19,6 +19,10 @@ 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);
@ -103,11 +107,14 @@ pub fn dict_insert<'a, 'ctx, 'env>(
let u8_ptr = env.context.i8_type().ptr_type(AddressSpace::Generic);
let key_ptr = builder.build_alloca(key.get_type(), "key_ptr");
let value_ptr = builder.build_alloca(value.get_type(), "value_ptr");
let key_type = basic_type_from_layout(env, key_layout);
let value_type = basic_type_from_layout(env, value_layout);
env.builder.build_store(key_ptr, key);
env.builder.build_store(value_ptr, value);
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()
@ -414,8 +421,6 @@ pub fn dict_keys<'a, 'ctx, 'env>(
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);
@ -429,9 +434,7 @@ pub fn dict_keys<'a, 'ctx, 'env>(
let inc_key_fn = build_inc_wrapper(env, layout_ids, key_layout);
let list_ptr = builder.build_alloca(zig_list_type(env), "list_ptr");
call_void_bitcode_fn(
call_list_bitcode_fn(
env,
&[
pass_dict_c_abi(env, dict),
@ -439,21 +442,9 @@ pub fn dict_keys<'a, 'ctx, 'env>(
key_width.into(),
value_width.into(),
inc_key_fn.as_global_value().as_pointer_value().into(),
list_ptr.into(),
],
bitcode::DICT_KEYS,
);
let list_ptr = env
.builder
.build_bitcast(
list_ptr,
super::convert::zig_list_type(env).ptr_type(AddressSpace::Generic),
"to_roc_list",
)
.into_pointer_value();
env.builder.build_load(list_ptr, "load_keys_list")
)
}
fn pass_dict_c_abi<'a, 'ctx, 'env>(
@ -670,10 +661,6 @@ pub fn dict_values<'a, 'ctx, 'env>(
key_layout: &Layout<'a>,
value_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
let builder = env.builder;
let zig_list_type = super::convert::zig_list_type(env);
let key_width = env
.ptr_int()
.const_int(key_layout.stack_size(env.target_info) as u64, false);
@ -687,9 +674,7 @@ pub fn dict_values<'a, 'ctx, 'env>(
let inc_value_fn = build_inc_wrapper(env, layout_ids, value_layout);
let list_ptr = builder.build_alloca(zig_list_type, "list_ptr");
call_void_bitcode_fn(
call_list_bitcode_fn(
env,
&[
pass_dict_c_abi(env, dict),
@ -697,21 +682,9 @@ pub fn dict_values<'a, 'ctx, 'env>(
key_width.into(),
value_width.into(),
inc_value_fn.as_global_value().as_pointer_value().into(),
list_ptr.into(),
],
bitcode::DICT_VALUES,
);
let list_ptr = env
.builder
.build_bitcast(
list_ptr,
super::convert::zig_list_type(env).ptr_type(AddressSpace::Generic),
"to_roc_list",
)
.into_pointer_value();
env.builder.build_load(list_ptr, "load_keys_list")
)
}
#[allow(clippy::too_many_arguments)]
@ -723,15 +696,6 @@ pub fn set_from_list<'a, 'ctx, 'env>(
) -> BasicValueEnum<'ctx> {
let builder = env.builder;
let list_alloca = builder.build_alloca(list.get_type(), "list_alloca");
let list_ptr = env.builder.build_bitcast(
list_alloca,
env.str_list_c_abi().ptr_type(AddressSpace::Generic),
"to_zig_list",
);
env.builder.build_store(list_alloca, list);
let key_width = env
.ptr_int()
.const_int(key_layout.stack_size(env.target_info) as u64, false);
@ -751,8 +715,7 @@ pub fn set_from_list<'a, 'ctx, 'env>(
call_void_bitcode_fn(
env,
&[
env.builder
.build_load(list_ptr.into_pointer_value(), "as_i128"),
list_to_c_abi(env, list).into(),
alignment_iv.into(),
key_width.into(),
value_width.into(),
@ -814,7 +777,7 @@ fn build_hash_wrapper<'a, 'ctx, 'env>(
let value_cast = env
.builder
.build_bitcast(value_ptr, value_type, "load_opaque")
.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");

View file

@ -3,7 +3,6 @@ use crate::llvm::bitcode::call_bitcode_fn;
use crate::llvm::build::tag_pointer_clear_tag_id;
use crate::llvm::build::Env;
use crate::llvm::build::{get_tag_id, FAST_CALL_CONV, TAG_DATA_INDEX};
use crate::llvm::build_str;
use crate::llvm::convert::basic_type_from_layout;
use bumpalo::collections::Vec;
use inkwell::values::{
@ -13,6 +12,7 @@ use roc_builtins::bitcode;
use roc_module::symbol::Symbol;
use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout};
use super::build::use_roc_value;
use super::convert::argument_type_from_union_layout;
#[derive(Clone, Debug)]
@ -127,12 +127,7 @@ fn hash_builtin<'a, 'ctx, 'env>(
}
Builtin::Str => {
// let zig deal with big vs small string
call_bitcode_fn(
env,
&[seed.into(), build_str::str_to_c_abi(env, val).into()],
bitcode::DICT_HASH_STR,
)
.into_int_value()
call_bitcode_fn(env, &[seed.into(), val], bitcode::DICT_HASH_STR).into_int_value()
}
Builtin::Dict(_, _) => {
@ -259,9 +254,11 @@ fn hash_struct<'a, 'ctx, 'env>(
for (index, field_layout) in field_layouts.iter().enumerate() {
let field = env
.builder
.build_extract_value(value, index as u32, "eq_field")
.build_extract_value(value, index as u32, "hash_field")
.unwrap();
let field = use_roc_value(env, *field_layout, field, "store_field_for_hashing");
if let Layout::RecursivePointer = field_layout {
match &when_recursive {
WhenRecursive::Unreachable => {

View file

@ -4,7 +4,7 @@ use crate::llvm::bitcode::{
call_bitcode_fn, call_list_bitcode_fn, call_void_bitcode_fn,
};
use crate::llvm::build::{
allocate_with_refcount_help, cast_basic_basic, complex_bitcast, Env, RocFunctionCall,
allocate_with_refcount_help, cast_basic_basic, Env, RocFunctionCall, Scope,
};
use crate::llvm::convert::basic_type_from_layout;
use crate::llvm::refcounting::increment_refcount_layout;
@ -15,9 +15,48 @@ use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue, Str
use inkwell::{AddressSpace, IntPredicate};
use morphic_lib::UpdateMode;
use roc_builtins::bitcode::{self, IntWidth};
use roc_module::symbol::Symbol;
use roc_mono::layout::{Builtin, Layout, LayoutIds};
use super::build::{load_roc_value, store_roc_value};
use super::build::{create_entry_block_alloca, load_roc_value, load_symbol, store_roc_value};
pub fn list_symbol_to_c_abi<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
scope: &Scope<'a, 'ctx>,
symbol: Symbol,
) -> PointerValue<'ctx> {
let parent = env
.builder
.get_insert_block()
.and_then(|b| b.get_parent())
.unwrap();
let list_type = super::convert::zig_list_type(env);
let list_alloca = create_entry_block_alloca(env, parent, list_type.into(), "list_alloca");
let list = load_symbol(scope, &symbol);
env.builder.build_store(list_alloca, list);
list_alloca
}
pub fn list_to_c_abi<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
list: BasicValueEnum<'ctx>,
) -> PointerValue<'ctx> {
let parent = env
.builder
.get_insert_block()
.and_then(|b| b.get_parent())
.unwrap();
let list_type = super::convert::zig_list_type(env);
let list_alloca = create_entry_block_alloca(env, parent, list_type.into(), "list_alloca");
env.builder.build_store(list_alloca, list);
list_alloca
}
pub fn pass_update_mode<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
@ -47,18 +86,6 @@ fn pass_element_as_opaque<'a, 'ctx, 'env>(
)
}
fn pass_list_cc<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
list: BasicValueEnum<'ctx>,
) -> BasicValueEnum<'ctx> {
complex_bitcast(
env.builder,
list,
env.str_list_c_abi().into(),
"to_str_list_int",
)
}
pub fn layout_width<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout: &Layout<'a>,
@ -128,7 +155,7 @@ pub fn list_join<'a, 'ctx, 'env>(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, outer_list),
list_to_c_abi(env, outer_list).into(),
env.alignment_intvalue(element_layout),
layout_width(env, element_layout),
],
@ -146,7 +173,7 @@ pub fn list_reverse<'a, 'ctx, 'env>(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, list),
list_to_c_abi(env, list).into(),
env.alignment_intvalue(element_layout),
layout_width(env, element_layout),
pass_update_mode(env, update_mode),
@ -193,7 +220,7 @@ pub fn list_append<'a, 'ctx, 'env>(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, original_wrapper.into()),
list_to_c_abi(env, original_wrapper.into()).into(),
env.alignment_intvalue(element_layout),
pass_element_as_opaque(env, element, *element_layout),
layout_width(env, element_layout),
@ -213,7 +240,7 @@ pub fn list_prepend<'a, 'ctx, 'env>(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, original_wrapper.into()),
list_to_c_abi(env, original_wrapper.into()).into(),
env.alignment_intvalue(element_layout),
pass_element_as_opaque(env, element, *element_layout),
layout_width(env, element_layout),
@ -234,7 +261,7 @@ pub fn list_swap<'a, 'ctx, 'env>(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, original_wrapper.into()),
list_to_c_abi(env, original_wrapper.into()).into(),
env.alignment_intvalue(element_layout),
layout_width(env, element_layout),
index_1.into(),
@ -258,7 +285,7 @@ pub fn list_sublist<'a, 'ctx, 'env>(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, original_wrapper.into()),
list_to_c_abi(env, original_wrapper.into()).into(),
env.alignment_intvalue(element_layout),
layout_width(env, element_layout),
start.into(),
@ -281,7 +308,7 @@ pub fn list_drop_at<'a, 'ctx, 'env>(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, original_wrapper.into()),
list_to_c_abi(env, original_wrapper.into()).into(),
env.alignment_intvalue(element_layout),
layout_width(env, element_layout),
count.into(),
@ -312,7 +339,7 @@ pub fn list_replace_unsafe<'a, 'ctx, 'env>(
UpdateMode::InPlace => call_list_bitcode_fn(
env,
&[
pass_list_cc(env, list),
list_to_c_abi(env, list).into(),
index.into(),
pass_element_as_opaque(env, element, *element_layout),
layout_width(env, element_layout),
@ -323,7 +350,7 @@ pub fn list_replace_unsafe<'a, 'ctx, 'env>(
UpdateMode::Immutable => call_list_bitcode_fn(
env,
&[
pass_list_cc(env, list),
list_to_c_abi(env, list).into(),
env.alignment_intvalue(element_layout),
index.into(),
pass_element_as_opaque(env, element, *element_layout),
@ -407,7 +434,7 @@ pub fn list_walk_generic<'a, 'ctx, 'env>(
ListWalk::WalkBackwardsUntil => todo!(),
};
let default_ptr = if default_layout.is_passed_by_reference() {
let default_ptr = if default_layout.is_passed_by_reference(env.target_info) {
debug_assert!(default.is_pointer_value());
default.into_pointer_value()
} else {
@ -426,7 +453,7 @@ pub fn list_walk_generic<'a, 'ctx, 'env>(
call_void_bitcode_fn(
env,
&[
pass_list_cc(env, list),
list_to_c_abi(env, list).into(),
roc_function_call.caller.into(),
pass_as_opaque(env, roc_function_call.data),
roc_function_call.inc_n_data.into(),
@ -457,7 +484,7 @@ pub fn list_walk_generic<'a, 'ctx, 'env>(
call_void_bitcode_fn(
env,
&[
pass_list_cc(env, list),
list_to_c_abi(env, list).into(),
roc_function_call.caller.into(),
pass_as_opaque(env, roc_function_call.data),
roc_function_call.inc_n_data.into(),
@ -476,7 +503,7 @@ pub fn list_walk_generic<'a, 'ctx, 'env>(
}
}
if default_layout.is_passed_by_reference() {
if default_layout.is_passed_by_reference(env.target_info) {
result_ptr.into()
} else {
env.builder.build_load(result_ptr, "load_result")
@ -504,7 +531,7 @@ pub fn list_range<'a, 'ctx, 'env>(
.const_int(int_width as u64, false)
.into();
call_bitcode_fn(
call_list_bitcode_fn(
env,
&[
int_width,
@ -531,7 +558,7 @@ pub fn list_contains<'a, 'ctx, 'env>(
call_bitcode_fn(
env,
&[
pass_list_cc(env, list),
list_to_c_abi(env, list).into(),
pass_element_as_opaque(env, element, *element_layout),
layout_width(env, element_layout),
eq_fn,
@ -554,7 +581,7 @@ pub fn list_keep_if<'a, 'ctx, 'env>(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, list),
list_to_c_abi(env, list).into(),
roc_function_call.caller.into(),
pass_as_opaque(env, roc_function_call.data),
roc_function_call.inc_n_data.into(),
@ -605,10 +632,10 @@ pub fn list_keep_oks<'a, 'ctx, 'env>(
_ => unreachable!(),
};
call_bitcode_fn(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, list),
list_to_c_abi(env, list).into(),
roc_function_call.caller.into(),
pass_as_opaque(env, roc_function_call.data),
roc_function_call.inc_n_data.into(),
@ -653,10 +680,10 @@ pub fn list_keep_errs<'a, 'ctx, 'env>(
_ => unreachable!(),
};
call_bitcode_fn(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, list),
list_to_c_abi(env, list).into(),
roc_function_call.caller.into(),
pass_as_opaque(env, roc_function_call.data),
roc_function_call.inc_n_data.into(),
@ -683,7 +710,7 @@ pub fn list_sort_with<'a, 'ctx, 'env>(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, list),
list_to_c_abi(env, list).into(),
compare_wrapper.into(),
pass_as_opaque(env, roc_function_call.data),
roc_function_call.inc_n_data.into(),
@ -706,7 +733,7 @@ pub fn list_map_with_index<'a, 'ctx, 'env>(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, list),
list_to_c_abi(env, list).into(),
roc_function_call.caller.into(),
pass_as_opaque(env, roc_function_call.data),
roc_function_call.inc_n_data.into(),
@ -730,7 +757,7 @@ pub fn list_map<'a, 'ctx, 'env>(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, list),
list_to_c_abi(env, list).into(),
roc_function_call.caller.into(),
pass_as_opaque(env, roc_function_call.data),
roc_function_call.inc_n_data.into(),
@ -756,11 +783,11 @@ pub fn list_map2<'a, 'ctx, 'env>(
let dec_a = build_dec_wrapper(env, layout_ids, element1_layout);
let dec_b = build_dec_wrapper(env, layout_ids, element2_layout);
call_bitcode_fn(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, list1),
pass_list_cc(env, list2),
list_to_c_abi(env, list1).into(),
list_to_c_abi(env, list2).into(),
roc_function_call.caller.into(),
pass_as_opaque(env, roc_function_call.data),
roc_function_call.inc_n_data.into(),
@ -795,9 +822,9 @@ pub fn list_map3<'a, 'ctx, 'env>(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, list1),
pass_list_cc(env, list2),
pass_list_cc(env, list3),
list_to_c_abi(env, list1).into(),
list_to_c_abi(env, list2).into(),
list_to_c_abi(env, list3).into(),
roc_function_call.caller.into(),
pass_as_opaque(env, roc_function_call.data),
roc_function_call.inc_n_data.into(),
@ -837,10 +864,10 @@ pub fn list_map4<'a, 'ctx, 'env>(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, list1),
pass_list_cc(env, list2),
pass_list_cc(env, list3),
pass_list_cc(env, list4),
list_to_c_abi(env, list1).into(),
list_to_c_abi(env, list2).into(),
list_to_c_abi(env, list3).into(),
list_to_c_abi(env, list4).into(),
roc_function_call.caller.into(),
pass_as_opaque(env, roc_function_call.data),
roc_function_call.inc_n_data.into(),
@ -870,8 +897,8 @@ pub fn list_concat<'a, 'ctx, 'env>(
call_list_bitcode_fn(
env,
&[
pass_list_cc(env, first_list),
pass_list_cc(env, second_list),
list_to_c_abi(env, first_list).into(),
list_to_c_abi(env, second_list).into(),
env.alignment_intvalue(element_layout),
layout_width(env, element_layout),
],
@ -889,7 +916,7 @@ pub fn list_any<'a, 'ctx, 'env>(
call_bitcode_fn(
env,
&[
pass_list_cc(env, list),
list_to_c_abi(env, list).into(),
roc_function_call.caller.into(),
pass_as_opaque(env, roc_function_call.data),
roc_function_call.inc_n_data.into(),
@ -910,7 +937,7 @@ pub fn list_all<'a, 'ctx, 'env>(
call_bitcode_fn(
env,
&[
pass_list_cc(env, list),
list_to_c_abi(env, list).into(),
roc_function_call.caller.into(),
pass_as_opaque(env, roc_function_call.data),
roc_function_call.inc_n_data.into(),
@ -936,7 +963,7 @@ pub fn list_find_unsafe<'a, 'ctx, 'env>(
let result = call_bitcode_fn(
env,
&[
pass_list_cc(env, list),
list_to_c_abi(env, list).into(),
roc_function_call.caller.into(),
pass_as_opaque(env, roc_function_call.data),
roc_function_call.inc_n_data.into(),
@ -1259,7 +1286,6 @@ pub fn allocate_list<'a, 'ctx, 'env>(
number_of_elements: IntValue<'ctx>,
) -> PointerValue<'ctx> {
let builder = env.builder;
let ctx = env.context;
let len_type = env.ptr_int();
let elem_bytes = elem_layout.stack_size(env.target_info) as u64;
@ -1267,13 +1293,9 @@ pub fn allocate_list<'a, 'ctx, 'env>(
let number_of_data_bytes =
builder.build_int_mul(bytes_per_element, number_of_elements, "data_length");
// the refcount of a new list is initially 1
// we assume that the list is indeed used (dead variables are eliminated)
let rc1 = crate::llvm::refcounting::refcount_1(ctx, env.target_info);
let basic_type = basic_type_from_layout(env, elem_layout);
let alignment_bytes = elem_layout.alignment_bytes(env.target_info);
allocate_with_refcount_help(env, basic_type, alignment_bytes, number_of_data_bytes, rc1)
allocate_with_refcount_help(env, basic_type, alignment_bytes, number_of_data_bytes)
}
pub fn store_list<'a, 'ctx, 'env>(
@ -1285,10 +1307,8 @@ pub fn store_list<'a, 'ctx, 'env>(
let struct_type = super::convert::zig_list_type(env);
let mut struct_val;
// Store the pointer
struct_val = builder
let mut struct_val = builder
.build_insert_value(
struct_type.get_undef(),
pass_as_opaque(env, pointer_to_first_element),

View file

@ -1,10 +1,8 @@
use crate::llvm::bitcode::{
call_bitcode_fn, call_list_bitcode_fn, call_str_bitcode_fn, call_void_bitcode_fn,
};
use crate::llvm::bitcode::{call_bitcode_fn, call_str_bitcode_fn, call_void_bitcode_fn};
use crate::llvm::build::{complex_bitcast, Env, Scope};
use crate::llvm::build_list::{allocate_list, pass_update_mode, store_list};
use inkwell::builder::Builder;
use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue, StructValue};
use inkwell::values::{BasicValueEnum, IntValue, PointerValue, StructValue};
use inkwell::AddressSpace;
use morphic_lib::UpdateMode;
use roc_builtins::bitcode::{self, IntWidth};
@ -12,22 +10,11 @@ use roc_module::symbol::Symbol;
use roc_mono::layout::{Builtin, Layout};
use roc_target::PtrWidth;
use super::build::load_symbol;
use super::build::{create_entry_block_alloca, load_symbol};
use super::build_list::list_symbol_to_c_abi;
pub static CHAR_LAYOUT: Layout = Layout::u8();
/// Str.repeat : Str, Nat -> Str
pub fn str_repeat<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
scope: &Scope<'a, 'ctx>,
str_symbol: Symbol,
count_symbol: Symbol,
) -> BasicValueEnum<'ctx> {
let str_c_abi = str_symbol_to_c_abi(env, scope, str_symbol);
let count = load_symbol(scope, &count_symbol);
call_str_bitcode_fn(env, &[str_c_abi.into(), count], bitcode::STR_REPEAT)
}
/// Str.split : Str, Str -> List Str
pub fn str_split<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
@ -37,15 +24,11 @@ pub fn str_split<'a, 'ctx, 'env>(
) -> BasicValueEnum<'ctx> {
let builder = env.builder;
let str_c_abi = str_symbol_to_c_abi(env, scope, str_symbol);
let delim_c_abi = str_symbol_to_c_abi(env, scope, delimiter_symbol);
let string = load_symbol(scope, &str_symbol);
let delimiter = load_symbol(scope, &delimiter_symbol);
let segment_count = call_list_bitcode_fn(
env,
&[str_c_abi.into(), delim_c_abi.into()],
bitcode::STR_COUNT_SEGMENTS,
)
.into_int_value();
let segment_count =
call_bitcode_fn(env, &[string, delimiter], bitcode::STR_COUNT_SEGMENTS).into_int_value();
// a pointer to the elements
let ret_list_ptr = allocate_list(env, &Layout::Builtin(Builtin::Str), segment_count);
@ -62,53 +45,39 @@ pub fn str_split<'a, 'ctx, 'env>(
call_void_bitcode_fn(
env,
&[
ret_list_ptr_zig_rocstr,
str_c_abi.into(),
delim_c_abi.into(),
],
&[ret_list_ptr_zig_rocstr, string, delimiter],
bitcode::STR_STR_SPLIT_IN_PLACE,
);
store_list(env, ret_list_ptr, segment_count)
}
fn str_symbol_to_c_abi<'a, 'ctx, 'env>(
pub fn str_symbol_to_c_abi<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
scope: &Scope<'a, 'ctx>,
symbol: Symbol,
) -> IntValue<'ctx> {
) -> PointerValue<'ctx> {
let string = load_symbol(scope, &symbol);
let target_type = match env.target_info.ptr_width() {
PtrWidth::Bytes8 => env.context.i128_type().into(),
PtrWidth::Bytes4 => env.context.i64_type().into(),
};
complex_bitcast(env.builder, string, target_type, "str_to_c_abi").into_int_value()
str_to_c_abi(env, string)
}
pub fn str_to_c_abi<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
value: BasicValueEnum<'ctx>,
) -> IntValue<'ctx> {
let cell = env.builder.build_alloca(value.get_type(), "cell");
env.builder.build_store(cell, value);
let target_type = match env.target_info.ptr_width() {
PtrWidth::Bytes8 => env.context.i128_type(),
PtrWidth::Bytes4 => env.context.i64_type(),
};
let target_type_ptr = env
) -> PointerValue<'ctx> {
let parent = env
.builder
.build_bitcast(cell, target_type.ptr_type(AddressSpace::Generic), "cast")
.into_pointer_value();
.get_insert_block()
.and_then(|b| b.get_parent())
.unwrap();
env.builder
.build_load(target_type_ptr, "load_as_c_abi")
.into_int_value()
let str_type = super::convert::zig_str_type(env);
let string_alloca = create_entry_block_alloca(env, parent, str_type.into(), "str_alloca");
env.builder.build_store(string_alloca, value);
string_alloca
}
pub fn destructure<'ctx>(
@ -129,155 +98,6 @@ pub fn destructure<'ctx>(
(generic_ptr, length)
}
/// Str.concat : Str, Str -> Str
pub fn str_concat<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
scope: &Scope<'a, 'ctx>,
str1_symbol: Symbol,
str2_symbol: Symbol,
) -> BasicValueEnum<'ctx> {
// swap the arguments; second argument comes before the second in the output string
let str1_c_abi = str_symbol_to_c_abi(env, scope, str1_symbol);
let str2_c_abi = str_symbol_to_c_abi(env, scope, str2_symbol);
call_str_bitcode_fn(
env,
&[str1_c_abi.into(), str2_c_abi.into()],
bitcode::STR_CONCAT,
)
}
/// Str.join : List Str, Str -> Str
pub fn str_join_with<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
scope: &Scope<'a, 'ctx>,
list_symbol: Symbol,
str_symbol: Symbol,
) -> BasicValueEnum<'ctx> {
// dirty hack; pretend a `list` is a `str` that works because
// they have the same stack layout `{ u8*, usize }`
let list_i128 = str_symbol_to_c_abi(env, scope, list_symbol);
let str_i128 = str_symbol_to_c_abi(env, scope, str_symbol);
call_str_bitcode_fn(
env,
&[list_i128.into(), str_i128.into()],
bitcode::STR_JOIN_WITH,
)
}
pub fn str_number_of_bytes<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
scope: &Scope<'a, 'ctx>,
str_symbol: Symbol,
) -> IntValue<'ctx> {
let str_i128 = str_symbol_to_c_abi(env, scope, str_symbol);
// the builtin will always return an u64
let length =
call_bitcode_fn(env, &[str_i128.into()], bitcode::STR_NUMBER_OF_BYTES).into_int_value();
// cast to the appropriate usize of the current build
env.builder
.build_int_cast_sign_flag(length, env.ptr_int(), false, "len_as_usize")
}
/// Str.startsWith : Str, Str -> Bool
pub fn str_starts_with<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
scope: &Scope<'a, 'ctx>,
str_symbol: Symbol,
prefix_symbol: Symbol,
) -> BasicValueEnum<'ctx> {
let str_i128 = str_symbol_to_c_abi(env, scope, str_symbol);
let prefix_i128 = str_symbol_to_c_abi(env, scope, prefix_symbol);
call_bitcode_fn(
env,
&[str_i128.into(), prefix_i128.into()],
bitcode::STR_STARTS_WITH,
)
}
/// Str.startsWithCodePt : Str, U32 -> Bool
pub fn str_starts_with_code_point<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
scope: &Scope<'a, 'ctx>,
str_symbol: Symbol,
prefix_symbol: Symbol,
) -> BasicValueEnum<'ctx> {
let str_i128 = str_symbol_to_c_abi(env, scope, str_symbol);
let prefix = load_symbol(scope, &prefix_symbol);
call_bitcode_fn(
env,
&[str_i128.into(), prefix],
bitcode::STR_STARTS_WITH_CODE_PT,
)
}
/// Str.endsWith : Str, Str -> Bool
pub fn str_ends_with<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
scope: &Scope<'a, 'ctx>,
str_symbol: Symbol,
prefix_symbol: Symbol,
) -> BasicValueEnum<'ctx> {
let str_i128 = str_symbol_to_c_abi(env, scope, str_symbol);
let prefix_i128 = str_symbol_to_c_abi(env, scope, prefix_symbol);
call_bitcode_fn(
env,
&[str_i128.into(), prefix_i128.into()],
bitcode::STR_ENDS_WITH,
)
}
/// Str.countGraphemes : Str -> Int
pub fn str_count_graphemes<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
scope: &Scope<'a, 'ctx>,
str_symbol: Symbol,
) -> BasicValueEnum<'ctx> {
let str_i128 = str_symbol_to_c_abi(env, scope, str_symbol);
call_bitcode_fn(
env,
&[str_i128.into()],
bitcode::STR_COUNT_GRAPEHEME_CLUSTERS,
)
}
/// Str.trim : Str -> Str
pub fn str_trim<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
scope: &Scope<'a, 'ctx>,
str_symbol: Symbol,
) -> BasicValueEnum<'ctx> {
let str_i128 = str_symbol_to_c_abi(env, scope, str_symbol);
call_str_bitcode_fn(env, &[str_i128.into()], bitcode::STR_TRIM)
}
/// Str.trimLeft : Str -> Str
pub fn str_trim_left<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
scope: &Scope<'a, 'ctx>,
str_symbol: Symbol,
) -> BasicValueEnum<'ctx> {
let str_i128 = str_symbol_to_c_abi(env, scope, str_symbol);
call_str_bitcode_fn(env, &[str_i128.into()], bitcode::STR_TRIM_LEFT)
}
/// Str.trimRight : Str -> Str
pub fn str_trim_right<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
scope: &Scope<'a, 'ctx>,
str_symbol: Symbol,
) -> BasicValueEnum<'ctx> {
let str_i128 = str_symbol_to_c_abi(env, scope, str_symbol);
call_str_bitcode_fn(env, &[str_i128.into()], bitcode::STR_TRIM_RIGHT)
}
/// Str.fromInt : Int -> Str
pub fn str_from_int<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
@ -287,21 +107,6 @@ pub fn str_from_int<'a, 'ctx, 'env>(
call_str_bitcode_fn(env, &[value.into()], &bitcode::STR_FROM_INT[int_width])
}
/// Str.toUtf8 : Str -> List U8
pub fn str_to_utf8<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
original_wrapper: StructValue<'ctx>,
) -> BasicValueEnum<'ctx> {
let string = complex_bitcast(
env.builder,
original_wrapper.into(),
env.str_list_c_abi().into(),
"to_utf8",
);
call_list_bitcode_fn(env, &[string], bitcode::STR_TO_UTF8)
}
fn decode_from_utf8_result<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
pointer: PointerValue<'ctx>,
@ -341,8 +146,8 @@ fn decode_from_utf8_result<'a, 'ctx, 'env>(
/// Str.fromUtf8 : List U8, { count : Nat, start : Nat } -> { a : Bool, b : Str, c : Nat, d : I8 }
pub fn str_from_utf8_range<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
_parent: FunctionValue<'ctx>,
list_wrapper: StructValue<'ctx>,
scope: &Scope<'a, 'ctx>,
list: Symbol,
count_and_start: StructValue<'ctx>,
) -> BasicValueEnum<'ctx> {
let builder = env.builder;
@ -353,16 +158,11 @@ pub fn str_from_utf8_range<'a, 'ctx, 'env>(
call_void_bitcode_fn(
env,
&[
complex_bitcast(
env.builder,
list_wrapper.into(),
env.str_list_c_abi().into(),
"to_i128",
),
list_symbol_to_c_abi(env, scope, list).into(),
complex_bitcast(
env.builder,
count_and_start.into(),
env.str_list_c_abi().into(),
env.twice_ptr_int().into(),
"to_i128",
),
result_ptr.into(),
@ -376,8 +176,8 @@ pub fn str_from_utf8_range<'a, 'ctx, 'env>(
/// Str.fromUtf8 : List U8 -> { a : Bool, b : Str, c : Nat, d : I8 }
pub fn str_from_utf8<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
_parent: FunctionValue<'ctx>,
original_wrapper: StructValue<'ctx>,
scope: &Scope<'a, 'ctx>,
list: Symbol,
update_mode: UpdateMode,
) -> BasicValueEnum<'ctx> {
let builder = env.builder;
@ -388,12 +188,7 @@ pub fn str_from_utf8<'a, 'ctx, 'env>(
call_void_bitcode_fn(
env,
&[
complex_bitcast(
env.builder,
original_wrapper.into(),
env.str_list_c_abi().into(),
"to_i128",
),
list_symbol_to_c_abi(env, scope, list).into(),
pass_update_mode(env, update_mode),
result_ptr.into(),
],
@ -420,12 +215,5 @@ pub fn str_equal<'a, 'ctx, 'env>(
value1: BasicValueEnum<'ctx>,
value2: BasicValueEnum<'ctx>,
) -> BasicValueEnum<'ctx> {
let str1_i128 = str_to_c_abi(env, value1);
let str2_i128 = str_to_c_abi(env, value2);
call_bitcode_fn(
env,
&[str1_i128.into(), str2_i128.into()],
bitcode::STR_EQUAL,
)
call_bitcode_fn(env, &[value1, value2], bitcode::STR_EQUAL)
}

View file

@ -14,7 +14,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 super::build::{load_roc_value, use_roc_value};
use super::convert::argument_type_from_union_layout;
#[derive(Clone, Debug)]
@ -755,8 +755,8 @@ fn build_struct_eq_help<'a, 'ctx, 'env>(
build_eq(
env,
layout_ids,
field1,
field2,
use_roc_value(env, *field_layout, field1, "field1"),
use_roc_value(env, *field_layout, field2, "field2"),
field_layout,
field_layout,
when_recursive.clone(),

View file

@ -132,6 +132,15 @@ pub fn argument_type_from_layout<'a, 'ctx, 'env>(
argument_type_from_layout(env, &lambda_set.runtime_representation())
}
Union(union_layout) => argument_type_from_union_layout(env, union_layout),
Builtin(_) => {
let base = basic_type_from_layout(env, layout);
if layout.is_passed_by_reference(env.target_info) {
base.ptr_type(AddressSpace::Generic).into()
} else {
base
}
}
other => basic_type_from_layout(env, other),
}
}

View file

@ -8,7 +8,6 @@ use crate::llvm::build_list::{incrementing_elem_loop, list_len, load_list};
use crate::llvm::convert::basic_type_from_layout;
use bumpalo::collections::Vec;
use inkwell::basic_block::BasicBlock;
use inkwell::context::Context;
use inkwell::module::Linkage;
use inkwell::types::{AnyTypeEnum, BasicMetadataTypeEnum, BasicType, BasicTypeEnum};
use inkwell::values::{
@ -18,20 +17,9 @@ use inkwell::{AddressSpace, IntPredicate};
use roc_module::symbol::Interns;
use roc_module::symbol::Symbol;
use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout};
use roc_target::TargetInfo;
use super::convert::argument_type_from_union_layout;
/// "Infinite" reference count, for static values
/// Ref counts are encoded as negative numbers where isize::MIN represents 1
pub const REFCOUNT_MAX: usize = 0_usize;
pub fn refcount_1(ctx: &Context, target_info: TargetInfo) -> IntValue<'_> {
match target_info.ptr_width() {
roc_target::PtrWidth::Bytes4 => ctx.i32_type().const_int(i32::MIN as u64, false),
roc_target::PtrWidth::Bytes8 => ctx.i64_type().const_int(i64::MIN as u64, false),
}
}
use super::build::load_roc_value;
use super::convert::{argument_type_from_layout, argument_type_from_union_layout};
pub struct PointerToRefcount<'ctx> {
value: PointerValue<'ctx>,
@ -95,7 +83,14 @@ impl<'ctx> PointerToRefcount<'ctx> {
pub fn is_1<'a, 'env>(&self, env: &Env<'a, 'ctx, 'env>) -> IntValue<'ctx> {
let current = self.get_refcount(env);
let one = refcount_1(env.context, env.target_info);
let one = match env.target_info.ptr_width() {
roc_target::PtrWidth::Bytes4 => {
env.context.i32_type().const_int(i32::MIN as u64, false)
}
roc_target::PtrWidth::Bytes8 => {
env.context.i64_type().const_int(i64::MIN as u64, false)
}
};
env.builder
.build_int_compare(IntPredicate::EQ, current, one, "is_one")
@ -124,38 +119,7 @@ impl<'ctx> PointerToRefcount<'ctx> {
}
fn increment<'a, 'env>(&self, amount: IntValue<'ctx>, env: &Env<'a, 'ctx, 'env>) {
let refcount = self.get_refcount(env);
let builder = env.builder;
let refcount_type = env.ptr_int();
let is_static_allocation = builder.build_int_compare(
IntPredicate::EQ,
refcount,
refcount_type.const_int(REFCOUNT_MAX as u64, false),
"refcount_max_check",
);
let block = env.builder.get_insert_block().expect("to be in a function");
let parent = block.get_parent().unwrap();
let modify_block = env
.context
.append_basic_block(parent, "inc_refcount_modify");
let cont_block = env.context.append_basic_block(parent, "inc_refcount_cont");
env.builder
.build_conditional_branch(is_static_allocation, cont_block, modify_block);
{
env.builder.position_at_end(modify_block);
let incremented = builder.build_int_add(refcount, amount, "increment_refcount");
self.set_refcount(env, incremented);
env.builder.build_unconditional_branch(cont_block);
}
env.builder.position_at_end(cont_block);
incref_pointer(env, self.value, amount);
}
pub fn decrement<'a, 'env>(&self, env: &Env<'a, 'ctx, 'env>, layout: &Layout<'a>) {
@ -231,6 +195,25 @@ impl<'ctx> PointerToRefcount<'ctx> {
}
}
fn incref_pointer<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
pointer: PointerValue<'ctx>,
amount: IntValue<'ctx>,
) {
call_void_bitcode_fn(
env,
&[
env.builder.build_bitcast(
pointer,
env.ptr_int().ptr_type(AddressSpace::Generic),
"to_isize_ptr",
),
amount.into(),
],
roc_builtins::bitcode::UTILS_INCREF,
);
}
fn decref_pointer<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
pointer: PointerValue<'ctx>,
@ -687,7 +670,7 @@ fn modify_refcount_list<'a, 'ctx, 'env>(
let function = match env.module.get_function(fn_name.as_str()) {
Some(function_value) => function_value,
None => {
let basic_type = basic_type_from_layout(env, layout);
let basic_type = argument_type_from_layout(env, layout);
let function_value = build_header(env, basic_type, mode, &fn_name);
modify_refcount_list_help(
@ -824,7 +807,7 @@ fn modify_refcount_str<'a, 'ctx, 'env>(
let function = match env.module.get_function(fn_name.as_str()) {
Some(function_value) => function_value,
None => {
let basic_type = basic_type_from_layout(env, layout);
let basic_type = argument_type_from_layout(env, layout);
let function_value = build_header(env, basic_type, mode, &fn_name);
modify_refcount_str_help(env, mode, layout, function_value);
@ -864,17 +847,26 @@ fn modify_refcount_str_help<'a, 'ctx, 'env>(
let parent = fn_val;
let arg_val = if Layout::Builtin(Builtin::Str).is_passed_by_reference(env.target_info) {
env.builder
.build_load(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());
arg_val
};
let str_wrapper = arg_val.into_struct_value();
let len = builder
.build_extract_value(str_wrapper, Builtin::WRAPPER_LEN, "read_str_ptr")
let capacity = builder
.build_extract_value(str_wrapper, Builtin::WRAPPER_CAPACITY, "read_str_capacity")
.unwrap()
.into_int_value();
// Small strings have 1 as the first bit of length, making them negative.
// Small strings have 1 as the first bit of capacity, making them negative.
// Thus, to check for big and non empty, just needs a signed len > 0.
let is_big_and_non_empty = builder.build_int_compare(
IntPredicate::SGT,
len,
capacity,
env.ptr_int().const_zero(),
"is_big_str",
);
@ -1434,9 +1426,8 @@ fn build_rec_union_recursive_decrement<'a, 'ctx, 'env>(
.build_struct_gep(struct_ptr, i as u32, "gep_recursive_pointer")
.unwrap();
let field = env
.builder
.build_load(elem_pointer, "decrement_struct_field");
let field =
load_roc_value(env, *field_layout, elem_pointer, "decrement_struct_field");
deferred_nonrec.push((field, field_layout));
}
@ -1825,7 +1816,7 @@ fn modify_refcount_union_help<'a, 'ctx, 'env>(
.build_struct_gep(cast_tag_data_pointer, i as u32, "modify_tag_field")
.unwrap();
let field_value = if field_layout.is_passed_by_reference() {
let field_value = if field_layout.is_passed_by_reference(env.target_info) {
field_ptr.into()
} else {
env.builder.build_load(field_ptr, "field_value")