From: Brendan Hansen Date: Mon, 4 Jan 2021 20:15:30 +0000 (-0600) Subject: array literal assignment optimization X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=483d6200c69cf6c490ee09f089d1cc28686c18dc;p=onyx.git array literal assignment optimization --- diff --git a/bin/onyx b/bin/onyx index 6ea6feeb..08a86280 100755 Binary files a/bin/onyx and b/bin/onyx differ diff --git a/progs/odin_example.onyx b/progs/odin_example.onyx index 7dd0778f..8791accb 100644 --- a/progs/odin_example.onyx +++ b/progs/odin_example.onyx @@ -85,6 +85,14 @@ BadUnion :: struct { Vec2 :: struct { x: i32; y: i32; } Entity :: struct { use pos: Vec2; } +array_literal_optim :: proc () #export { + // This needs to be optimized + bar : [5] u32; + bar = u32.[ 1, 2, 3, 4, 5 ]; + bar[2] = 1234; + for b: bar do printf("b: %i\n", b); +} + main :: proc (args: [] cstr) { a : BadUnion; a.int = 1234; @@ -100,14 +108,11 @@ main :: proc (args: [] cstr) { foo : [5] [2] u32; foo = f(); + array_literal_optim(); + printf("%p == %p\n", cast(^u32) foo, ^foo); for ^thing: foo do for t: *thing do printf("%p %i\n", thing, t); - // This needs to be optimized - bar := u32.[ 1, 2, 3, 4, 5 ]; - bar[2] = 1234; - for b: bar do printf("b: %i\n", b); - println(compress(f32.[ 1, 2, 3, 4, 5 ], proc (a: $T, b: T) -> T { return a + b; })); } diff --git a/src/onyxwasm.c b/src/onyxwasm.c index ebed5db1..b95bb834 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -369,6 +369,7 @@ EMIT_FUNC(function_body, AstFunction* fd); EMIT_FUNC(block, AstBlock* block, b32 generate_block_headers); EMIT_FUNC(statement, AstNode* stmt); EMIT_FUNC(assignment, AstBinaryOp* assign); +EMIT_FUNC(assignment_of_array, AstBinaryOp* assign); EMIT_FUNC(store_instruction, Type* type, u32 offset); EMIT_FUNC(load_instruction, Type* type, u32 offset); EMIT_FUNC(if, AstIfWhile* if_node); @@ -496,50 +497,7 @@ EMIT_FUNC(assignment, AstBinaryOp* assign) { } if (assign->right->type->kind == Type_Kind_Array) { - Type* rtype = assign->right->type; - - Type* elem_type = rtype; - u32 elem_count = 1; - while (elem_type->kind == Type_Kind_Array) { - elem_count *= elem_type->Array.count; - elem_type = elem_type->Array.elem; - } - u32 elem_size = type_size_of(elem_type); - - u64 lptr_local = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32); - u64 rptr_local = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32); - - emit_location(mod, &code, assign->left); - WIL(WI_LOCAL_SET, lptr_local); - - emit_expression(mod, &code, assign->right); - WIL(WI_LOCAL_SET, rptr_local); - - // NOTE: Currently, we inline the copying of the array; But if the array has - // many elements, this could result in a LOT of instructions. Maybe for lengths - // greater than like 16 we output a loop that copies them? - // - brendanfh 2020/12/16 - fori (i, 0, elem_count) { - if (!type_is_structlike(elem_type)) - WIL(WI_LOCAL_GET, lptr_local); - - if (bh_arr_last(code).type == WI_LOCAL_SET && bh_arr_last(code).data.l == rptr_local) - bh_arr_last(code).type = WI_LOCAL_TEE; - else - WIL(WI_LOCAL_GET, rptr_local); - emit_load_instruction(mod, &code, elem_type, i * elem_size); - - if (!type_is_structlike(elem_type)) { - emit_store_instruction(mod, &code, elem_type, i * elem_size); - } else { - WIL(WI_LOCAL_GET, lptr_local); - emit_store_instruction(mod, &code, elem_type, i * elem_size); - } - } - - local_raw_free(mod->local_alloc, WASM_TYPE_INT32); - local_raw_free(mod->local_alloc, WASM_TYPE_INT32); - + emit_assignment_of_array(mod, &code, assign); *pcode = code; return; } @@ -604,6 +562,83 @@ EMIT_FUNC(assignment, AstBinaryOp* assign) { *pcode = code; } +EMIT_FUNC(assignment_of_array, AstBinaryOp* assign) { + bh_arr(WasmInstruction) code = *pcode; + + Type* rtype = assign->right->type; + assert(rtype->kind == Type_Kind_Array); + + Type* elem_type = rtype; + u32 elem_count = 1; + while (elem_type->kind == Type_Kind_Array) { + elem_count *= elem_type->Array.count; + elem_type = elem_type->Array.elem; + } + u32 elem_size = type_size_of(elem_type); + + if (assign->right->kind == Ast_Kind_Array_Literal) { + u64 lptr_local = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32); + + emit_location(mod, &code, assign->left); + WIL(WI_LOCAL_SET, lptr_local); + + AstArrayLiteral* al = (AstArrayLiteral *) assign->right; + fori (i, 0, elem_count) { + if (!type_is_structlike(elem_type)) + WIL(WI_LOCAL_GET, lptr_local); + + emit_expression(mod, &code, al->values[i]); + + if (!type_is_structlike(elem_type)) { + emit_store_instruction(mod, &code, elem_type, i * elem_size); + } else { + WIL(WI_LOCAL_GET, lptr_local); + emit_store_instruction(mod, &code, elem_type, i * elem_size); + } + } + + local_raw_free(mod->local_alloc, WASM_TYPE_INT32); + + } else { + u64 lptr_local = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32); + u64 rptr_local = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32); + + emit_location(mod, &code, assign->left); + WIL(WI_LOCAL_SET, lptr_local); + + emit_expression(mod, &code, assign->right); + WIL(WI_LOCAL_SET, rptr_local); + + // NOTE: Currently, we inline the copying of the array; But if the array has + // many elements, this could result in a LOT of instructions. Maybe for lengths + // greater than like 16 we output a loop that copies them? + // - brendanfh 2020/12/16 + fori (i, 0, elem_count) { + if (!type_is_structlike(elem_type)) + WIL(WI_LOCAL_GET, lptr_local); + + if (bh_arr_last(code).type == WI_LOCAL_SET && bh_arr_last(code).data.l == rptr_local) + bh_arr_last(code).type = WI_LOCAL_TEE; + else + WIL(WI_LOCAL_GET, rptr_local); + emit_load_instruction(mod, &code, elem_type, i * elem_size); + + if (!type_is_structlike(elem_type)) { + emit_store_instruction(mod, &code, elem_type, i * elem_size); + } else { + WIL(WI_LOCAL_GET, lptr_local); + emit_store_instruction(mod, &code, elem_type, i * elem_size); + } + } + + local_raw_free(mod->local_alloc, WASM_TYPE_INT32); + local_raw_free(mod->local_alloc, WASM_TYPE_INT32); + } + + *pcode = code; + return; +} + EMIT_FUNC(store_instruction, Type* type, u32 offset) { bh_arr(WasmInstruction) code = *pcode;