Passed down inplace to everything that uses allocate_list

This commit is contained in:
Chad Stearns 2020-09-13 14:46:21 -04:00
parent 0a1e297b0f
commit 3112025b0c
2 changed files with 104 additions and 41 deletions

View File

@ -212,6 +212,17 @@ pub fn construct_optimization_passes<'a>(
(mpm, fpm)
}
fn get_inplace_from_layout<'a, 'b>(layout: &'b Layout<'a>) -> InPlace {
match layout {
Layout::Builtin(Builtin::EmptyList) => InPlace::InPlace,
Layout::Builtin(Builtin::List(memory_mode, _)) => match memory_mode {
MemoryMode::Unique => InPlace::InPlace,
MemoryMode::Refcounted => InPlace::Clone,
},
_ => unreachable!("Layout {:?} does not have an inplace", layout),
}
}
pub fn build_exp_literal<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
literal: &roc_mono::ir::Literal<'a>,
@ -239,7 +250,7 @@ pub fn build_exp_literal<'a, 'ctx, 'env>(
let len_type = env.ptr_int();
let len = len_type.const_int(bytes_len, false);
allocate_list(env, &CHAR_LAYOUT, len)
allocate_list(env, InPlace::Clone, &CHAR_LAYOUT, len)
// TODO check if malloc returned null; if so, runtime error for OOM!
};
@ -671,7 +682,11 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
}
}
EmptyArray => empty_polymorphic_list(env),
Array { elem_layout, elems } => list_literal(env, scope, elem_layout, elems),
Array { elem_layout, elems } => {
let inplace = get_inplace_from_layout(layout);
list_literal(env, inplace, scope, elem_layout, elems)
}
FunctionPointer(symbol, layout) => {
let fn_name = layout_ids
.get(*symbol, layout)
@ -760,6 +775,7 @@ pub fn allocate_with_refcount<'a, 'ctx, 'env>(
fn list_literal<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
inplace: InPlace,
scope: &Scope<'a, 'ctx>,
elem_layout: &Layout<'a>,
elems: &&[Symbol],
@ -775,7 +791,7 @@ fn list_literal<'a, 'ctx, 'env>(
let len_type = env.ptr_int();
let len = len_type.const_int(bytes_len, false);
allocate_list(env, elem_layout, len)
allocate_list(env, inplace, elem_layout, len)
// TODO check if malloc returned null; if so, runtime error for OOM!
};
@ -1469,6 +1485,7 @@ fn call_intrinsic<'a, 'ctx, 'env>(
})
}
#[derive(Copy, Clone)]
pub enum InPlace {
InPlace,
Clone,
@ -1512,7 +1529,9 @@ fn run_low_level<'a, 'ctx, 'env>(
let second_str = load_symbol(env, scope, &args[1]);
str_concat(env, parent, first_str, second_str)
let inplace = get_inplace_from_layout(layout);
str_concat(env, inplace, parent, first_str, second_str)
}
ListLen => {
// List.len : List * -> Int
@ -1528,7 +1547,9 @@ fn run_low_level<'a, 'ctx, 'env>(
let (arg, arg_layout) = load_symbol_and_layout(env, scope, &args[0]);
list_single(env, layout, arg, arg_layout)
let inplace = get_inplace_from_layout(layout);
list_single(env, inplace, arg, arg_layout)
}
ListRepeat => {
// List.repeat : Int, elem -> List elem
@ -1537,7 +1558,9 @@ fn run_low_level<'a, 'ctx, 'env>(
let list_len = load_symbol(env, scope, &args[0]).into_int_value();
let (elem, elem_layout) = load_symbol_and_layout(env, scope, &args[1]);
list_repeat(env, parent, list_len, elem, elem_layout)
let inplace = get_inplace_from_layout(layout);
list_repeat(env, inplace, parent, list_len, elem, elem_layout)
}
ListReverse => {
// List.reverse : List elem -> List elem
@ -1545,7 +1568,9 @@ fn run_low_level<'a, 'ctx, 'env>(
let (list, list_layout) = load_symbol_and_layout(env, scope, &args[0]);
list_reverse(env, parent, InPlace::Clone, list, list_layout)
let inplace = get_inplace_from_layout(layout);
list_reverse(env, parent, inplace, list, list_layout)
}
ListConcat => {
debug_assert_eq!(args.len(), 2);
@ -1554,7 +1579,9 @@ fn run_low_level<'a, 'ctx, 'env>(
let second_list = load_symbol(env, scope, &args[1]);
list_concat(env, parent, first_list, second_list, list_layout)
let inplace = get_inplace_from_layout(layout);
list_concat(env, inplace, parent, first_list, second_list, list_layout)
}
ListMap => {
// List.map : List before, (before -> after) -> List after
@ -1564,7 +1591,9 @@ fn run_low_level<'a, 'ctx, 'env>(
let (func, func_layout) = load_symbol_and_layout(env, scope, &args[1]);
list_map(env, parent, func, func_layout, list, list_layout)
let inplace = get_inplace_from_layout(layout);
list_map(env, inplace, parent, func, func_layout, list, list_layout)
}
ListKeepIf => {
// List.keepIf : List elem, (elem -> Bool) -> List elem
@ -1574,7 +1603,9 @@ fn run_low_level<'a, 'ctx, 'env>(
let (func, func_layout) = load_symbol_and_layout(env, scope, &args[1]);
list_keep_if(env, parent, func, func_layout, list, list_layout)
let inplace = get_inplace_from_layout(layout);
list_keep_if(env, inplace, parent, func, func_layout, list, list_layout)
}
ListWalkRight => {
// List.walkRight : List elem, (elem -> accum -> accum), accum -> accum
@ -1604,7 +1635,9 @@ fn run_low_level<'a, 'ctx, 'env>(
let original_wrapper = load_symbol(env, scope, &args[0]).into_struct_value();
let (elem, elem_layout) = load_symbol_and_layout(env, scope, &args[1]);
list_append(env, original_wrapper, elem, elem_layout)
let inplace = get_inplace_from_layout(layout);
list_append(env, inplace, original_wrapper, elem, elem_layout)
}
ListPrepend => {
// List.prepend : List elem, elem -> List elem
@ -1613,7 +1646,9 @@ fn run_low_level<'a, 'ctx, 'env>(
let original_wrapper = load_symbol(env, scope, &args[0]).into_struct_value();
let (elem, elem_layout) = load_symbol_and_layout(env, scope, &args[1]);
list_prepend(env, original_wrapper, elem, elem_layout)
let inplace = get_inplace_from_layout(layout);
list_prepend(env, inplace, original_wrapper, elem, elem_layout)
}
ListJoin => {
// List.join : List (List elem) -> List elem
@ -1621,7 +1656,9 @@ fn run_low_level<'a, 'ctx, 'env>(
let (list, outer_list_layout) = load_symbol_and_layout(env, scope, &args[0]);
list_join(env, parent, list, outer_list_layout)
let inplace = get_inplace_from_layout(layout);
list_join(env, inplace, parent, list, outer_list_layout)
}
NumAbs | NumNeg | NumRound | NumSqrtUnchecked | NumSin | NumCos | NumToFloat => {
debug_assert_eq!(args.len(), 1);
@ -1925,6 +1962,7 @@ where
/// Str.concat : Str, Str -> Str
fn str_concat<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
inplace: InPlace,
parent: FunctionValue<'ctx>,
first_str: BasicValueEnum<'ctx>,
second_str: BasicValueEnum<'ctx>,
@ -1955,6 +1993,7 @@ fn str_concat<'a, 'ctx, 'env>(
let (new_wrapper, _) = clone_nonempty_list(
env,
inplace,
second_str_len,
load_list_ptr(builder, second_str_wrapper, ptr_type),
&CHAR_LAYOUT,
@ -1982,6 +2021,7 @@ fn str_concat<'a, 'ctx, 'env>(
let if_second_str_is_empty = || {
let (new_wrapper, _) = clone_nonempty_list(
env,
inplace,
first_str_len,
load_list_ptr(builder, first_str_wrapper, ptr_type),
&CHAR_LAYOUT,
@ -1999,7 +2039,7 @@ fn str_concat<'a, 'ctx, 'env>(
let combined_str_len =
builder.build_int_add(first_str_len, second_str_len, "add_list_lengths");
let combined_str_ptr = allocate_list(env, &CHAR_LAYOUT, combined_str_len);
let combined_str_ptr = allocate_list(env, inplace, &CHAR_LAYOUT, combined_str_len);
// FIRST LOOP
let first_str_ptr = load_list_ptr(builder, first_str_wrapper, ptr_type);

View File

@ -17,7 +17,7 @@ fn get_list_element_type<'a, 'b>(layout: &'b Layout<'a>) -> Option<&'b Layout<'a
/// List.single : a -> List a
pub fn list_single<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout: &Layout<'a>,
inplace: InPlace,
elem: BasicValueEnum<'ctx>,
elem_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
@ -26,7 +26,8 @@ pub fn list_single<'a, 'ctx, 'env>(
// allocate a list of size 1 on the heap
let size = ctx.i64_type().const_int(1, false);
let ptr = allocate_list(env, elem_layout, size);
let ptr = allocate_list(env, inplace, elem_layout, size);
// Put the element into the list
let elem_ptr = unsafe {
@ -48,6 +49,7 @@ pub fn list_single<'a, 'ctx, 'env>(
/// List.repeat : Int, elem -> List elem
pub fn list_repeat<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
inplace: InPlace,
parent: FunctionValue<'ctx>,
list_len: IntValue<'ctx>,
elem: BasicValueEnum<'ctx>,
@ -72,7 +74,7 @@ pub fn list_repeat<'a, 'ctx, 'env>(
let build_then = || {
// Allocate space for the new array that we'll copy into.
let list_ptr = allocate_list(env, elem_layout, list_len);
let list_ptr = allocate_list(env, inplace, elem_layout, list_len);
// TODO check if malloc returned null; if so, runtime error for OOM!
let index_name = "#index";
@ -137,6 +139,7 @@ pub fn list_repeat<'a, 'ctx, 'env>(
/// List.prepend List elem, elem -> List elem
pub fn list_prepend<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
inplace: InPlace,
original_wrapper: StructValue<'ctx>,
elem: BasicValueEnum<'ctx>,
elem_layout: &Layout<'a>,
@ -158,7 +161,7 @@ pub fn list_prepend<'a, 'ctx, 'env>(
);
// Allocate space for the new array that we'll copy into.
let clone_ptr = allocate_list(env, elem_layout, new_list_len);
let clone_ptr = allocate_list(env, inplace, elem_layout, new_list_len);
builder.build_store(clone_ptr, elem);
@ -199,6 +202,7 @@ pub fn list_prepend<'a, 'ctx, 'env>(
/// List.join : List (List elem) -> List elem
pub fn list_join<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
inplace: InPlace,
parent: FunctionValue<'ctx>,
outer_list: BasicValueEnum<'ctx>,
outer_list_layout: &Layout<'a>,
@ -276,7 +280,7 @@ pub fn list_join<'a, 'ctx, 'env>(
.build_load(list_len_sum_alloca, list_len_sum_name)
.into_int_value();
let final_list_ptr = allocate_list(env, elem_layout, final_list_sum);
let final_list_ptr = allocate_list(env, inplace, elem_layout, final_list_sum);
let dest_elem_ptr_alloca = builder.build_alloca(elem_ptr_type, "dest_elem");
@ -377,7 +381,7 @@ pub fn list_join<'a, 'ctx, 'env>(
pub fn list_reverse_help<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
parent: FunctionValue<'ctx>,
in_place: InPlace,
inplace: InPlace,
length: IntValue<'ctx>,
source_ptr: PointerValue<'ctx>,
dest_ptr: PointerValue<'ctx>,
@ -406,7 +410,7 @@ pub fn list_reverse_help<'a, 'ctx, 'env>(
// if updating in-place, then the "middle element" can be left untouched
// otherwise, the middle element needs to be copied over from the source to the target
let predicate = match in_place {
let predicate = match inplace {
InPlace::InPlace => IntPredicate::SGT,
InPlace::Clone => IntPredicate::SGE,
};
@ -430,7 +434,7 @@ pub fn list_reverse_help<'a, 'ctx, 'env>(
let high_value = builder.build_load(high_ptr, "load_high");
// swap the two values
if let InPlace::Clone = in_place {
if let InPlace::Clone = inplace {
low_ptr = unsafe { builder.build_in_bounds_gep(dest_ptr, &[low], "low_ptr") };
high_ptr = unsafe { builder.build_in_bounds_gep(dest_ptr, &[high], "high_ptr") };
}
@ -451,7 +455,7 @@ pub fn list_reverse_help<'a, 'ctx, 'env>(
pub fn list_reverse<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
parent: FunctionValue<'ctx>,
in_place: InPlace,
output_inplace: InPlace,
list: BasicValueEnum<'ctx>,
list_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
@ -461,12 +465,21 @@ pub fn list_reverse<'a, 'ctx, 'env>(
let ctx = env.context;
let wrapper_struct = list.into_struct_value();
let element_layout = match get_list_element_type(list_layout) {
Some(element_layout) => element_layout.clone(),
None => {
let (input_inplace, element_layout) = match list_layout.clone() {
Layout::Builtin(Builtin::EmptyList) => (
InPlace::InPlace,
// this pointer will never actually be dereferenced
Layout::Builtin(Builtin::Int64)
}
Layout::Builtin(Builtin::Int64),
),
Layout::Builtin(Builtin::List(memory_mode, elem_layout)) => (
match memory_mode {
MemoryMode::Unique => InPlace::InPlace,
MemoryMode::Refcounted => InPlace::Clone,
},
elem_layout.clone(),
),
_ => unreachable!("Invalid layout {:?} in List.reverse", list_layout),
};
let list_type = basic_type_from_layout(env.arena, env.context, &element_layout, env.ptr_bytes);
@ -475,9 +488,9 @@ pub fn list_reverse<'a, 'ctx, 'env>(
let list_ptr = load_list_ptr(builder, wrapper_struct, ptr_type);
let length = list_len(builder, list.into_struct_value());
match in_place {
match input_inplace {
InPlace::InPlace => {
list_reverse_help(env, parent, in_place, length, list_ptr, list_ptr);
list_reverse_help(env, parent, input_inplace, length, list_ptr, list_ptr);
list
}
@ -512,7 +525,7 @@ pub fn list_reverse<'a, 'ctx, 'env>(
{
builder.position_at_end(len_1_block);
let new_list_ptr = clone_list(env, &element_layout, one, list_ptr);
let new_list_ptr = clone_list(env, output_inplace, &element_layout, one, list_ptr);
builder.build_store(result, new_list_ptr);
builder.build_unconditional_branch(cont_block);
@ -522,7 +535,7 @@ pub fn list_reverse<'a, 'ctx, 'env>(
{
builder.position_at_end(len_n_block);
let new_list_ptr = allocate_list(env, &element_layout, length);
let new_list_ptr = allocate_list(env, output_inplace, &element_layout, length);
list_reverse_help(env, parent, InPlace::Clone, length, list_ptr, new_list_ptr);
@ -574,6 +587,7 @@ pub fn list_get_unsafe<'a, 'ctx, 'env>(
/// List.append : List elem, elem -> List elem
pub fn list_append<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
inplace: InPlace,
original_wrapper: StructValue<'ctx>,
elem: BasicValueEnum<'ctx>,
elem_layout: &Layout<'a>,
@ -609,7 +623,7 @@ pub fn list_append<'a, 'ctx, 'env>(
.build_int_mul(elem_bytes, list_len, "mul_old_len_by_elem_bytes");
// Allocate space for the new array that we'll copy into.
let clone_ptr = allocate_list(env, elem_layout, new_list_len);
let clone_ptr = allocate_list(env, inplace, elem_layout, new_list_len);
// TODO check if malloc returned null; if so, runtime error for OOM!
@ -635,7 +649,7 @@ pub fn list_set<'a, 'ctx, 'env>(
parent: FunctionValue<'ctx>,
args: &[(BasicValueEnum<'ctx>, &'a Layout<'a>)],
env: &Env<'a, 'ctx, 'env>,
in_place: InPlace,
inplace: InPlace,
) -> BasicValueEnum<'ctx> {
let builder = env.builder;
@ -657,13 +671,14 @@ pub fn list_set<'a, 'ctx, 'env>(
let ctx = env.context;
let elem_type = basic_type_from_layout(env.arena, ctx, elem_layout, env.ptr_bytes);
let ptr_type = get_ptr_type(&elem_type, AddressSpace::Generic);
let (new_wrapper, array_data_ptr) = match in_place {
let (new_wrapper, array_data_ptr) = match inplace {
InPlace::InPlace => (
original_wrapper,
load_list_ptr(builder, original_wrapper, ptr_type),
),
InPlace::Clone => clone_nonempty_list(
env,
inplace,
list_len,
load_list_ptr(builder, original_wrapper, ptr_type),
elem_layout,
@ -813,6 +828,7 @@ pub fn list_walk_right<'a, 'ctx, 'env>(
/// List.keepIf : List elem, (elem -> Bool) -> List elem
pub fn list_keep_if<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
inplace: InPlace,
parent: FunctionValue<'ctx>,
func: BasicValueEnum<'ctx>,
func_layout: &Layout<'a>,
@ -903,7 +919,7 @@ pub fn list_keep_if<'a, 'ctx, 'env>(
// Make a new list, with a length equal to the number
// of `elem` that passed the `elem -> Bool` function.
let ret_list_ptr = allocate_list(env, elem_layout, final_ret_list_len);
let ret_list_ptr = allocate_list(env, inplace, elem_layout, final_ret_list_len);
// Make a pointer into the return list. This pointer is used
// below to store elements into return list.
@ -993,6 +1009,7 @@ pub fn list_keep_if<'a, 'ctx, 'env>(
/// List.map : List before, (before -> after) -> List after
pub fn list_map<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
inplace: InPlace,
parent: FunctionValue<'ctx>,
func: BasicValueEnum<'ctx>,
func_layout: &Layout<'a>,
@ -1007,7 +1024,7 @@ pub fn list_map<'a, 'ctx, 'env>(
let ctx = env.context;
let builder = env.builder;
let ret_list_ptr = allocate_list(env, ret_elem_layout, len);
let ret_list_ptr = allocate_list(env, inplace, ret_elem_layout, len);
let elem_type = basic_type_from_layout(env.arena, ctx, elem_layout, env.ptr_bytes);
let ptr_type = get_ptr_type(&elem_type, AddressSpace::Generic);
@ -1054,6 +1071,7 @@ pub fn list_map<'a, 'ctx, 'env>(
/// List.concat : List elem, List elem -> List elem
pub fn list_concat<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
inplace: InPlace,
parent: FunctionValue<'ctx>,
first_list: BasicValueEnum<'ctx>,
second_list: BasicValueEnum<'ctx>,
@ -1095,6 +1113,7 @@ pub fn list_concat<'a, 'ctx, 'env>(
let (new_wrapper, _) = clone_nonempty_list(
env,
inplace,
second_list_len,
load_list_ptr(builder, second_list_wrapper, ptr_type),
elem_layout,
@ -1122,6 +1141,7 @@ pub fn list_concat<'a, 'ctx, 'env>(
let if_second_list_is_empty = || {
let (new_wrapper, _) = clone_nonempty_list(
env,
inplace,
first_list_len,
load_list_ptr(builder, first_list_wrapper, ptr_type),
elem_layout,
@ -1140,7 +1160,8 @@ pub fn list_concat<'a, 'ctx, 'env>(
let combined_list_len =
builder.build_int_add(first_list_len, second_list_len, "add_list_lengths");
let combined_list_ptr = allocate_list(env, elem_layout, combined_list_len);
let combined_list_ptr =
allocate_list(env, inplace, elem_layout, combined_list_len);
let first_list_ptr = load_list_ptr(builder, first_list_wrapper, ptr_type);
@ -1540,6 +1561,7 @@ pub fn load_list_ptr<'ctx>(
pub fn clone_nonempty_list<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
inplace: InPlace,
list_len: IntValue<'ctx>,
elems_ptr: PointerValue<'ctx>,
elem_layout: &Layout<'_>,
@ -1557,7 +1579,7 @@ pub fn clone_nonempty_list<'a, 'ctx, 'env>(
.build_int_mul(elem_bytes, list_len, "clone_mul_len_by_elem_bytes");
// Allocate space for the new array that we'll copy into.
let clone_ptr = allocate_list(env, elem_layout, list_len);
let clone_ptr = allocate_list(env, inplace, elem_layout, list_len);
let int_type = ptr_int(ctx, ptr_bytes);
let ptr_as_int = builder.build_ptr_to_int(clone_ptr, int_type, "list_cast_ptr");
@ -1607,6 +1629,7 @@ pub fn clone_nonempty_list<'a, 'ctx, 'env>(
pub fn clone_list<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
output_inplace: InPlace,
elem_layout: &Layout<'a>,
length: IntValue<'ctx>,
old_ptr: PointerValue<'ctx>,
@ -1615,7 +1638,7 @@ pub fn clone_list<'a, 'ctx, 'env>(
let ptr_bytes = env.ptr_bytes;
// allocate new empty list (with refcount 1)
let new_ptr = allocate_list(env, elem_layout, length);
let new_ptr = allocate_list(env, output_inplace, elem_layout, length);
let stack_size = elem_layout.stack_size(env.ptr_bytes);
let bytes = builder.build_int_mul(
@ -1632,7 +1655,7 @@ pub fn clone_list<'a, 'ctx, 'env>(
pub fn allocate_list<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
// in_place: InPlace,
inplace: InPlace,
elem_layout: &Layout<'a>,
length: IntValue<'ctx>,
) -> PointerValue<'ctx> {