using wasm local when possible again
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 8 Aug 2020 03:34:42 +0000 (22:34 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 8 Aug 2020 03:34:42 +0000 (22:34 -0500)
docs/plan
include/onyxastnodes.h
include/onyxwasm.h
onyx
progs/alloc.onyx
progs/stack_based.onyx
src/onyxchecker.c
src/onyxwasm.c

index b26d4beb1cdf6097f5d6217f184000367ec0d8e4..94de23d3ed4f6189c0f820d9ad11bd3a4149b47b 100644 (file)
--- a/docs/plan
+++ b/docs/plan
@@ -146,7 +146,7 @@ HOW:
 
         [X] Convert to using a proper stack based system
 
-        [ ] Be smart about when to use the stack versus use the wasm locals
+        [X] Be smart about when to use the stack versus use the wasm locals
 
         [ ] Array literals
 
index 63a1f95d94dedf8e7dac70e5a0fa1ad0dc24e9c9..7844ecff6e838aa016fd5c59462ecbbc9fe615b9 100644 (file)
@@ -149,6 +149,7 @@ typedef enum AstFlags {
     Ast_Flag_Expr_Ignored      = BH_BIT(8),
     Ast_Flag_Param_Splatted    = BH_BIT(9),
     Ast_Flag_Param_Use         = BH_BIT(10),
+    Ast_Flag_Address_Taken     = BH_BIT(11),
 
     // Type flags
     Ast_Flag_Type_Is_Resolved  = BH_BIT(8),
index 4ef2ea3897df0c38c83f9f5e26e611871cdecf6d..e0b74e7122c8a13aaecc7a2981fac8fdfc9a0d46 100644 (file)
@@ -290,6 +290,8 @@ typedef struct DeferredStmt {
     AstNode *stmt;
 } DeferredStmt;
 
+#define LOCAL_IS_WASM 0x8000000000000
+
 typedef struct OnyxWasmModule {
     bh_allocator allocator;
 
@@ -321,6 +323,7 @@ typedef struct OnyxWasmModule {
     bh_arr(WasmDatum)     data;
     bh_arr(i32)           elems;
 
+    // NOTE: Set of things used when compiling; not part of the actual module
     u32 export_count;
     u32 next_type_idx;
     u32 next_func_idx;
@@ -331,6 +334,8 @@ typedef struct OnyxWasmModule {
     u32 next_elem_idx;
 
     u32 *stack_top_ptr, *stack_base_ptr;
+
+    b32 has_stack_locals : 1;
 } OnyxWasmModule;
 
 OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc);
diff --git a/onyx b/onyx
index 8a908bc8b4819ce7a7d153424cc8909528907acc..22752e469c94f02caed9df161847bdd893e2cde4 100755 (executable)
Binary files a/onyx and b/onyx differ
index e2dac415531d6adb1b3c3c2b993c5c9a1a750641..b432d7698a0829334b40714f24e048019e9e91b2 100644 (file)
@@ -2,6 +2,7 @@ package memory
 
 use "progs/intrinsics"
 
+use package printing { print }
 use package intrinsics {
     memory_size, memory_grow
 }
@@ -15,13 +16,13 @@ AllocAction :: enum {
     Resize;
 }
 
+alloc_proc :: #type proc (rawptr, AllocAction, u32, u32, rawptr) -> rawptr;
+
 Allocator :: struct {
     data: rawptr;
     func: alloc_proc; 
 }
 
-alloc_proc :: #type proc (rawptr, AllocAction, u32, u32, rawptr) -> rawptr;
-
 alloc :: proc (use a: ^Allocator, size: u32) -> rawptr {
     return func(data, AllocAction.Alloc, size, 16, null);
 }
index 52e495f0221be22f153ccb33d7584312aa241b97..f2f4f4adfd146434603cad764eb77149f0c1f27e 100644 (file)
@@ -1,8 +1,10 @@
 package main
 
 use "progs/print_funcs"
+use "progs/alloc"
 
 use package printing
+use package memory
 
 ret_val :: proc (x: i32, y: i32) -> i32 {
     big_arr : [128] i32;
@@ -10,19 +12,56 @@ ret_val :: proc (x: i32, y: i32) -> i32 {
     return big_arr[127] + x + y;
 }
 
+N :: 10
+
+sumN :: proc (x: [N] i32) -> i32 {
+    s := 0;
+    for i: 0, N do s += x[i];
+    return s;
+}
+
+summing :: proc (x: ^i32) -> i32 {
+    s := 0;
+    for i: 0, N do s += x[i];
+    return s;
+}
+
+Vec3 :: struct {
+    x: i32;
+    y: i32;
+    z: i32;
+}
+
+mag_squared :: proc (v: Vec3) -> i32 {
+    return v.x * v.x + v.y * v.y + v.z * v.z;
+}
+
+stuff :: #file_contents "Makefile"
+
 main :: proc #export {
+    heap_init();
     print("Hello, World!");
     print(cast(i32) __heap_start);
+
     a := 12345;
 
-    arr : [5] i32;
+    arr: [N] i32;
     arr[0] = 10;
     arr[1] = 20;
     arr[2] = 30;
     arr[3] = 40;
     arr[4] = 50;
+    arr[9] = 123;
+    print(sumN(arr));
+    print(summing(cast(^i32) arr));
+
+    v: Vec3;
+    v.x = 2;
+    v.y = 4;
+    v.z = 10;
+    print(mag_squared(v));
 
     print(ret_val(10, 4));
     
-    for i: 0, 5 do print(arr[i]);
+    for i: 0, N do print(arr[i]);
 }
\ No newline at end of file
index 0b9a9c4107bdba2f28eaaed4b3b8253d0d7949f5..e5aace0ba7823b82af098f0756ed149d4354442b 100644 (file)
@@ -584,6 +584,8 @@ CHECK(address_of, AstAddressOf* aof) {
         return 1;
     }
 
+    aof->expr->flags |= Ast_Flag_Address_Taken;
+
     aof->type = type_make_pointer(semstate.allocator, aof->expr->type);
 
     return 0;
index ad0d7811c8fd8e459d6d7910ede1c88f0734db65..2d617a1ad118edb32f102791a06e18112c95fc5f 100644 (file)
@@ -355,10 +355,17 @@ COMPILE_FUNC(assignment, AstBinaryOp* assign) {
     AstTyped* lval = assign->left;
 
     if (lval->kind == Ast_Kind_Local) {
-        u64 offset = 0;
-        compile_local_location(mod, &code, (AstLocal *) lval, &offset);
-        compile_expression(mod, &code, assign->right);
-        compile_store_instruction(mod, &code, lval->type, type_get_alignment_log2(lval->type), offset);
+        if (bh_imap_get(&mod->local_map, (u64) lval) & LOCAL_IS_WASM) {
+            u32 localidx = (u32) (bh_imap_get(&mod->local_map, (u64) lval) & ~LOCAL_IS_WASM);
+            compile_expression(mod, &code, assign->right);
+            WID(WI_LOCAL_SET, localidx);
+
+        } else {
+            u64 offset = 0;
+            compile_local_location(mod, &code, (AstLocal *) lval, &offset);
+            compile_expression(mod, &code, assign->right);
+            compile_store_instruction(mod, &code, lval->type, type_get_alignment_log2(lval->type), offset);
+        }
 
     } else if (lval->kind == Ast_Kind_Global) {
         i32 globalidx = (i32) bh_imap_get(&mod->index_map, (u64) lval);
@@ -558,15 +565,20 @@ COMPILE_FUNC(while, AstWhile* while_node) {
 COMPILE_FUNC(for, AstFor* for_node) {
     bh_arr(WasmInstruction) code = *pcode;
 
-    // i32 it_idx = (i32) bh_imap_get(&mod->local_map, (u64) for_node->var);
-
     AstLocal* var = for_node->var;
-
+    u64 tmp = bh_imap_get(&mod->local_map, (u64) var);
+    b32 it_is_local = (b32) ((tmp & LOCAL_IS_WASM) != 0);
+    u32 it_idx = (u32) (tmp & ~LOCAL_IS_WASM);
     u64 offset = 0;
-    compile_local_location(mod, &code, var, &offset);
-    compile_expression(mod, &code, for_node->start);
-    compile_store_instruction(mod, &code, var->type, type_get_alignment_log2(var->type), offset);
-    //WID(WI_LOCAL_SET, it_idx);
+
+    if (it_is_local) {
+        compile_expression(mod, &code, for_node->start);
+        WID(WI_LOCAL_SET, it_idx);
+    } else {
+        compile_local_location(mod, &code, var, &offset);
+        compile_expression(mod, &code, for_node->start);
+        compile_store_instruction(mod, &code, var->type, type_get_alignment_log2(var->type), offset);
+    }
 
     WID(WI_BLOCK_START, 0x40);
     WID(WI_LOOP_START, 0x40);
@@ -574,10 +586,13 @@ COMPILE_FUNC(for, AstFor* for_node) {
     bh_arr_push(mod->structured_jump_target, 1);
     bh_arr_push(mod->structured_jump_target, 2);
 
-    offset = 0;
-    compile_local_location(mod, &code, var, &offset);
-    compile_load_instruction(mod, &code, var->type, offset);
-    // WID(WI_LOCAL_GET, it_idx);
+    if (it_is_local) {
+        WID(WI_LOCAL_GET, it_idx);
+    } else {
+        offset = 0;
+        compile_local_location(mod, &code, var, &offset);
+        compile_load_instruction(mod, &code, var->type, offset);
+    }
     compile_expression(mod, &code, for_node->end);
     WI(WI_I32_GE_S);
     WID(WI_COND_JUMP, 0x01);
@@ -586,19 +601,27 @@ COMPILE_FUNC(for, AstFor* for_node) {
         compile_statement(mod, &code, stmt);
     }
 
-    offset = 0;
-    compile_local_location(mod, &code, var, &offset);
-    offset = 0;
-    compile_local_location(mod, &code, var, &offset);
-    compile_load_instruction(mod, &code, var->type, offset);
-    if (for_node->step == NULL)
-        WID(WI_I32_CONST, 0x01);
-    else
-        compile_expression(mod, &code, for_node->step);
-    // WID(WI_LOCAL_GET, it_idx);
-    WI(WI_I32_ADD);
-    compile_store_instruction(mod, &code, var->type, type_get_alignment_log2(var->type), offset);
-    //WID(WI_LOCAL_SET, it_idx);
+    if (it_is_local) {
+        WID(WI_LOCAL_GET, it_idx);
+        if (for_node->step == NULL)
+            WID(WI_I32_CONST, 0x01);
+        else
+            compile_expression(mod, &code, for_node->step);
+        WI(WI_I32_ADD);
+        WID(WI_LOCAL_SET, it_idx);
+    } else {
+        offset = 0;
+        compile_local_location(mod, &code, var, &offset);
+        offset = 0;
+        compile_local_location(mod, &code, var, &offset);
+        compile_load_instruction(mod, &code, var->type, offset);
+        if (for_node->step == NULL)
+            WID(WI_I32_CONST, 0x01);
+        else
+            compile_expression(mod, &code, for_node->step);
+        WI(WI_I32_ADD);
+        compile_store_instruction(mod, &code, var->type, type_get_alignment_log2(var->type), offset);
+    }
 
     compile_deferred_stmts(mod, &code, (AstNode *) for_node);
 
@@ -939,9 +962,21 @@ COMPILE_FUNC(expression, AstTyped* expr) {
         }
 
         case Ast_Kind_Local: {
-            u64 offset = 0;
-            compile_local_location(mod, &code, (AstLocal *) expr, &offset);
-            compile_load_instruction(mod, &code, expr->type, offset);
+            u64 tmp = bh_imap_get(&mod->local_map, (u64) expr);
+            if (tmp & LOCAL_IS_WASM) {
+                WID(WI_LOCAL_GET, (u32) (tmp & ~LOCAL_IS_WASM));
+            } else {
+                u64 offset = 0;
+                compile_local_location(mod, &code, (AstLocal *) expr, &offset);
+
+                if (expr->type->kind != Type_Kind_Array) {
+                    compile_load_instruction(mod, &code, expr->type, offset);
+                } else {
+                    WID(WI_I32_CONST, offset);
+                    WI(WI_I32_ADD);
+                }
+            }
+            
             break;
         }
 
@@ -1256,7 +1291,8 @@ COMPILE_FUNC(return, AstReturn* ret) {
         } 
     }
 
-    compile_stack_leave(mod, &code, 0);
+    if (mod->has_stack_locals)
+        compile_stack_leave(mod, &code, 0);
 
     WI(WI_RETURN);
 
@@ -1386,6 +1422,13 @@ static inline b32 should_compile_function(AstFunction* fd) {
     return 1;
 }
 
+static b32 local_is_wasm_local(AstLocal* local) {
+    if (local->flags & Ast_Flag_Address_Taken) return 1;
+    if (local->type->kind == Type_Kind_Basic) return 1;
+    if (local->type->kind == Type_Kind_Pointer) return 1;
+    return 0;
+}
+
 static void compile_function(OnyxWasmModule* mod, AstFunction* fd) {
     if (!should_compile_function(fd)) return;
 
@@ -1433,31 +1476,37 @@ static void compile_function(OnyxWasmModule* mod, AstFunction* fd) {
 
     // If there is no body then don't process the code
     if (fd->body != NULL) {
-        // // NOTE: Generate the local map
-        i32 localidx = 0;
+        // NOTE: Generate the local map
+        u64 localidx = 0;
         for (AstLocal *param = fd->params; param != NULL; param = (AstLocal *) param->next) {
-            bh_imap_put(&mod->local_map, (u64) param, localidx++);
+            bh_imap_put(&mod->local_map, (u64) param, localidx++ | LOCAL_IS_WASM);
         }
 
-        // static const WasmType local_types[4] = { WASM_TYPE_INT32, WASM_TYPE_INT64, WASM_TYPE_FLOAT32, WASM_TYPE_FLOAT64 };
+        static const WasmType local_types[4] = { WASM_TYPE_INT32, WASM_TYPE_INT64, WASM_TYPE_FLOAT32, WASM_TYPE_FLOAT64 };
 
-        // // HACK: This assumes that the order of the count members
-        // // is the same as the order of the local_types above
-        // u8* count = &wasm_func.locals.i32_count;
-        // fori (ti, 0, 3) {
-        //     bh_arr_each(AstLocal *, local, fd->locals) {
-        //         if (onyx_type_to_wasm_type((*local)->type) == local_types[ti]) {
-        //             bh_imap_put(&mod->local_map, (u64) *local, localidx++);
+        // HACK: This assumes that the order of the count members
+        // is the same as the order of the local_types above
+        u8* count = &wasm_func.locals.i32_count;
+        fori (ti, 0, 3) {
+            bh_arr_each(AstLocal *, local, fd->locals) {
+                if (!local_is_wasm_local(*local)) continue;
 
-        //             (*count)++;
-        //         }
-        //     }
+                if (onyx_type_to_wasm_type((*local)->type) == local_types[ti]) {
+                    bh_imap_put(&mod->local_map, (u64) *local, localidx++ | LOCAL_IS_WASM);
 
-        //     count++;
-        // }
+                    (*count)++;
+                }
+            }
+
+            count++;
+        }
 
-        i32 offset = 0;
+        b32 has_stack_locals = 0;
+        u64 offset = 0;
         bh_arr_each(AstLocal *, local, fd->locals) {
+            if (local_is_wasm_local(*local)) continue;
+
+            has_stack_locals = 1;
             u32 size  = type_size_of((*local)->type);
             u32 align = type_alignment_of((*local)->type);
             if (offset % align != 0)
@@ -1471,9 +1520,14 @@ static void compile_function(OnyxWasmModule* mod, AstFunction* fd) {
             offset += 16 - (offset % 16);
 
         // Generate code
-        compile_stack_enter(mod, &wasm_func.code, (u64) offset);
+        if (has_stack_locals)
+            compile_stack_enter(mod, &wasm_func.code, (u64) offset);
+
+        mod->has_stack_locals = has_stack_locals;
         compile_function_body(mod, &wasm_func.code, fd);
-        compile_stack_leave(mod, &wasm_func.code, 0);
+
+        if (has_stack_locals)
+            compile_stack_leave(mod, &wasm_func.code, 0);
     }
 
     bh_arr_push(wasm_func.code, ((WasmInstruction){ WI_BLOCK_END, 0x00 }));