mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 23:04:49 +00:00
Merge remote-tracking branch 'origin/trunk' into builtins-in-roc
This commit is contained in:
commit
1d0f9e9192
178 changed files with 5342 additions and 3304 deletions
|
@ -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
|
@ -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");
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue