List.repeat in zig

This commit is contained in:
Folkert 2021-02-18 23:39:50 +01:00
parent 32bba5206a
commit d29b8764f0
9 changed files with 96 additions and 90 deletions

View file

@ -7,6 +7,9 @@ const Allocator = mem.Allocator;
const EqFn = fn (?[*]u8, ?[*]u8) callconv(.C) bool;
const Opaque = ?[*]u8;
const Inc = fn (?[*]u8) callconv(.C) void;
const Dec = fn (?[*]u8) callconv(.C) void;
pub const RocList = extern struct {
bytes: ?[*]u8,
length: usize,
@ -278,3 +281,30 @@ pub fn listContains(list: RocList, key: Opaque, key_width: usize, is_eq: EqFn) c
return false;
}
pub fn listRepeat(count: usize, alignment: usize, element: Opaque, element_width: usize, inc_n_element: Inc) callconv(.C) RocList {
if (count == 0) {
return RocList.empty();
}
const allocator = std.heap.c_allocator;
var output = RocList.allocate(allocator, alignment, count, element_width);
if (output.bytes) |target_ptr| {
var i: usize = 0;
const source = element orelse unreachable;
while (i < count) : (i += 1) {
@memcpy(target_ptr + i * element_width, source, element_width);
}
// TODO do all increments at once!
i = 0;
while (i < count) : (i += 1) {
inc_n_element(element);
}
return output;
} else {
unreachable;
}
}

View file

@ -14,6 +14,7 @@ comptime {
exportListFn(list.listKeepOks, "keep_oks");
exportListFn(list.listKeepErrs, "keep_errs");
exportListFn(list.listContains, "contains");
exportListFn(list.listRepeat, "repeat");
}
// Dict Module

View file

@ -67,3 +67,4 @@ pub const LIST_KEEP_ERRS: &str = "roc_builtins.list.keep_errs";
pub const LIST_WALK: &str = "roc_builtins.list.walk";
pub const LIST_WALK_BACKWARDS: &str = "roc_builtins.list.walk_backwards";
pub const LIST_CONTAINS: &str = "roc_builtins.list.contains";
pub const LIST_REPEAT: &str = "roc_builtins.list.repeat";

View file

@ -207,6 +207,15 @@ fn build_transform_caller_help<'a, 'ctx, 'env>(
function_value
}
pub fn build_inc_n_wrapper<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>,
layout: &Layout<'a>,
n: u64,
) -> FunctionValue<'ctx> {
build_rc_wrapper(env, layout_ids, layout, Mode::Inc(n))
}
pub fn build_inc_wrapper<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>,

View file

