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 EqFn = fn (?[*]u8, ?[*]u8) callconv(.C) bool;
const Opaque = ?[*]u8; const Opaque = ?[*]u8;
const Inc = fn (?[*]u8) callconv(.C) void;
const Dec = fn (?[*]u8) callconv(.C) void;
pub const RocList = extern struct { pub const RocList = extern struct {
bytes: ?[*]u8, bytes: ?[*]u8,
length: usize, length: usize,
@ -278,3 +281,30 @@ pub fn listContains(list: RocList, key: Opaque, key_width: usize, is_eq: EqFn) c
return false; 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.listKeepOks, "keep_oks");
exportListFn(list.listKeepErrs, "keep_errs"); exportListFn(list.listKeepErrs, "keep_errs");
exportListFn(list.listContains, "contains"); exportListFn(list.listContains, "contains");
exportListFn(list.listRepeat, "repeat");
} }
// Dict Module // 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: &str = "roc_builtins.list.walk";
pub const LIST_WALK_BACKWARDS: &str = "roc_builtins.list.walk_backwards"; pub const LIST_WALK_BACKWARDS: &str = "roc_builtins.list.walk_backwards";
pub const LIST_CONTAINS: &str = "roc_builtins.list.contains"; 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 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>( pub fn build_inc_wrapper<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>, env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>, 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); 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 => { ListReverse => {
// List.reverse : List elem -> List elem // List.reverse : List elem -> List elem

View file

@ -1,6 +1,7 @@
#![allow(clippy::too_many_arguments)] #![allow(clippy::too_many_arguments)]
use crate::llvm::bitcode::{ 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::{ use crate::llvm::build::{
allocate_with_refcount_help, build_num_binop, cast_basic_basic, complex_bitcast, Env, InPlace, 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 /// List.repeat : Int, elem -> List elem
pub fn list_repeat<'a, 'ctx, 'env>( pub fn list_repeat<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>, env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>,
inplace: InPlace, inplace: InPlace,
parent: FunctionValue<'ctx>, parent: FunctionValue<'ctx>,
list_len: IntValue<'ctx>, list_len: IntValue<'ctx>,
elem: BasicValueEnum<'ctx>, element: BasicValueEnum<'ctx>,
elem_layout: &Layout<'a>, element_layout: &Layout<'a>,
) -> BasicValueEnum<'ctx> { ) -> BasicValueEnum<'ctx> {
let builder = env.builder; let builder = env.builder;
let ctx = env.context;
// list_len > 0 let u8_ptr = env.context.i8_type().ptr_type(AddressSpace::Generic);
// We have to do a loop below, continuously adding the `elem`
// to the output list `List elem` until we have reached the let element_ptr = builder.build_alloca(element.get_type(), "element_ptr");
// number of repeats. This `comparison` is used to check env.builder.build_store(element_ptr, element);
// if we need to do any looping; because if we dont, then we
// dont need to allocate memory for the index or the check let element_width = env
// if index != 0 .ptr_int()
let comparison = builder.build_int_compare( .const_int(element_layout.stack_size(env.ptr_bytes) as u64, false);
IntPredicate::UGT,
list_len, let alignment = element_layout.alignment_bytes(env.ptr_bytes);
ctx.i64_type().const_int(0, false), let alignment_iv = env.ptr_int().const_int(alignment as u64, false);
"atleastzero", let inc_element_fn = build_inc_wrapper(env, layout_ids, element_layout);
let output = call_bitcode_fn(
env,
&[
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,
); );
let build_then = || { complex_bitcast(
// Allocate space for the new array that we'll copy into. env.builder,
let list_ptr = allocate_list(env, inplace, elem_layout, list_len); output,
// TODO check if malloc returned null; if so, runtime error for OOM! collection(env.context, env.ptr_bytes).into(),
"from_i128",
let index_name = "#index";
let start_alloca = builder.build_alloca(ctx.i64_type(), index_name);
// 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 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(
env,
parent,
comparison,
build_then,
build_else,
BasicTypeEnum::StructType(struct_type),
) )
} }
@ -1532,7 +1488,7 @@ where
"bounds_check", "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.build_conditional_branch(condition, loop_bb, after_loop_bb);
builder.position_at_end(after_loop_bb); builder.position_at_end(after_loop_bb);
@ -1599,7 +1555,7 @@ where
// #index < end // #index < end
let loop_end_cond = bounds_check_comparison(builder, next_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.build_conditional_branch(loop_end_cond, loop_bb, after_loop_bb);
builder.position_at_end(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]), ListConcat | StrConcat => arena.alloc_slice_copy(&[owned, borrowed]),
StrSplit => arena.alloc_slice_copy(&[borrowed, borrowed]), StrSplit => arena.alloc_slice_copy(&[borrowed, borrowed]),
ListSingle => arena.alloc_slice_copy(&[irrelevant]), 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]), ListReverse => arena.alloc_slice_copy(&[owned]),
ListPrepend => arena.alloc_slice_copy(&[owned, owned]), ListPrepend => arena.alloc_slice_copy(&[owned, owned]),
StrJoinWith => arena.alloc_slice_copy(&[irrelevant, irrelevant]), 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 std::collections::HashMap;
use ven_pretty::{BoxAllocator, DocAllocator, DocBuilder}; 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 { macro_rules! return_on_layout_error {
($env:expr, $layout_result:expr) => { ($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.Task {} []
main = main =
Task.after Task.getInt \n -> Task.putLine (showBool test1)
when n is # Task.after Task.getInt \n ->
1 -> # when n is
Task.putLine (showBool test1) # 1 ->
# Task.putLine (showBool test1)
_ -> #
ns = Str.fromInt n # _ ->
Task.putLine "No test \(ns)" # ns = Str.fromInt n
# Task.putLine "No test \(ns)"
showBool : Bool -> Str showBool : Bool -> Str
showBool = \b -> showBool = \b ->