WIP List.map + RC'd closure troubles

This commit is contained in:
Folkert 2021-05-17 19:31:52 +02:00
parent 2b72f9e733
commit 8dddf952a8
5 changed files with 121 additions and 18 deletions

View file

@ -175,18 +175,34 @@ pub fn listReverse(list: RocList, alignment: usize, element_width: usize) callco
} }
} }
pub fn listMap(list: RocList, transform: Opaque, caller: Caller1, alignment: usize, old_element_width: usize, new_element_width: usize) callconv(.C) RocList { pub const RocFunctionCall1 = extern struct {
caller: Caller1,
data: Opaque,
inc_n_data: IncN,
data_is_owned: bool,
};
pub fn listMap(
list: RocList,
call: RocFunctionCall1,
alignment: usize,
old_element_width: usize,
new_element_width: usize,
) callconv(.C) RocList {
if (list.bytes) |source_ptr| { if (list.bytes) |source_ptr| {
const size = list.len(); const size = list.len();
var i: usize = 0; var i: usize = 0;
const output = RocList.allocate(std.heap.c_allocator, alignment, size, new_element_width); const output = RocList.allocate(std.heap.c_allocator, alignment, size, new_element_width);
const target_ptr = output.bytes orelse unreachable; const target_ptr = output.bytes orelse unreachable;
while (i < size) : (i += 1) { // if (call.data_is_owned) {
caller(transform, source_ptr + (i * old_element_width), target_ptr + (i * new_element_width)); // }
}
// utils.decref(std.heap.c_allocator, alignment, list.bytes, size * old_element_width); call.inc_n_data(call.data, size);
while (i < size) : (i += 1) {
call.caller(call.data, source_ptr + (i * old_element_width), target_ptr + (i * new_element_width));
}
return output; return output;
} else { } else {

View file

@ -3669,10 +3669,12 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
Layout::Builtin(Builtin::EmptyList) => empty_list(env), Layout::Builtin(Builtin::EmptyList) => empty_list(env),
Layout::Builtin(Builtin::List(_, element_layout)) => list_map( Layout::Builtin(Builtin::List(_, element_layout)) => list_map(
env, env,
layout_ids,
function, function,
function_layout, function_layout,
closure, closure,
*closure_layout, *closure_layout,
function_owns_closure_data,
list, list,
element_layout, element_layout,
), ),

View file

@ -858,26 +858,100 @@ pub fn list_map_with_index<'a, 'ctx, 'env>(
) )
} }
fn roc_function_call_1<'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>,
closure_data_is_owned: bool,
argument_layouts: &[Layout<'a>],
) -> PointerValue<'ctx> {
// %list.RocFunctionCall1 = type { void (i8*, i8*, i8*)*, i8*, void (i8*, i64)*, i1 }
let struct_type = env.module.get_struct_type("list.RocFunctionCall1").unwrap();
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, argument_layouts)
.as_global_value()
.as_pointer_value();
let inc_closure_data = build_inc_n_wrapper(env, layout_ids, &closure_data_layout)
.as_global_value()
.as_pointer_value();
let closure_data_is_owned = env
.context
.bool_type()
.const_int(closure_data_is_owned as u64, false);
let mut struct_value = builder
.build_insert_value(struct_type.get_undef(), stepper_caller, 0, "")
.unwrap();
struct_value = builder
.build_insert_value(struct_value, pass_as_opaque(env, closure_data_ptr), 1, "")
.unwrap();
struct_value = builder
.build_insert_value(struct_value, inc_closure_data, 2, "")
.unwrap();
struct_value = builder
.build_insert_value(struct_value, closure_data_is_owned, 3, "")
.unwrap();
let ptr = env.builder.build_alloca(struct_type, "roc_function_call_1");
env.builder.build_store(ptr, struct_value);
ptr
}
/// List.map : List before, (before -> after) -> List after /// List.map : List before, (before -> after) -> List after
pub fn list_map<'a, 'ctx, 'env>( pub fn list_map<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>, env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>,
transform: FunctionValue<'ctx>, transform: FunctionValue<'ctx>,
transform_layout: Layout<'a>, transform_layout: Layout<'a>,
closure_data: BasicValueEnum<'ctx>, closure_data: BasicValueEnum<'ctx>,
closure_data_layout: Layout<'a>, closure_data_layout: Layout<'a>,
closure_data_is_owned: bool,
list: BasicValueEnum<'ctx>, list: BasicValueEnum<'ctx>,
element_layout: &Layout<'a>, element_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> { ) -> BasicValueEnum<'ctx> {
list_map_generic( let argument_layouts = &[*element_layout];
let return_layout = match transform_layout {
Layout::FunctionPointer(_, ret) => ret,
Layout::Closure(_, _, ret) => ret,
_ => unreachable!("not a callable layout"),
};
let roc_function_call = roc_function_call_1(
env, env,
layout_ids,
transform, transform,
transform_layout,
list,
element_layout,
closure_data, closure_data,
closure_data_layout, closure_data_layout,
closure_data_is_owned,
argument_layouts,
);
call_bitcode_fn_returns_list(
env,
&[
pass_list_as_i128(env, list),
roc_function_call.into(),
alignment_intvalue(env, &element_layout),
layout_width(env, element_layout),
layout_width(env, return_layout),
],
bitcode::LIST_MAP, bitcode::LIST_MAP,
&[*element_layout],
) )
} }

