array literal assignment optimization
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 4 Jan 2021 20:15:30 +0000 (14:15 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 4 Jan 2021 20:15:30 +0000 (14:15 -0600)
bin/onyx
progs/odin_example.onyx
src/onyxwasm.c

index 6ea6feebf02c890c805e4a8d137968b5a8c11245..08a86280a1d7502212ba9f29e3ba1b2b6185cf29 100755 (executable)
Binary files a/bin/onyx and b/bin/onyx differ
index 7dd0778f1895bec4d92c45ba1e4bb837140f1e14..8791accbe0f1140152af30a6f4031a1f12f9d174 100644 (file)
@@ -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; }));
     }
 
index ebed5db1fdcfd203aaa9bd60f4a3205aca7e595c..b95bb834858e52414a9766bb6f4c0887c0140d11 100644 (file)
@@ -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;