@ -3597,7 +3597,15 @@ fn run_low_level<'a, 'ctx, 'env>(
let inplace = get_inplace_from_layout(layout);
list_repeat(env, inplace, parent, list_len, elem, elem_layout)
list_repeat(
env,
layout_ids,
inplace,
parent,
list_len,
elem,
elem_layout,
)
}
ListReverse => {
// List.reverse : List elem -> List elem

View file

@ -1,6 +1,7 @@
#![allow(clippy::too_many_arguments)]
use crate::llvm::bitcode::{
build_eq_wrapper, build_transform_caller, call_bitcode_fn, call_void_bitcode_fn,
build_eq_wrapper, build_inc_wrapper, build_transform_caller, call_bitcode_fn,
call_void_bitcode_fn,
};
use crate::llvm::build::{
allocate_with_refcount_help, build_num_binop, cast_basic_basic, complex_bitcast, Env, InPlace,
@ -53,90 +54,45 @@ 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>,
layout_ids: &mut LayoutIds<'a>,
inplace: InPlace,
parent: FunctionValue<'ctx>,
list_len: IntValue<'ctx>,
elem: BasicValueEnum<'ctx>,
elem_layout: &Layout<'a>,
element: BasicValueEnum<'ctx>,
element_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> {
let builder = env.builder;
let ctx = env.context;
// list_len > 0
// We have to do a loop below, continuously adding the `elem`
// to the output list `List elem` until we have reached the
// number of repeats. This `comparison` is used to check
// if we need to do any looping; because if we dont, then we
// dont need to allocate memory for the index or the check
// if index != 0
let comparison = builder.build_int_compare(
IntPredicate::UGT,
list_len,
ctx.i64_type().const_int(0, false),
"atleastzero",
);
let u8_ptr = env.context.i8_type().ptr_type(AddressSpace::Generic);
let build_then = || {
// Allocate space for the new array that we'll copy into.
let list_ptr = allocate_list(env, inplace, elem_layout, list_len);
// TODO check if malloc returned null; if so, runtime error for OOM!
let element_ptr = builder.build_alloca(element.get_type(), "element_ptr");
env.builder.build_store(element_ptr, element);
let index_name = "#index";
let start_alloca = builder.build_alloca(ctx.i64_type(), index_name);
let element_width = env
.ptr_int()
.const_int(element_layout.stack_size(env.ptr_bytes) as u64, false);
// Start at the last element in the list.
let last_elem_index = builder.build_int_sub(
list_len,
ctx.i64_type().const_int(1, false),
"lastelemindex",
);
builder.build_store(start_alloca, last_elem_index);
let alignment = element_layout.alignment_bytes(env.ptr_bytes);
let alignment_iv = env.ptr_int().const_int(alignment as u64, false);
let inc_element_fn = build_inc_wrapper(env, layout_ids, element_layout);
let loop_bb = ctx.append_basic_block(parent, "loop");
builder.build_unconditional_branch(loop_bb);
builder.position_at_end(loop_bb);
// #index = #index - 1
let curr_index = builder
.build_load(start_alloca, index_name)
.into_int_value();
let next_index =
builder.build_int_sub(curr_index, ctx.i64_type().const_int(1, false), "nextindex");
builder.build_store(start_alloca, next_index);
let elem_ptr =
unsafe { builder.build_in_bounds_gep(list_ptr, &[curr_index], "load_index") };
// Mutate the new array in-place to change the element.
builder.build_store(elem_ptr, elem);
// #index != 0
let end_cond = builder.build_int_compare(
IntPredicate::NE,
ctx.i64_type().const_int(0, false),
curr_index,
"loopcond",
);
let after_bb = ctx.append_basic_block(parent, "afterloop");
builder.build_conditional_branch(end_cond, loop_bb, after_bb);
builder.position_at_end(after_bb);
store_list(env, list_ptr, list_len)
};
let build_else = || empty_polymorphic_list(env);
let struct_type = collection(ctx, env.ptr_bytes);
build_basic_phi2(
let output = call_bitcode_fn(
env,
parent,
comparison,
build_then,
build_else,
BasicTypeEnum::StructType(struct_type),
&[
list_len.into(),
alignment_iv.into(),
env.builder.build_bitcast(element_ptr, u8_ptr, "to_u8_ptr"),
element_width.into(),
inc_element_fn.as_global_value().as_pointer_value().into(),
],
bitcode::LIST_REPEAT,
);
complex_bitcast(
env.builder,
output,
collection(env.context, env.ptr_bytes).into(),
"from_i128",
)
}
@ -1532,7 +1488,7 @@ where
"bounds_check",
);
let after_loop_bb = ctx.append_basic_block(parent, "after_outer_loop");
let after_loop_bb = ctx.append_basic_block(parent, "after_outer_loop_1");
builder.build_conditional_branch(condition, loop_bb, after_loop_bb);
builder.position_at_end(after_loop_bb);
@ -1599,7 +1555,7 @@ where
// #index < end
let loop_end_cond = bounds_check_comparison(builder, next_index, end);
let after_loop_bb = ctx.append_basic_block(parent, "after_outer_loop");
let after_loop_bb = ctx.append_basic_block(parent, "after_outer_loop_2");
builder.build_conditional_branch(loop_end_cond, loop_bb, after_loop_bb);
builder.position_at_end(after_loop_bb);

View file

@ -635,7 +635,7 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
ListConcat | StrConcat => arena.alloc_slice_copy(&[owned, borrowed]),
StrSplit => arena.alloc_slice_copy(&[borrowed, borrowed]),
ListSingle => arena.alloc_slice_copy(&[irrelevant]),
ListRepeat => arena.alloc_slice_copy(&[irrelevant, irrelevant]),
ListRepeat => arena.alloc_slice_copy(&[irrelevant, borrowed]),
ListReverse => arena.alloc_slice_copy(&[owned]),
ListPrepend => arena.alloc_slice_copy(&[owned, owned]),
StrJoinWith => arena.alloc_slice_copy(&[irrelevant, irrelevant]),

View file

@ -17,7 +17,7 @@ use roc_types::subs::{Content, FlatType, Subs, Variable};
use std::collections::HashMap;
use ven_pretty::{BoxAllocator, DocAllocator, DocBuilder};
pub const PRETTY_PRINT_IR_SYMBOLS: bool = false;
pub const PRETTY_PRINT_IR_SYMBOLS: bool = true;
macro_rules! return_on_layout_error {
($env:expr, $layout_result:expr) => {

View file

@ -9,14 +9,15 @@ fromList = \list -> List.walk list (\x, a -> Set.insert a x) Set.empty
main : Task.Task {} []
main =
Task.after Task.getInt \n ->
when n is
1 ->
Task.putLine (showBool test1)
_ ->
ns = Str.fromInt n
Task.putLine "No test \(ns)"
# Task.after Task.getInt \n ->
# when n is
# 1 ->
# Task.putLine (showBool test1)
#
# _ ->
# ns = Str.fromInt n
# Task.putLine "No test \(ns)"
showBool : Bool -> Str
showBool = \b ->