mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 14:24:45 +00:00
List.repeat in zig
This commit is contained in:
parent
32bba5206a
commit
d29b8764f0
9 changed files with 96 additions and 90 deletions
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -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>,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
||||||
// 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 build_then = || {
|
let element_ptr = builder.build_alloca(element.get_type(), "element_ptr");
|
||||||
// Allocate space for the new array that we'll copy into.
|
env.builder.build_store(element_ptr, element);
|
||||||
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";
|
let element_width = env
|
||||||
let start_alloca = builder.build_alloca(ctx.i64_type(), index_name);
|
.ptr_int()
|
||||||
|
.const_int(element_layout.stack_size(env.ptr_bytes) as u64, false);
|
||||||
|
|
||||||
// Start at the last element in the list.
|
let alignment = element_layout.alignment_bytes(env.ptr_bytes);
|
||||||
let last_elem_index = builder.build_int_sub(
|
let alignment_iv = env.ptr_int().const_int(alignment as u64, false);
|
||||||
list_len,
|
let inc_element_fn = build_inc_wrapper(env, layout_ids, element_layout);
|
||||||
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");
|
let output = call_bitcode_fn(
|
||||||
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,
|
env,
|
||||||
parent,
|
&[
|
||||||
comparison,
|
list_len.into(),
|
||||||
build_then,
|
alignment_iv.into(),
|
||||||
build_else,
|
env.builder.build_bitcast(element_ptr, u8_ptr, "to_u8_ptr"),
|
||||||
BasicTypeEnum::StructType(struct_type),
|
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",
|
"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);
|
||||||
|
|
|
@ -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]),
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
|
@ -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 ->
|
|
||||||
when n is
|
|
||||||
1 ->
|
|
||||||
Task.putLine (showBool test1)
|
Task.putLine (showBool test1)
|
||||||
|
# Task.after Task.getInt \n ->
|
||||||
_ ->
|
# when n is
|
||||||
ns = Str.fromInt n
|
# 1 ->
|
||||||
Task.putLine "No test \(ns)"
|
# Task.putLine (showBool test1)
|
||||||
|
#
|
||||||
|
# _ ->
|
||||||
|
# ns = Str.fromInt n
|
||||||
|
# Task.putLine "No test \(ns)"
|
||||||
|
|
||||||
showBool : Bool -> Str
|
showBool : Bool -> Str
|
||||||
showBool = \b ->
|
showBool = \b ->
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue