add list-product builtin function

This commit is contained in:
Peter Fields 2021-03-27 20:15:16 +00:00
parent 47ddfd2639
commit fed470b316
7 changed files with 102 additions and 17 deletions

View file

@ -788,6 +788,81 @@ pub fn list_sum<'a, 'ctx, 'env>(
builder.build_load(accum_alloca, "load_final_acum")
}
/// List.product : List (Num a) -> Num a
pub fn list_product<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
parent: FunctionValue<'ctx>,
list: BasicValueEnum<'ctx>,
default_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
let ctx = env.context;
let builder = env.builder;
let list_wrapper = list.into_struct_value();
let len = list_len(env.builder, list_wrapper);
let accum_type = basic_type_from_layout(env.arena, ctx, default_layout, env.ptr_bytes);
let accum_alloca = builder.build_alloca(accum_type, "alloca_walk_right_accum");
let default: BasicValueEnum = match accum_type {
BasicTypeEnum::IntType(int_type) => int_type.const_int(1,false).into(),
BasicTypeEnum::FloatType(float_type) => float_type.const_float(1.0).into(),
_ => unreachable!(""),
};
builder.build_store(accum_alloca, default);
let then_block = ctx.append_basic_block(parent, "then");
let cont_block = ctx.append_basic_block(parent, "branchcont");
let condition = builder.build_int_compare(
IntPredicate::UGT,
len,
ctx.i64_type().const_zero(),
"list_non_empty",
);
builder.build_conditional_branch(condition, then_block, cont_block);
builder.position_at_end(then_block);
let elem_ptr_type = get_ptr_type(&accum_type, AddressSpace::Generic);
let list_ptr = load_list_ptr(builder, list_wrapper, elem_ptr_type);
let walk_right_loop = |_, elem: BasicValueEnum<'ctx>| {
// load current accumulator
let current = builder.build_load(accum_alloca, "retrieve_accum");
let new_current = build_num_binop(
env,
parent,
current,
default_layout,
elem,
default_layout,
roc_module::low_level::LowLevel::NumMul,
);
builder.build_store(accum_alloca, new_current);
};
incrementing_elem_loop(
builder,
ctx,
parent,
list_ptr,
len,
"#index",
walk_right_loop,
);
builder.build_unconditional_branch(cont_block);
builder.position_at_end(cont_block);
builder.build_load(accum_alloca, "load_final_acum")
}
/// List.walk : List elem, (elem -> accum -> accum), accum -> accum
pub fn list_walk<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,