From: Brendan Hansen Date: Sat, 5 Sep 2020 04:24:05 +0000 (-0500) Subject: added for loop iteration over slices and dynamic arrays X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=7353de7b5094be95084c2420a7f775438185fa50;p=onyx.git added for loop iteration over slices and dynamic arrays --- diff --git a/core/builtin.onyx b/core/builtin.onyx index b07fe7d6..a867c8d1 100644 --- a/core/builtin.onyx +++ b/core/builtin.onyx @@ -5,6 +5,8 @@ cstring :: #type ^u8; Buffer :: #type []void; +// NOTE: Because of many implementation details, all fields of this +// struct are required to be i32's. range :: struct { low : i32; high : i32; diff --git a/onyx b/onyx index 135af032..93a0ad26 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/poly_test.onyx b/progs/poly_test.onyx index 2da51158..78ba3807 100644 --- a/progs/poly_test.onyx +++ b/progs/poly_test.onyx @@ -49,16 +49,19 @@ compose :: proc (a: A, f: proc ($A) -> $B, g: proc (B) -> $C) -> C { SOA :: struct { a : [..] i32; b : [..] i64; + c : [..] V2; } soa_init :: proc (s: ^SOA) { array_init(^s.a); array_init(^s.b); + array_init(^s.c); } soa_deinit :: proc (s: ^SOA) { array_free(^s.a); array_free(^s.b); + array_free(^s.c); } get_range :: proc (arr: ^[..] $T) -> range { @@ -82,6 +85,15 @@ by :: proc (r: range, s: u32) -> range { return range.{ low = r.low, high = r.high, step = s }; } +V2 :: struct { x: i32; y: i32; } +print_v2 :: proc (v: V2) #add_overload print { + print("V2("); + print(v.x); + print(", "); + print(v.y); + print(")"); +} + main :: proc (args: [] cstring) { res := compose(5, proc (x: i32) -> i32 do return x * 3;, proc (x: i32) -> i32 do return x + 5;); @@ -108,12 +120,20 @@ main :: proc (args: [] cstring) { for i: 0 .. 100 { array_push(^s.a, (5 * i) % 21); array_push(^s.b, 3l * cast(i64) i); + array_push(^s.c, V2.{ i, i * i }); } r := ^s.a |> get_range() |> by(3); print(r); print_array(^s.a); + for vec: s.c { + print(vec); + print(" "); + } + print("\n"); + + array_sort(^s.a, cmp_dec); array_sort(^s.b, cmp_dec); diff --git a/src/onyxchecker.c b/src/onyxchecker.c index 52467ffb..3fed3fcc 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -108,8 +108,21 @@ b32 check_for(AstFor* fornode) { // NOTE: Blindly copy the first range member's type which will // be the low value. - brendanfh 2020/09/04 fornode->var->type = builtin_range_type_type->Struct.memarr[0]->type; - fornode->loop_type = For_Loop_Range; + + } + else if (iter_type->kind == Type_Kind_Slice) { + can_iterate = 1; + + fornode->var->type = iter_type->Slice.ptr_to_data->Pointer.elem; + fornode->loop_type = For_Loop_Slice; + + } + else if (iter_type->kind == Type_Kind_DynArray) { + can_iterate = 1; + + fornode->var->type = iter_type->DynArray.ptr_to_data->Pointer.elem; + fornode->loop_type = For_Loop_DynArr; } if (!can_iterate) { diff --git a/src/onyxwasm.c b/src/onyxwasm.c index ac45c468..1b6237eb 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -763,12 +763,13 @@ EMIT_FUNC(for_range, AstFor* for_node, u64 iter_local) { WIL(WI_LOCAL_SET, step_local); WIL(WI_LOCAL_SET, high_local); - WIL(WI_LOCAL_SET, low_local); if (it_is_local) { - WIL(WI_LOCAL_GET, low_local); + WIL(WI_LOCAL_TEE, low_local); WIL(WI_LOCAL_SET, iter_local); + } else { + WIL(WI_LOCAL_SET, low_local); emit_local_location(mod, &code, var, &offset); WIL(WI_LOCAL_GET, low_local); emit_store_instruction(mod, &code, var->type, offset); @@ -833,6 +834,96 @@ EMIT_FUNC(for_range, AstFor* for_node, u64 iter_local) { *pcode = code; } +EMIT_FUNC(for_slice, AstFor* for_node, u64 iter_local) { + bh_arr(WasmInstruction) code = *pcode; + + // NOTE: This implementation is only for loops by value, not by pointer. + + // At this point the stack will look like: + // data + // count + // + // The locals we need to have: + // end_ptr + // start_ptr + // + + u64 end_ptr_local = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32); + u64 ptr_local = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32); + + AstLocal* var = for_node->var; + u64 elem_size = type_size_of(var->type); + b32 it_is_local = (b32) ((iter_local & LOCAL_IS_WASM) != 0); + u64 offset = 0; + + WIL(WI_LOCAL_SET, end_ptr_local); + WIL(WI_LOCAL_TEE, ptr_local); + WIL(WI_LOCAL_GET, end_ptr_local); + if (elem_size != 1) { + WID(WI_I32_CONST, elem_size); + WI(WI_I32_MUL); + } + WI(WI_I32_ADD); + WIL(WI_LOCAL_SET, end_ptr_local); + + WID(WI_BLOCK_START, 0x40); + WID(WI_LOOP_START, 0x40); + WID(WI_BLOCK_START, 0x40); + + bh_arr_push(mod->structured_jump_target, 1); + bh_arr_push(mod->structured_jump_target, 0); + bh_arr_push(mod->structured_jump_target, 2); + + WIL(WI_LOCAL_GET, ptr_local); + WIL(WI_LOCAL_GET, end_ptr_local); + WI(WI_I32_GE_S); + WID(WI_COND_JUMP, 0x02); + + // NOTE: Storing structs requires that the location to store it is, + // the top most thing on the stack. Everything requires it to be + // 'under' the other element being stored. -brendanfh 2020/09/04 + if (!it_is_local && var->type->kind != Type_Kind_Struct) { + emit_local_location(mod, &code, var, &offset); + } + + WIL(WI_LOCAL_GET, ptr_local); + emit_load_instruction(mod, &code, var->type, 0); + if (it_is_local) { + WIL(WI_LOCAL_SET, iter_local); + } else { + if (var->type->kind != Type_Kind_Struct) { + emit_store_instruction(mod, &code, var->type, offset); + } else { + emit_local_location(mod, &code, var, &offset); + emit_store_instruction(mod, &code, var->type, offset); + } + } + + emit_block(mod, &code, for_node->stmt, 0); + + bh_arr_pop(mod->structured_jump_target); + WI(WI_BLOCK_END); + + WIL(WI_LOCAL_GET, ptr_local); + WIL(WI_I32_CONST, elem_size); + WI(WI_I32_ADD); + WIL(WI_LOCAL_SET, ptr_local); + + bh_arr_pop(mod->structured_jump_target); + bh_arr_pop(mod->structured_jump_target); + + if (bh_arr_last(code).type != WI_JUMP) + WID(WI_JUMP, 0x00); + + WI(WI_LOOP_END); + WI(WI_BLOCK_END); + + local_raw_free(mod->local_alloc, WASM_TYPE_INT32); + local_raw_free(mod->local_alloc, WASM_TYPE_INT32); + + *pcode = code; +} + EMIT_FUNC(for, AstFor* for_node) { bh_arr(WasmInstruction) code = *pcode; @@ -844,6 +935,14 @@ EMIT_FUNC(for, AstFor* for_node) { if (for_node->loop_type == For_Loop_Range) { emit_for_range(mod, &code, for_node, iter_local); + } else if (for_node->loop_type == For_Loop_Slice) { + emit_for_slice(mod, &code, for_node, iter_local); + } else if (for_node->loop_type == For_Loop_DynArr) { + // NOTE: A dynamic array is just a slice with an extra capacity field on the end. + // Just dropping the capacity field will mean we can just use the slice implementation. + // - brendanfh 2020/09/04 + WI(WI_DROP); + emit_for_slice(mod, &code, for_node, iter_local); } else { onyx_report_error(for_node->token->pos, "Invalid for loop type. You should probably not be seeing this..."); }