Merge remote-tracking branch 'origin/trunk' into roc_alloc

This commit is contained in:
Richard Feldman 2021-05-24 20:05:12 -04:00
commit 7d7588ca19
41 changed files with 4658 additions and 2767 deletions

View file

@ -1,10 +1,10 @@
#![allow(clippy::too_many_arguments)]
use crate::llvm::bitcode::{
build_compare_wrapper, build_dec_wrapper, build_eq_wrapper, build_inc_n_wrapper,
build_inc_wrapper, build_transform_caller, call_bitcode_fn, call_void_bitcode_fn,
build_dec_wrapper, build_eq_wrapper, build_inc_n_wrapper, build_inc_wrapper,
build_transform_caller, call_bitcode_fn, call_void_bitcode_fn,
};
use crate::llvm::build::{
allocate_with_refcount_help, cast_basic_basic, complex_bitcast, Env, InPlace,
allocate_with_refcount_help, cast_basic_basic, complex_bitcast, Env, InPlace, RocFunctionCall,
};
use crate::llvm::convert::{basic_type_from_layout, get_ptr_type};
use crate::llvm::refcounting::{
@ -72,7 +72,7 @@ fn pass_list_as_i128<'a, 'ctx, 'env>(
complex_bitcast(env.builder, list, env.context.i128_type().into(), "to_i128")
}
fn layout_width<'a, 'ctx, 'env>(
pub fn layout_width<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
@ -81,7 +81,7 @@ fn layout_width<'a, 'ctx, 'env>(
.into()
}
fn pass_as_opaque<'a, 'ctx, 'env>(
pub fn pass_as_opaque<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
ptr: PointerValue<'ctx>,
) -> BasicValueEnum<'ctx> {
@ -466,50 +466,12 @@ pub enum ListWalk {
WalkBackwardsUntil,
}
pub fn list_walk_help<'a, 'ctx, 'env>(
pub fn list_walk_generic<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>,
scope: &crate::llvm::build::Scope<'a, 'ctx>,
parent: FunctionValue<'ctx>,
args: &[roc_module::symbol::Symbol],
variant: ListWalk,
) -> BasicValueEnum<'ctx> {
use crate::llvm::build::load_symbol_and_layout;
debug_assert_eq!(args.len(), 3);
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
let (func, func_layout) = load_symbol_and_layout(scope, &args[1]);
let (default, default_layout) = load_symbol_and_layout(scope, &args[2]);
match list_layout {
Layout::Builtin(Builtin::EmptyList) => default,
Layout::Builtin(Builtin::List(_, element_layout)) => list_walk_generic(
env,
layout_ids,
parent,
list,
element_layout,
func,
func_layout,
default,
default_layout,
variant,
),
_ => unreachable!("invalid list layout"),
}
}
fn list_walk_generic<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>,
_parent: FunctionValue<'ctx>,
roc_function_call: RocFunctionCall<'ctx>,
list: BasicValueEnum<'ctx>,
element_layout: &Layout<'a>,
func: BasicValueEnum<'ctx>,
func_layout: &Layout<'a>,
default: BasicValueEnum<'ctx>,
default_layout: &Layout<'a>,
variant: ListWalk,
@ -523,21 +485,9 @@ fn list_walk_generic<'a, 'ctx, 'env>(
ListWalk::WalkBackwardsUntil => todo!(),
};
let transform_ptr = builder.build_alloca(func.get_type(), "transform_ptr");
env.builder.build_store(transform_ptr, func);
let default_ptr = builder.build_alloca(default.get_type(), "default_ptr");
env.builder.build_store(default_ptr, default);
let stepper_caller = build_transform_caller(
env,
layout_ids,
func_layout,
&[*element_layout, *default_layout],
)
.as_global_value()
.as_pointer_value();
let result_ptr = env.builder.build_alloca(default.get_type(), "result");
match variant {
@ -546,8 +496,10 @@ fn list_walk_generic<'a, 'ctx, 'env>(
env,
&[
pass_list_as_i128(env, list),
pass_as_opaque(env, transform_ptr),
stepper_caller.into(),
roc_function_call.caller.into(),
pass_as_opaque(env, roc_function_call.data),
roc_function_call.inc_n_data.into(),
roc_function_call.data_is_owned.into(),
pass_as_opaque(env, default_ptr),
alignment_intvalue(env, &element_layout),
layout_width(env, element_layout),
@ -563,8 +515,10 @@ fn list_walk_generic<'a, 'ctx, 'env>(
env,
&[
pass_list_as_i128(env, list),
pass_as_opaque(env, transform_ptr),
stepper_caller.into(),
roc_function_call.caller.into(),
pass_as_opaque(env, roc_function_call.data),
roc_function_call.inc_n_data.into(),
roc_function_call.data_is_owned.into(),
pass_as_opaque(env, default_ptr),
alignment_intvalue(env, &element_layout),
layout_width(env, element_layout),
@ -673,21 +627,10 @@ pub fn list_contains<'a, 'ctx, 'env>(
pub fn list_keep_if<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>,
transform: BasicValueEnum<'ctx>,
transform_layout: &Layout<'a>,
roc_function_call: RocFunctionCall<'ctx>,
list: BasicValueEnum<'ctx>,
element_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
let builder = env.builder;
let transform_ptr = builder.build_alloca(transform.get_type(), "transform_ptr");
env.builder.build_store(transform_ptr, transform);
let stepper_caller =
build_transform_caller(env, layout_ids, transform_layout, &[*element_layout])
.as_global_value()
.as_pointer_value();
let inc_element_fn = build_inc_wrapper(env, layout_ids, element_layout);
let dec_element_fn = build_dec_wrapper(env, layout_ids, element_layout);
@ -695,8 +638,10 @@ pub fn list_keep_if<'a, 'ctx, 'env>(
env,
&[
pass_list_as_i128(env, list),
pass_as_opaque(env, transform_ptr),
stepper_caller.into(),
roc_function_call.caller.into(),
pass_as_opaque(env, roc_function_call.data),
roc_function_call.inc_n_data.into(),
roc_function_call.data_is_owned.into(),
alignment_intvalue(env, &element_layout),
layout_width(env, element_layout),
inc_element_fn.as_global_value().as_pointer_value().into(),
@ -710,20 +655,35 @@ pub fn list_keep_if<'a, 'ctx, 'env>(
pub fn list_keep_oks<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>,
transform: BasicValueEnum<'ctx>,
transform_layout: &Layout<'a>,
roc_function_call: RocFunctionCall<'ctx>,
function_layout: &Layout<'a>,
list: BasicValueEnum<'ctx>,
before_layout: &Layout<'a>,
after_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
list_keep_result(
// Layout of the `Result after *`
let result_layout = match function_layout {
Layout::FunctionPointer(_, ret) => ret,
Layout::Closure(_, _, ret) => ret,
_ => unreachable!("not a callable layout"),
};
let dec_result_fn = build_dec_wrapper(env, layout_ids, result_layout);
call_bitcode_fn(
env,
layout_ids,
transform,
transform_layout,
list,
before_layout,
after_layout,
&[
pass_list_as_i128(env, list),
roc_function_call.caller.into(),
pass_as_opaque(env, roc_function_call.data),
roc_function_call.inc_n_data.into(),
roc_function_call.data_is_owned.into(),
alignment_intvalue(env, &before_layout),
layout_width(env, before_layout),
layout_width(env, result_layout),
layout_width(env, after_layout),
dec_result_fn.as_global_value().as_pointer_value().into(),
],
bitcode::LIST_KEEP_OKS,
)
}
@ -732,20 +692,35 @@ pub fn list_keep_oks<'a, 'ctx, 'env>(
pub fn list_keep_errs<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>,
transform: BasicValueEnum<'ctx>,
transform_layout: &Layout<'a>,
roc_function_call: RocFunctionCall<'ctx>,
function_layout: &Layout<'a>,
list: BasicValueEnum<'ctx>,
before_layout: &Layout<'a>,
after_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
list_keep_result(
// Layout of the `Result after *`
let result_layout = match function_layout {
Layout::FunctionPointer(_, ret) => ret,
Layout::Closure(_, _, ret) => ret,
_ => unreachable!("not a callable layout"),
};
let dec_result_fn = build_dec_wrapper(env, layout_ids, result_layout);
call_bitcode_fn(
env,
layout_ids,
transform,
transform_layout,
list,
before_layout,
after_layout,
&[
pass_list_as_i128(env, list),
roc_function_call.caller.into(),
pass_as_opaque(env, roc_function_call.data),
roc_function_call.inc_n_data.into(),
roc_function_call.data_is_owned.into(),
alignment_intvalue(env, &before_layout),
layout_width(env, before_layout),
layout_width(env, result_layout),
layout_width(env, after_layout),
dec_result_fn.as_global_value().as_pointer_value().into(),
],
bitcode::LIST_KEEP_ERRS,
)
}
@ -753,8 +728,10 @@ pub fn list_keep_errs<'a, 'ctx, 'env>(
pub fn list_keep_result<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>,
transform: BasicValueEnum<'ctx>,
transform_layout: &Layout<'a>,
transform: FunctionValue<'ctx>,
transform_layout: Layout<'a>,
closure_data: BasicValueEnum<'ctx>,
closure_data_layout: Layout<'a>,
list: BasicValueEnum<'ctx>,
before_layout: &Layout<'a>,
after_layout: &Layout<'a>,
@ -768,39 +745,27 @@ pub fn list_keep_result<'a, 'ctx, 'env>(
_ => unreachable!("not a callable layout"),
};
let transform_ptr = builder.build_alloca(transform.get_type(), "transform_ptr");
env.builder.build_store(transform_ptr, transform);
let closure_data_ptr = builder.build_alloca(closure_data.get_type(), "closure_data_ptr");
env.builder.build_store(closure_data_ptr, closure_data);
let stepper_caller =
build_transform_caller(env, layout_ids, transform_layout, &[*before_layout])
build_transform_caller(env, transform, closure_data_layout, &[*before_layout])
.as_global_value()
.as_pointer_value();
let before_width = env
.ptr_int()
.const_int(before_layout.stack_size(env.ptr_bytes) as u64, false);
let after_width = env
.ptr_int()
.const_int(after_layout.stack_size(env.ptr_bytes) as u64, false);
let result_width = env
.ptr_int()
.const_int(result_layout.stack_size(env.ptr_bytes) as u64, false);
let inc_closure = build_inc_wrapper(env, layout_ids, transform_layout);
let inc_closure = build_inc_wrapper(env, layout_ids, &transform_layout);
let dec_result_fn = build_dec_wrapper(env, layout_ids, result_layout);
call_bitcode_fn(
env,
&[
pass_list_as_i128(env, list),
pass_as_opaque(env, transform_ptr),
pass_as_opaque(env, closure_data_ptr),
stepper_caller.into(),
alignment_intvalue(env, &before_layout),
before_width.into(),
result_width.into(),
after_width.into(),
layout_width(env, before_layout),
layout_width(env, after_layout),
layout_width(env, result_layout),
inc_closure.as_global_value().as_pointer_value().into(),
dec_result_fn.as_global_value().as_pointer_value().into(),
],
@ -811,23 +776,19 @@ pub fn list_keep_result<'a, 'ctx, 'env>(
/// List.sortWith : List a, (a, a -> Ordering) -> List a
pub fn list_sort_with<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>,
transform: BasicValueEnum<'ctx>,
roc_function_call: RocFunctionCall<'ctx>,
compare_wrapper: PointerValue<'ctx>,
list: BasicValueEnum<'ctx>,
element_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
let transform_ptr = transform.into_pointer_value();
let compare_wrapper = build_compare_wrapper(env, layout_ids, element_layout)
.as_global_value()
.as_pointer_value();
call_bitcode_fn_returns_list(
env,
&[
pass_list_as_i128(env, list),
pass_as_opaque(env, transform_ptr),
compare_wrapper.into(),
pass_as_opaque(env, roc_function_call.data),
roc_function_call.inc_n_data.into(),
roc_function_call.data_is_owned.into(),
alignment_intvalue(env, &element_layout),
layout_width(env, element_layout),
],
@ -835,127 +796,64 @@ pub fn list_sort_with<'a, 'ctx, 'env>(
)
}
/// List.map : List before, (before -> after) -> List after
pub fn list_map<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>,
transform: BasicValueEnum<'ctx>,
transform_layout: &Layout<'a>,
list: BasicValueEnum<'ctx>,
element_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
list_map_generic(
env,
layout_ids,
transform,
transform_layout,
list,
element_layout,
bitcode::LIST_MAP,
&[*element_layout],
)
}
/// List.mapWithIndex : List before, (Nat, before -> after) -> List after
pub fn list_map_with_index<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>,
transform: BasicValueEnum<'ctx>,
transform_layout: &Layout<'a>,
roc_function_call: RocFunctionCall<'ctx>,
list: BasicValueEnum<'ctx>,
element_layout: &Layout<'a>,
return_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
list_map_generic(
env,
layout_ids,
transform,
transform_layout,
list,
element_layout,
bitcode::LIST_MAP_WITH_INDEX,
&[Layout::Builtin(Builtin::Usize), *element_layout],
)
}
fn list_map_generic<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>,
transform: BasicValueEnum<'ctx>,
transform_layout: &Layout<'a>,
list: BasicValueEnum<'ctx>,
element_layout: &Layout<'a>,
op: &str,
argument_layouts: &[Layout<'a>],
) -> BasicValueEnum<'ctx> {
let builder = env.builder;
let return_layout = match transform_layout {
Layout::FunctionPointer(_, ret) => ret,
Layout::Closure(_, _, ret) => ret,
_ => unreachable!("not a callable layout"),
};
let transform_ptr = builder.build_alloca(transform.get_type(), "transform_ptr");
env.builder.build_store(transform_ptr, transform);
let stepper_caller =
build_transform_caller(env, layout_ids, transform_layout, argument_layouts)
.as_global_value()
.as_pointer_value();
call_bitcode_fn_returns_list(
env,
&[
pass_list_as_i128(env, list),
pass_as_opaque(env, transform_ptr),
stepper_caller.into(),
roc_function_call.caller.into(),
pass_as_opaque(env, roc_function_call.data),
roc_function_call.inc_n_data.into(),
roc_function_call.data_is_owned.into(),
alignment_intvalue(env, &element_layout),
layout_width(env, element_layout),
layout_width(env, return_layout),
],
op,
bitcode::LIST_MAP_WITH_INDEX,
)
}
/// List.map : List before, (before -> after) -> List after
pub fn list_map<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
roc_function_call: RocFunctionCall<'ctx>,
list: BasicValueEnum<'ctx>,
element_layout: &Layout<'a>,
return_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
call_bitcode_fn_returns_list(
env,
&[
pass_list_as_i128(env, list),
roc_function_call.caller.into(),
pass_as_opaque(env, roc_function_call.data),
roc_function_call.inc_n_data.into(),
roc_function_call.data_is_owned.into(),
alignment_intvalue(env, &element_layout),
layout_width(env, element_layout),
layout_width(env, return_layout),
],
bitcode::LIST_MAP,
)
}
pub fn list_map2<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>,
transform: BasicValueEnum<'ctx>,
transform_layout: &Layout<'a>,
roc_function_call: RocFunctionCall<'ctx>,
list1: BasicValueEnum<'ctx>,
list2: BasicValueEnum<'ctx>,
element1_layout: &Layout<'a>,
element2_layout: &Layout<'a>,
return_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
let builder = env.builder;
let return_layout = match transform_layout {
Layout::FunctionPointer(_, ret) => ret,
Layout::Closure(_, _, ret) => ret,
_ => unreachable!("not a callable layout"),
};
let transform_ptr = builder.build_alloca(transform.get_type(), "transform_ptr");
env.builder.build_store(transform_ptr, transform);
let argument_layouts = [*element1_layout, *element2_layout];
let stepper_caller =
build_transform_caller(env, layout_ids, transform_layout, &argument_layouts)
.as_global_value()
.as_pointer_value();
let a_width = env
.ptr_int()
.const_int(element1_layout.stack_size(env.ptr_bytes) as u64, false);
let b_width = env
.ptr_int()
.const_int(element2_layout.stack_size(env.ptr_bytes) as u64, false);
let c_width = env
.ptr_int()
.const_int(return_layout.stack_size(env.ptr_bytes) as u64, false);
let dec_a = build_dec_wrapper(env, layout_ids, element1_layout);
let dec_b = build_dec_wrapper(env, layout_ids, element2_layout);
@ -964,12 +862,14 @@ pub fn list_map2<'a, 'ctx, 'env>(
&[
pass_list_as_i128(env, list1),
pass_list_as_i128(env, list2),
pass_as_opaque(env, transform_ptr),
stepper_caller.into(),
alignment_intvalue(env, &transform_layout),
a_width.into(),
b_width.into(),
c_width.into(),
roc_function_call.caller.into(),
pass_as_opaque(env, roc_function_call.data),
roc_function_call.inc_n_data.into(),
roc_function_call.data_is_owned.into(),
alignment_intvalue(env, return_layout),
layout_width(env, element1_layout),
layout_width(env, element2_layout),
layout_width(env, return_layout),
dec_a.as_global_value().as_pointer_value().into(),
dec_b.as_global_value().as_pointer_value().into(),
],
@ -980,48 +880,15 @@ pub fn list_map2<'a, 'ctx, 'env>(
pub fn list_map3<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>,
transform: BasicValueEnum<'ctx>,
transform_layout: &Layout<'a>,
roc_function_call: RocFunctionCall<'ctx>,
list1: BasicValueEnum<'ctx>,
list2: BasicValueEnum<'ctx>,
list3: BasicValueEnum<'ctx>,
element1_layout: &Layout<'a>,
element2_layout: &Layout<'a>,
element3_layout: &Layout<'a>,
result_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
let builder = env.builder;
let return_layout = match transform_layout {
Layout::FunctionPointer(_, ret) => ret,
Layout::Closure(_, _, ret) => ret,
_ => unreachable!("not a callable layout"),
};
let transform_ptr = builder.build_alloca(transform.get_type(), "transform_ptr");
env.builder.build_store(transform_ptr, transform);
let argument_layouts = [*element1_layout, *element2_layout, *element3_layout];
let stepper_caller =
build_transform_caller(env, layout_ids, transform_layout, &argument_layouts)
.as_global_value()
.as_pointer_value();
let a_width = env
.ptr_int()
.const_int(element1_layout.stack_size(env.ptr_bytes) as u64, false);
let b_width = env
.ptr_int()
.const_int(element2_layout.stack_size(env.ptr_bytes) as u64, false);
let c_width = env
.ptr_int()
.const_int(element3_layout.stack_size(env.ptr_bytes) as u64, false);
let d_width = env
.ptr_int()
.const_int(return_layout.stack_size(env.ptr_bytes) as u64, false);
let dec_a = build_dec_wrapper(env, layout_ids, element1_layout);
let dec_b = build_dec_wrapper(env, layout_ids, element2_layout);
let dec_c = build_dec_wrapper(env, layout_ids, element3_layout);
@ -1032,13 +899,15 @@ pub fn list_map3<'a, 'ctx, 'env>(
pass_list_as_i128(env, list1),
pass_list_as_i128(env, list2),
pass_list_as_i128(env, list3),
pass_as_opaque(env, transform_ptr),
stepper_caller.into(),
alignment_intvalue(env, transform_layout),
a_width.into(),
b_width.into(),
c_width.into(),
d_width.into(),
roc_function_call.caller.into(),
pass_as_opaque(env, roc_function_call.data),
roc_function_call.inc_n_data.into(),
roc_function_call.data_is_owned.into(),
alignment_intvalue(env, result_layout),
layout_width(env, element1_layout),
layout_width(env, element2_layout),
layout_width(env, element3_layout),
layout_width(env, result_layout),
dec_a.as_global_value().as_pointer_value().into(),
dec_b.as_global_value().as_pointer_value().into(),
dec_c.as_global_value().as_pointer_value().into(),