View file

@ -2049,12 +2049,6 @@ fn update<'a>(
&& state.goal_phase == Phase::MakeSpecializations && state.goal_phase == Phase::MakeSpecializations
{ {
Proc::insert_refcount_operations(arena, &mut state.procedures); Proc::insert_refcount_operations(arena, &mut state.procedures);
Proc::optimize_refcount_operations(
arena,
module_id,
&mut ident_ids,
&mut state.procedures,
);
// display the mono IR of the module, for debug purposes // display the mono IR of the module, for debug purposes
if roc_mono::ir::PRETTY_PRINT_IR_SYMBOLS { if roc_mono::ir::PRETTY_PRINT_IR_SYMBOLS {
let procs_string = state let procs_string = state
@ -2067,6 +2061,12 @@ fn update<'a>(
println!("{}", result); println!("{}", result);
} }
// Proc::optimize_refcount_operations(
// arena,
// module_id,
// &mut ident_ids,
// &mut state.procedures,
// );
state.constrained_ident_ids.insert(module_id, ident_ids); state.constrained_ident_ids.insert(module_id, ident_ids);

View file

@ -416,6 +416,12 @@ impl<'a> Context<'a> {
and it has been borrowed by the application. and it has been borrowed by the application.
Remark: `x` may occur multiple times in the application (e.g., `f x y x`). Remark: `x` may occur multiple times in the application (e.g., `f x y x`).
This is why we check whether it is the first occurrence. */ This is why we check whether it is the first occurrence. */
dbg!(
self.must_consume(*x),
is_first_occurence(xs, i),
*is_borrow,
!b_live_vars.contains(x)
);
if self.must_consume(*x) if self.must_consume(*x)
&& is_first_occurence(xs, i) && is_first_occurence(xs, i)
@ -461,16 +467,21 @@ impl<'a> Context<'a> {
Some(ps) => { Some(ps) => {
let b = if ps[0].borrow { let b = if ps[0].borrow {
let ps = [BORROWED, BORROWED, BORROWED]; let ps = [BORROWED, BORROWED, BORROWED];
println!("----------------");
self.add_dec_after_lowlevel(arguments, &ps, b, b_live_vars) self.add_dec_after_lowlevel(arguments, &ps, b, b_live_vars)
} else { } else {
// let ps = [OWNED, BORROWED, BORROWED]; let ps = [OWNED, BORROWED, BORROWED];
// self.add_dec_after_lowlevel(arguments, &ps, b, b_live_vars) println!("----------------");
let b = self.add_dec_after_lowlevel(arguments, &ps, b, b_live_vars);
self.arena.alloc(Stmt::Refcounting( self.arena.alloc(Stmt::Refcounting(
ModifyRc::DecRef(arguments[0]), ModifyRc::DecRef(arguments[0]),
self.arena.alloc(b), self.arena.alloc(b),
)) ))
}; };
dbg!(self.must_consume(arguments[2]));
let call_type = { let call_type = {
if ps[1].borrow { if ps[1].borrow {
call_type call_type