mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-21 07:49:17 +03:00
first pass for List.keep
This commit is contained in:
parent
e3b102e0c3
commit
d01d539d6b
@ -356,19 +356,33 @@ pub fn listMap3(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn listKeepIf(list: RocList, transform: Opaque, caller: Caller1, alignment: usize, element_width: usize, inc: Inc, dec: Dec) callconv(.C) RocList {
|
||||
pub fn listKeepIf(
|
||||
list: RocList,
|
||||
caller: Caller1,
|
||||
data: Opaque,
|
||||
inc_n_data: IncN,
|
||||
data_is_owned: bool,
|
||||
alignment: usize,
|
||||
element_width: usize,
|
||||
inc: Inc,
|
||||
dec: Dec,
|
||||
) callconv(.C) RocList {
|
||||
if (list.bytes) |source_ptr| {
|
||||
const size = list.len();
|
||||
var i: usize = 0;
|
||||
var output = RocList.allocate(std.heap.c_allocator, alignment, list.len(), list.len() * element_width);
|
||||
const target_ptr = output.bytes orelse unreachable;
|
||||
|
||||
if (data_is_owned) {
|
||||
inc_n_data(data, size);
|
||||
}
|
||||
|
||||
var kept: usize = 0;
|
||||
while (i < size) : (i += 1) {
|
||||
var keep = false;
|
||||
const element = source_ptr + (i * element_width);
|
||||
inc(element);
|
||||
caller(transform, element, @ptrCast(?[*]u8, &keep));
|
||||
caller(data, element, @ptrCast(?[*]u8, &keep));
|
||||
|
||||
if (keep) {
|
||||
@memcpy(target_ptr + (kept * element_width), element, element_width);
|
||||
@ -379,9 +393,6 @@ pub fn listKeepIf(list: RocList, transform: Opaque, caller: Caller1, alignment:
|
||||
}
|
||||
}
|
||||
|
||||
// consume the input list
|
||||
utils.decref(std.heap.c_allocator, alignment, list.bytes, size * element_width);
|
||||
|
||||
if (kept == 0) {
|
||||
// if the output is empty, deallocate the space we made for the result
|
||||
utils.decref(std.heap.c_allocator, alignment, output.bytes, size * element_width);
|
||||
@ -396,15 +407,73 @@ pub fn listKeepIf(list: RocList, transform: Opaque, caller: Caller1, alignment:
|
||||
}
|
||||
}
|
||||
|
||||
pub fn listKeepOks(list: RocList, transform: Opaque, caller: Caller1, alignment: usize, before_width: usize, result_width: usize, after_width: usize, inc_closure: Inc, dec_result: Dec) callconv(.C) RocList {
|
||||
return listKeepResult(list, RocResult.isOk, transform, caller, alignment, before_width, result_width, after_width, inc_closure, dec_result);
|
||||
pub fn listKeepOks(
|
||||
list: RocList,
|
||||
caller: Caller1,
|
||||
data: Opaque,
|
||||
inc_n_data: IncN,
|
||||
data_is_owned: bool,
|
||||
alignment: usize,
|
||||
before_width: usize,
|
||||
result_width: usize,
|
||||
after_width: usize,
|
||||
dec_result: Dec,
|
||||
) callconv(.C) RocList {
|
||||
return listKeepResult(
|
||||
list,
|
||||
RocResult.isOk,
|
||||
caller,
|
||||
data,
|
||||
inc_n_data,
|
||||
data_is_owned,
|
||||
alignment,
|
||||
before_width,
|
||||
result_width,
|
||||
after_width,
|
||||
dec_result,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn listKeepErrs(list: RocList, transform: Opaque, caller: Caller1, alignment: usize, before_width: usize, result_width: usize, after_width: usize, inc_closure: Inc, dec_result: Dec) callconv(.C) RocList {
|
||||
return listKeepResult(list, RocResult.isErr, transform, caller, alignment, before_width, result_width, after_width, inc_closure, dec_result);
|
||||
pub fn listKeepErrs(
|
||||
list: RocList,
|
||||
caller: Caller1,
|
||||
data: Opaque,
|
||||
inc_n_data: IncN,
|
||||
data_is_owned: bool,
|
||||
alignment: usize,
|
||||
before_width: usize,
|
||||
result_width: usize,
|
||||
after_width: usize,
|
||||
dec_result: Dec,
|
||||
) callconv(.C) RocList {
|
||||
return listKeepResult(
|
||||
list,
|
||||
RocResult.isErr,
|
||||
caller,
|
||||
data,
|
||||
inc_n_data,
|
||||
data_is_owned,
|
||||
alignment,
|
||||
before_width,
|
||||
result_width,
|
||||
after_width,
|
||||
dec_result,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn listKeepResult(list: RocList, is_good_constructor: fn (RocResult) bool, transform: Opaque, caller: Caller1, alignment: usize, before_width: usize, result_width: usize, after_width: usize, inc_closure: Inc, dec_result: Dec) RocList {
|
||||
pub fn listKeepResult(
|
||||
list: RocList,
|
||||
is_good_constructor: fn (RocResult) bool,
|
||||
caller: Caller1,
|
||||
data: Opaque,
|
||||
inc_n_data: IncN,
|
||||
data_is_owned: bool,
|
||||
alignment: usize,
|
||||
before_width: usize,
|
||||
result_width: usize,
|
||||
after_width: usize,
|
||||
dec_result: Dec,
|
||||
) RocList {
|
||||
if (list.bytes) |source_ptr| {
|
||||
const size = list.len();
|
||||
var i: usize = 0;
|
||||
@ -413,11 +482,14 @@ pub fn listKeepResult(list: RocList, is_good_constructor: fn (RocResult) bool, t
|
||||
|
||||
var temporary = @ptrCast([*]u8, std.heap.c_allocator.alloc(u8, result_width) catch unreachable);
|
||||
|
||||
if (data_is_owned) {
|
||||
inc_n_data(data, size);
|
||||
}
|
||||
|
||||
var kept: usize = 0;
|
||||
while (i < size) : (i += 1) {
|
||||
const before_element = source_ptr + (i * before_width);
|
||||
inc_closure(transform);
|
||||
caller(transform, before_element, temporary);
|
||||
caller(data, before_element, temporary);
|
||||
|
||||
const result = utils.RocResult{ .bytes = temporary };
|
||||
|
||||
@ -430,7 +502,6 @@ pub fn listKeepResult(list: RocList, is_good_constructor: fn (RocResult) bool, t
|
||||
}
|
||||
}
|
||||
|
||||
utils.decref(std.heap.c_allocator, alignment, list.bytes, size * before_width);
|
||||
std.heap.c_allocator.free(temporary[0..result_width]);
|
||||
|
||||
if (kept == 0) {
|
||||
@ -746,13 +817,25 @@ fn quicksort(source_ptr: [*]u8, transform: Opaque, wrapper: CompareFn, element_w
|
||||
}
|
||||
}
|
||||
|
||||
pub fn listSortWith(input: RocList, transform: Opaque, wrapper: CompareFn, alignment: usize, element_width: usize) callconv(.C) RocList {
|
||||
pub fn listSortWith(
|
||||
input: RocList,
|
||||
caller: CompareFn,
|
||||
data: Opaque,
|
||||
inc_n_data: IncN,
|
||||
data_is_owned: bool,
|
||||
alignment: usize,
|
||||
element_width: usize,
|
||||
) callconv(.C) RocList {
|
||||
var list = input.makeUnique(std.heap.c_allocator, alignment, element_width);
|
||||
|
||||
if (data_is_owned) {
|
||||
inc_n_data(data, list.len());
|
||||
}
|
||||
|
||||
if (list.bytes) |source_ptr| {
|
||||
const low = 0;
|
||||
const high: isize = @intCast(isize, list.len()) - 1;
|
||||
quicksort(source_ptr, transform, wrapper, element_width, low, high);
|
||||
quicksort(source_ptr, data, caller, element_width, low, high);
|
||||
}
|
||||
|
||||
return list;
|
||||
|
@ -2305,7 +2305,32 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
|
||||
env,
|
||||
value.into_struct_value(),
|
||||
);
|
||||
|
||||
// because of how we insert DECREF for lists, we can't guarantee that
|
||||
// the list is non-empty. When the list is empty, the pointer to the
|
||||
// elements is NULL, and trying to get to the RC address will
|
||||
// underflow, causing a segfault. Therefore, in this case we must
|
||||
// manually check that the list is non-empty
|
||||
let not_empty = env.context.append_basic_block(parent, "not_null");
|
||||
let done = env.context.append_basic_block(parent, "done");
|
||||
|
||||
let length = list_len(env.builder, value.into_struct_value());
|
||||
let is_empty = env.builder.build_int_compare(
|
||||
IntPredicate::EQ,
|
||||
length,
|
||||
length.get_type().const_zero(),
|
||||
"",
|
||||
);
|
||||
|
||||
env.builder
|
||||
.build_conditional_branch(is_empty, done, not_empty);
|
||||
|
||||
env.builder.position_at_end(not_empty);
|
||||
|
||||
refcount_ptr.decrement(env, layout);
|
||||
|
||||
env.builder.build_unconditional_branch(done);
|
||||
env.builder.position_at_end(done);
|
||||
}
|
||||
|
||||
_ if layout.is_refcounted() => {
|
||||
@ -3680,16 +3705,24 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||
match list_layout {
|
||||
Layout::Builtin(Builtin::EmptyList) => default,
|
||||
Layout::Builtin(Builtin::List(_, element_layout)) => {
|
||||
let argument_layouts = &[**element_layout, *default_layout];
|
||||
|
||||
let roc_function_call = roc_function_call(
|
||||
env,
|
||||
layout_ids,
|
||||
function,
|
||||
closure,
|
||||
*closure_layout,
|
||||
function_owns_closure_data,
|
||||
argument_layouts,
|
||||
);
|
||||
|
||||
crate::llvm::build_list::list_walk_generic(
|
||||
env,
|
||||
layout_ids,
|
||||
parent,
|
||||
roc_function_call,
|
||||
list,
|
||||
element_layout,
|
||||
function,
|
||||
function_layout,
|
||||
closure,
|
||||
*closure_layout,
|
||||
default,
|
||||
default_layout,
|
||||
$variant,
|
||||
@ -3862,15 +3895,21 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||
|
||||
match list_layout {
|
||||
Layout::Builtin(Builtin::EmptyList) => empty_list(env),
|
||||
Layout::Builtin(Builtin::List(_, element_layout)) => list_keep_if(
|
||||
env,
|
||||
layout_ids,
|
||||
function,
|
||||
closure,
|
||||
*closure_layout,
|
||||
list,
|
||||
element_layout,
|
||||
),
|
||||
Layout::Builtin(Builtin::List(_, element_layout)) => {
|
||||
let argument_layouts = &[**element_layout];
|
||||
|
||||
let roc_function_call = roc_function_call(
|
||||
env,
|
||||
layout_ids,
|
||||
function,
|
||||
closure,
|
||||
*closure_layout,
|
||||
function_owns_closure_data,
|
||||
argument_layouts,
|
||||
);
|
||||
|
||||
list_keep_if(env, layout_ids, roc_function_call, list, element_layout)
|
||||
}
|
||||
_ => unreachable!("invalid list layout"),
|
||||
}
|
||||
}
|
||||
@ -3890,17 +3929,29 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||
(
|
||||
Layout::Builtin(Builtin::List(_, before_layout)),
|
||||
Layout::Builtin(Builtin::List(_, after_layout)),
|
||||
) => list_keep_oks(
|
||||
env,
|
||||
layout_ids,
|
||||
function,
|
||||
function_layout,
|
||||
closure,
|
||||
*closure_layout,
|
||||
list,
|
||||
before_layout,
|
||||
after_layout,
|
||||
),
|
||||
) => {
|
||||
let argument_layouts = &[**before_layout];
|
||||
|
||||
let roc_function_call = roc_function_call(
|
||||
env,
|
||||
layout_ids,
|
||||
function,
|
||||
closure,
|
||||
*closure_layout,
|
||||
function_owns_closure_data,
|
||||
argument_layouts,
|
||||
);
|
||||
|
||||
list_keep_oks(
|
||||
env,
|
||||
layout_ids,
|
||||
roc_function_call,
|
||||
&function_layout,
|
||||
list,
|
||||
before_layout,
|
||||
after_layout,
|
||||
)
|
||||
}
|
||||
(other1, other2) => {
|
||||
unreachable!("invalid list layouts:\n{:?}\n{:?}", other1, other2)
|
||||
}
|
||||
@ -3922,17 +3973,29 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||
(
|
||||
Layout::Builtin(Builtin::List(_, before_layout)),
|
||||
Layout::Builtin(Builtin::List(_, after_layout)),
|
||||
) => list_keep_errs(
|
||||
env,
|
||||
layout_ids,
|
||||
function,
|
||||
function_layout,
|
||||
closure,
|
||||
*closure_layout,
|
||||
list,
|
||||
before_layout,
|
||||
after_layout,
|
||||
),
|
||||
) => {
|
||||
let argument_layouts = &[**before_layout];
|
||||
|
||||
let roc_function_call = roc_function_call(
|
||||
env,
|
||||
layout_ids,
|
||||
function,
|
||||
closure,
|
||||
*closure_layout,
|
||||
function_owns_closure_data,
|
||||
argument_layouts,
|
||||
);
|
||||
|
||||
list_keep_errs(
|
||||
env,
|
||||
layout_ids,
|
||||
roc_function_call,
|
||||
&function_layout,
|
||||
list,
|
||||
before_layout,
|
||||
after_layout,
|
||||
)
|
||||
}
|
||||
(other1, other2) => {
|
||||
unreachable!("invalid list layouts:\n{:?}\n{:?}", other1, other2)
|
||||
}
|
||||
@ -3959,14 +4022,34 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
||||
|
||||
match list_layout {
|
||||
Layout::Builtin(Builtin::EmptyList) => empty_list(env),
|
||||
Layout::Builtin(Builtin::List(_, element_layout)) => list_sort_with(
|
||||
env,
|
||||
function,
|
||||
closure,
|
||||
*closure_layout,
|
||||
list,
|
||||
element_layout,
|
||||
),
|
||||
Layout::Builtin(Builtin::List(_, element_layout)) => {
|
||||
use crate::llvm::bitcode::build_compare_wrapper;
|
||||
|
||||
let argument_layouts = &[**element_layout, **element_layout];
|
||||
|
||||
let compare_wrapper =
|
||||
build_compare_wrapper(env, function, *closure_layout, element_layout)
|
||||
.as_global_value()
|
||||
.as_pointer_value();
|
||||
|
||||
let roc_function_call = roc_function_call(
|
||||
env,
|
||||
layout_ids,
|
||||
function,
|
||||
closure,
|
||||
*closure_layout,
|
||||
function_owns_closure_data,
|
||||
argument_layouts,
|
||||
);
|
||||
|
||||
list_sort_with(
|
||||
env,
|
||||
roc_function_call,
|
||||
compare_wrapper,
|
||||
list,
|
||||
element_layout,
|
||||
)
|
||||
}
|
||||
_ => unreachable!("invalid list layout"),
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
#![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_new, call_bitcode_fn, call_void_bitcode_fn,
|
||||
build_dec_wrapper, build_eq_wrapper, build_inc_n_wrapper, build_inc_wrapper,
|
||||
build_transform_caller_new, call_bitcode_fn, call_void_bitcode_fn,
|
||||
};
|
||||
use crate::llvm::build::{
|
||||
allocate_with_refcount_help, cast_basic_basic, complex_bitcast, Env, InPlace, RocFunctionCall,
|
||||
@ -444,56 +444,12 @@ pub enum ListWalk {
|
||||
WalkBackwardsUntil,
|
||||
}
|
||||
|
||||
pub fn list_walk_help<'a, 'ctx, 'env>(
|
||||
env: &'ctx Env<'a, 'ctx, 'env>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
scope: &crate::llvm::build::Scope<'a, 'ctx>,
|
||||
parent: FunctionValue<'ctx>,
|
||||
args: &[roc_module::symbol::Symbol],
|
||||
function: FunctionValue<'a>,
|
||||
function_layout: Layout<'a>,
|
||||
variant: ListWalk,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
use crate::llvm::build::load_symbol_and_layout;
|
||||
|
||||
debug_assert_eq!(args.len(), 4);
|
||||
|
||||
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||
|
||||
let (default, default_layout) = load_symbol_and_layout(scope, &args[1]);
|
||||
|
||||
let (closure, closure_layout) = load_symbol_and_layout(scope, &args[3]);
|
||||
|
||||
match list_layout {
|
||||
Layout::Builtin(Builtin::EmptyList) => default,
|
||||
Layout::Builtin(Builtin::List(_, element_layout)) => list_walk_generic(
|
||||
env,
|
||||
layout_ids,
|
||||
parent,
|
||||
list,
|
||||
element_layout,
|
||||
function,
|
||||
function_layout,
|
||||
closure,
|
||||
*closure_layout,
|
||||
default,
|
||||
default_layout,
|
||||
variant,
|
||||
),
|
||||
_ => unreachable!("invalid list layout"),
|
||||
}
|
||||
}
|
||||
|
||||
pub 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>,
|
||||
transform: FunctionValue<'ctx>,
|
||||
_transform_layout: Layout<'a>,
|
||||
closure_data: BasicValueEnum<'ctx>,
|
||||
closure_data_layout: Layout<'a>,
|
||||
default: BasicValueEnum<'ctx>,
|
||||
default_layout: &Layout<'a>,
|
||||
variant: ListWalk,
|
||||
@ -507,21 +463,9 @@ pub fn list_walk_generic<'a, 'ctx, 'env>(
|
||||
ListWalk::WalkBackwardsUntil => todo!(),
|
||||
};
|
||||
|
||||
let closure_data_ptr = builder.build_alloca(closure_data.get_type(), "closure_data_ptr");
|
||||
env.builder.build_store(closure_data_ptr, closure_data);
|
||||
|
||||
let default_ptr = builder.build_alloca(default.get_type(), "default_ptr");
|
||||
env.builder.build_store(default_ptr, default);
|
||||
|
||||
let stepper_caller = build_transform_caller_new(
|
||||
env,
|
||||
transform,
|
||||
closure_data_layout,
|
||||
&[*element_layout, *default_layout],
|
||||
)
|
||||
.as_global_value()
|
||||
.as_pointer_value();
|
||||
|
||||
let result_ptr = env.builder.build_alloca(default.get_type(), "result");
|
||||
|
||||
match variant {
|
||||
@ -530,8 +474,10 @@ pub fn list_walk_generic<'a, 'ctx, 'env>(
|
||||
env,
|
||||
&[
|
||||
pass_list_as_i128(env, list),
|
||||
pass_as_opaque(env, closure_data_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),
|
||||
@ -547,8 +493,10 @@ pub fn list_walk_generic<'a, 'ctx, 'env>(
|
||||
env,
|
||||
&[
|
||||
pass_list_as_i128(env, list),
|
||||
pass_as_opaque(env, closure_data_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),
|
||||
@ -657,22 +605,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: FunctionValue<'ctx>,
|
||||
closure_data: BasicValueEnum<'ctx>,
|
||||
closure_data_layout: Layout<'a>,
|
||||
roc_function_call: RocFunctionCall<'ctx>,
|
||||
list: BasicValueEnum<'ctx>,
|
||||
element_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let builder = env.builder;
|
||||
|
||||
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_new(env, transform, closure_data_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);
|
||||
|
||||
@ -680,8 +616,10 @@ pub fn list_keep_if<'a, 'ctx, 'env>(
|
||||
env,
|
||||
&[
|
||||
pass_list_as_i128(env, list),
|
||||
pass_as_opaque(env, closure_data_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(),
|
||||
@ -695,24 +633,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: FunctionValue<'ctx>,
|
||||
transform_layout: Layout<'a>,
|
||||
closure_data: BasicValueEnum<'ctx>,
|
||||
closure_data_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,
|
||||
closure_data,
|
||||
closure_data_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,
|
||||
)
|
||||
}
|
||||
@ -721,24 +670,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: FunctionValue<'ctx>,
|
||||
transform_layout: Layout<'a>,
|
||||
closure_data: BasicValueEnum<'ctx>,
|
||||
closure_data_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,
|
||||
closure_data,
|
||||
closure_data_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,
|
||||
)
|
||||
}
|
||||
@ -771,18 +731,6 @@ pub fn list_keep_result<'a, 'ctx, 'env>(
|
||||
.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 dec_result_fn = build_dec_wrapper(env, layout_ids, result_layout);
|
||||
|
||||
@ -793,9 +741,9 @@ pub fn list_keep_result<'a, 'ctx, 'env>(
|
||||
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(),
|
||||
],
|
||||
@ -806,28 +754,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>,
|
||||
transform: FunctionValue<'ctx>,
|
||||
closure_data: BasicValueEnum<'ctx>,
|
||||
closure_data_layout: Layout<'a>,
|
||||
roc_function_call: RocFunctionCall<'ctx>,
|
||||
compare_wrapper: PointerValue<'ctx>,
|
||||
list: BasicValueEnum<'ctx>,
|
||||
element_layout: &Layout<'a>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let compare_wrapper =
|
||||
build_compare_wrapper(env, transform, closure_data_layout, element_layout)
|
||||
.as_global_value()
|
||||
.as_pointer_value();
|
||||
|
||||
let closure_data_ptr = env
|
||||
.builder
|
||||
.build_alloca(closure_data.get_type(), "closure_data_ptr");
|
||||
env.builder.build_store(closure_data_ptr, closure_data);
|
||||
|
||||
call_bitcode_fn_returns_list(
|
||||
env,
|
||||
&[
|
||||
pass_list_as_i128(env, list),
|
||||
pass_as_opaque(env, closure_data_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),
|
||||
],
|
||||
|
@ -425,7 +425,7 @@ impl<'a> BorrowInfState<'a> {
|
||||
debug_assert!(op.is_higher_order());
|
||||
|
||||
match op {
|
||||
ListMap | ListSortWith => {
|
||||
ListMap | ListKeepIf | ListKeepOks | ListKeepErrs => {
|
||||
match self.param_map.get_symbol(arguments[1], *closure_layout) {
|
||||
Some(function_ps) => {
|
||||
// own the list if the function wants to own the element
|
||||
@ -481,7 +481,6 @@ impl<'a> BorrowInfState<'a> {
|
||||
if !function_ps[0].borrow {
|
||||
self.own_var(arguments[0]);
|
||||
}
|
||||
|
||||
if !function_ps[1].borrow {
|
||||
self.own_var(arguments[1]);
|
||||
}
|
||||
@ -496,6 +495,41 @@ impl<'a> BorrowInfState<'a> {
|
||||
}
|
||||
None => unreachable!(),
|
||||
},
|
||||
ListSortWith => {
|
||||
match self.param_map.get_symbol(arguments[1], *closure_layout) {
|
||||
Some(function_ps) => {
|
||||
// always own the input list
|
||||
self.own_var(arguments[0]);
|
||||
|
||||
// own the closure environment if the function needs to own it
|
||||
if let Some(false) = function_ps.get(2).map(|p| p.borrow) {
|
||||
self.own_var(arguments[2]);
|
||||
}
|
||||
}
|
||||
None => unreachable!(),
|
||||
}
|
||||
}
|
||||
ListWalk | ListWalkUntil | ListWalkBackwards | DictWalk => {
|
||||
match self.param_map.get_symbol(arguments[2], *closure_layout) {
|
||||
Some(function_ps) => {
|
||||
// own the data structure if the function wants to own the element
|
||||
if !function_ps[0].borrow {
|
||||
self.own_var(arguments[0]);
|
||||
}
|
||||
|
||||
// own the default value if the function wants to own it
|
||||
if !function_ps[1].borrow {
|
||||
self.own_var(arguments[1]);
|
||||
}
|
||||
|
||||
// own the closure environment if the function needs to own it
|
||||
if let Some(false) = function_ps.get(2).map(|p| p.borrow) {
|
||||
self.own_var(arguments[3]);
|
||||
}
|
||||
}
|
||||
None => unreachable!(),
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// very unsure what demand RunLowLevel should place upon its arguments
|
||||
self.own_var(z);
|
||||
|
@ -490,7 +490,10 @@ impl<'a> Context<'a> {
|
||||
const CLOSURE_DATA: bool = BORROWED;
|
||||
|
||||
match op {
|
||||
roc_module::low_level::LowLevel::ListMap => {
|
||||
roc_module::low_level::LowLevel::ListMap
|
||||
| roc_module::low_level::LowLevel::ListKeepIf
|
||||
| roc_module::low_level::LowLevel::ListKeepOks
|
||||
| roc_module::low_level::LowLevel::ListKeepErrs => {
|
||||
match self.param_map.get_symbol(arguments[1], *closure_layout) {
|
||||
Some(function_ps) => {
|
||||
let borrows = [function_ps[0].borrow, FUNCTION, CLOSURE_DATA];
|
||||
@ -589,6 +592,56 @@ impl<'a> Context<'a> {
|
||||
None => unreachable!(),
|
||||
}
|
||||
}
|
||||
roc_module::low_level::LowLevel::ListSortWith => {
|
||||
match self.param_map.get_symbol(arguments[1], *closure_layout) {
|
||||
Some(function_ps) => {
|
||||
let borrows = [OWNED, FUNCTION, CLOSURE_DATA];
|
||||
|
||||
let b = self.add_dec_after_lowlevel(
|
||||
arguments,
|
||||
&borrows,
|
||||
b,
|
||||
b_live_vars,
|
||||
);
|
||||
|
||||
let v = create_call!(function_ps.get(2));
|
||||
|
||||
&*self.arena.alloc(Stmt::Let(z, v, l, b))
|
||||
}
|
||||
None => unreachable!(),
|
||||
}
|
||||
}
|
||||
roc_module::low_level::LowLevel::ListWalk
|
||||
| roc_module::low_level::LowLevel::ListWalkUntil
|
||||
| roc_module::low_level::LowLevel::ListWalkBackwards
|
||||
| roc_module::low_level::LowLevel::DictWalk => {
|
||||
match self.param_map.get_symbol(arguments[2], *closure_layout) {
|
||||
Some(function_ps) => {
|
||||
// borrow data structure based on first argument of the folded function
|
||||
// borrow the default based on second argument of the folded function
|
||||
let borrows = [
|
||||
function_ps[0].borrow,
|
||||
function_ps[1].borrow,
|
||||
FUNCTION,
|
||||
CLOSURE_DATA,
|
||||
];
|
||||
|
||||
let b = self.add_dec_after_lowlevel(
|
||||
arguments,
|
||||
&borrows,
|
||||
b,
|
||||
b_live_vars,
|
||||
);
|
||||
|
||||
let b = decref_if_owned!(function_ps[0].borrow, arguments[0], b);
|
||||
|
||||
let v = create_call!(function_ps.get(2));
|
||||
|
||||
&*self.arena.alloc(Stmt::Let(z, v, l, b))
|
||||
}
|
||||
None => unreachable!(),
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let ps = crate::borrow::lowlevel_borrow_signature(self.arena, *op);
|
||||
let b = self.add_dec_after_lowlevel(arguments, ps, b, b_live_vars);
|
||||
|
Loading…
Reference in New Issue
Block a user