started refactoring how stack space is allocated
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 16 Apr 2021 22:40:30 +0000 (17:40 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 16 Apr 2021 22:40:30 +0000 (17:40 -0500)
bin/onyx
include/onyxastnodes.h
include/onyxwasm.h
src/onyxchecker.c
src/onyxclone.c
src/onyxparser.c
src/onyxsymres.c
src/onyxwasm.c

index 62630b2817bf6e0db06b4f0b195e08fe0c281879..80e1155d8b863fe850596dfa52667f06eb7e83fe 100755 (executable)
Binary files a/bin/onyx and b/bin/onyx differ
index d6f9aa2f795f1a9b9849f818692ac9ee9b8ddb82..2ef127812532a30629abe9e2c0d4e56edbca4d88 100644 (file)
@@ -575,8 +575,6 @@ struct AstBlock         {
     AstNode *body;
     Scope *scope;
 
-    bh_arr(AstTyped *)   allocate_exprs;
-
     Scope *binding_scope;
 };
 struct AstDefer         { AstNode_base; AstNode *stmt; };
index 2c81d93b67ce529e614fbad2649bd16706374b6c..a369cfb2033a333ee7c255636207a3446e3692a1 100644 (file)
@@ -497,6 +497,11 @@ typedef struct DeferredStmt {
     AstNode *stmt;
 } DeferredStmt;
 
+typedef struct AllocatedSpace {
+    u64 depth;
+    AstTyped *expr;
+} AllocatedSpace;
+
 typedef struct StrLitInfo {
     u32 addr;
     u32 len;
@@ -519,7 +524,8 @@ typedef struct OnyxWasmModule {
     // NOTE: Mapping ptrs to elements
     bh_imap elem_map;
 
-    bh_arr(DeferredStmt) deferred_stmts;
+    bh_arr(DeferredStmt)   deferred_stmts;
+    bh_arr(AllocatedSpace) local_allocations; 
 
     // NOTE: Used internally as a map from strings that represent function types,
     // 0x7f 0x7f : 0x7f ( (i32, i32) -> i32 )
index a15e17fee8fc09a685d4a7a5370205c9587b801d..b33617e6452c74f96e9f065a70e50084c1342447 100644 (file)
@@ -1467,6 +1467,13 @@ CheckStatus check_statement(AstNode** pstmt) {
             stmt->flags |= Ast_Flag_Expr_Ignored;
             return check_binaryop((AstBinaryOp **) pstmt, 1);
 
+        // NOTE: Local variable declarations used to be removed after the symbol
+        // resolution phase because long long ago, all locals needed to be known
+        // in a block in order to efficiently allocate enough space and registers
+        // for them all. Now with LocalAllocator, this is no longer necessary.
+        // Therefore, locals stay in the tree and need to be passed along.
+        case Ast_Kind_Local: return Check_Success;
+
         default:
             stmt->flags |= Ast_Flag_Expr_Ignored;
             return check_expression((AstTyped **) pstmt);
@@ -1485,24 +1492,24 @@ CheckStatus check_statement_chain(AstNode** start) {
 CheckStatus check_block(AstBlock* block) {
     CHECK(statement_chain, &block->body);
 
-    bh_arr_each(AstTyped *, value, block->allocate_exprs) {
-        fill_in_type(*value);
-
-        if ((*value)->kind == Ast_Kind_Local) {
-            if ((*value)->type == NULL) {
-                onyx_report_error((*value)->token->pos,
-                        "Unable to resolve type for local '%b'.",
-                        (*value)->token->text, (*value)->token->length);
-                return Check_Error;
-            }
-
-            if ((*value)->type->kind == Type_Kind_Compound) {
-                onyx_report_error((*value)->token->pos,
-                        "Compound type not allowed as local variable type. Try splitting this into multiple variables.");
-                return Check_Error;
-            }
-        }
-    }
+    // bh_arr_each(AstTyped *, value, block->allocate_exprs) {
+    //     fill_in_type(*value);
+
+    //     if ((*value)->kind == Ast_Kind_Local) {
+    //         if ((*value)->type == NULL) {
+    //             onyx_report_error((*value)->token->pos,
+    //                     "Unable to resolve type for local '%b'.",
+    //                     (*value)->token->text, (*value)->token->length);
+    //             return Check_Error;
+    //         }
+
+    //         if ((*value)->type->kind == Type_Kind_Compound) {
+    //             onyx_report_error((*value)->token->pos,
+    //                     "Compound type not allowed as local variable type. Try splitting this into multiple variables.");
+    //             return Check_Error;
+    //         }
+    //     }
+    // }
 
     return Check_Success;
 }
index e4a76f6a122b7938de350b71bffa05549d99ee61..4a7617d31930138df1978c9c3b75327b27d4c407 100644 (file)
@@ -215,8 +215,6 @@ AstNode* ast_clone(bh_allocator a, void* n) {
 
                case Ast_Kind_Block:
                        ((AstBlock *) nn)->body = ast_clone_list(a, ((AstBlock *) node)->body);
-                       ((AstBlock *) nn)->allocate_exprs = NULL;
-                       bh_arr_new(global_heap_allocator, ((AstBlock *) nn)->allocate_exprs, 4);
                        break;
 
                case Ast_Kind_Defer:
index e4bd7450913d11a3381984a24ebc29e68e689897..79a689f6fb89f467ab49a9b5b5c5d70dda4cf663 100644 (file)
@@ -1320,7 +1320,6 @@ static AstNode* parse_statement(OnyxParser* parser) {
 
 static AstBlock* parse_block(OnyxParser* parser) {
     AstBlock* block = make_node(AstBlock, Ast_Kind_Block);
-    bh_arr_new(global_heap_allocator, block->allocate_exprs, 4);
 
     // NOTE: --- is for an empty block
     if (parser->curr->type == Token_Type_Empty_Block) {
index 99c356a551acca13938f202746dce39cb7467b6a..a7aadca7bcba4e5e4ce7a27551eafdb9e106bece 100644 (file)
@@ -31,7 +31,7 @@ typedef enum SymresStatus {
 } SymresStatus;
 
 static SymresStatus symres_type(AstType** type);
-static SymresStatus symres_local(AstLocal** local, b32 add_to_block_locals);
+static SymresStatus symres_local(AstLocal** local);
 static SymresStatus symres_call(AstCall* call);
 static SymresStatus symres_size_of(AstSizeOf* so);
 static SymresStatus symres_align_of(AstAlignOf* so);
@@ -246,16 +246,9 @@ static SymresStatus symres_type(AstType** type) {
     return Symres_Success;
 }
 
-static SymresStatus symres_local(AstLocal** local, b32 add_to_block_locals) {
+static SymresStatus symres_local(AstLocal** local) {
     SYMRES(type, &(*local)->type_node);
 
-    // NOTE: This is a little gross, but it is allows for finer control
-    // over when locals are in scope in a block, which reduces the number
-    // of unique WASM locals and stack space needed.
-    //                                            - brendanfh 2020/12/16
-    if (add_to_block_locals)
-        bh_arr_push(bh_arr_last(block_stack)->allocate_exprs, (AstTyped *) *local);
-
     bh_arr_push(curr_function->allocate_exprs, (AstTyped *) *local);
 
     if ((*local)->token != NULL)
@@ -409,10 +402,8 @@ static SymresStatus symres_array_literal(AstArrayLiteral* al) {
     bh_arr_each(AstTyped *, expr, al->values)
         SYMRES(expression, expr);
 
-    if (bh_arr_length(block_stack) > 0) {
-        bh_arr_push(bh_arr_last(block_stack)->allocate_exprs, (AstTyped *) al);
+    if (curr_function != NULL)
         bh_arr_push(curr_function->allocate_exprs, (AstTyped *) al);
-    }
 
     return Symres_Success;
 }
@@ -509,7 +500,7 @@ static SymresStatus symres_if(AstIfWhile* ifnode) {
         ifnode->scope = scope_create(context.ast_alloc, curr_scope, ifnode->token->pos);
         scope_enter(ifnode->scope);
 
-        SYMRES(local, &ifnode->local, 0);
+        SYMRES(local, &ifnode->local);
 
         SYMRES(statement, (AstNode **) &ifnode->assignment, NULL);
     }
@@ -529,7 +520,7 @@ static SymresStatus symres_while(AstIfWhile* whilenode) {
         whilenode->scope = scope_create(context.ast_alloc, curr_scope, whilenode->token->pos);
         scope_enter(whilenode->scope);
 
-        SYMRES(local, &whilenode->local, 0);
+        SYMRES(local, &whilenode->local);
 
         SYMRES(statement, (AstNode **) &whilenode->assignment, NULL);
     }
@@ -548,7 +539,7 @@ static SymresStatus symres_for(AstFor* fornode) {
     fornode->scope = scope_create(context.ast_alloc, curr_scope, fornode->token->pos);
     scope_enter(fornode->scope);
     SYMRES(expression, &fornode->iter);
-    SYMRES(local, &fornode->var, 0);
+    SYMRES(local, &fornode->var);
     SYMRES(block, fornode->stmt);
     scope_leave();
 
@@ -743,8 +734,8 @@ static SymresStatus symres_statement(AstNode** stmt, b32 *remove) {
         case Ast_Kind_Jump:        break;
 
         case Ast_Kind_Local:
-            if (remove) *remove = 1;
-            SYMRES(local, (AstLocal **) stmt, 1);
+            // if (remove) *remove = 1;
+            SYMRES(local, (AstLocal **) stmt);
             break;
 
         case Ast_Kind_Use:
index 697152e27b71e860c6d60ec2a1ebb5a78cc1d458..05e26b9d4e1154a275abbb3ab05d9ef7a4570257 100644 (file)
@@ -1,3 +1,17 @@
+//
+// There are several things I'm seeing in this file that I want to clean up.
+// They are:
+//  [ ] remove the need to know if the stack is needed before generating the function.
+//      Just leave 5 nops at the beginning because they will be automatically removed
+//      by the WASM outputter.
+//  [ ] remove the need to have "allocate_exprs" on blocks and in functions. This will
+//      be easy once the above is done.
+//  [ ] there should be a better way to emit pending deferred statements because there
+//      is some code duplication between emit_return and emit_structured_jump.
+
+
+
+
 #define BH_DEBUG
 #include "onyxwasm.h"
 #include "onyxutils.h"
@@ -207,6 +221,8 @@ enum StructuredBlockType {
 EMIT_FUNC(function_body,                 AstFunction* fd);
 EMIT_FUNC(block,                         AstBlock* block, b32 generate_block_headers);
 EMIT_FUNC(statement,                     AstNode* stmt);
+EMIT_FUNC(local_allocation,              AstTyped* stmt);
+EMIT_FUNC_NO_ARGS(free_local_allocations);
 EMIT_FUNC(assignment,                    AstBinaryOp* assign);
 EMIT_FUNC(assignment_of_array,           AstTyped* left, AstTyped* right);
 EMIT_FUNC(compound_assignment,           AstBinaryOp* assign);
@@ -260,17 +276,12 @@ EMIT_FUNC(block, AstBlock* block, b32 generate_block_headers) {
     if (generate_block_headers)
         emit_enter_structured_block(mod, &code, SBT_Breakable_Block);
 
-    bh_arr_each(AstTyped *, expr, block->allocate_exprs)
-        bh_imap_put(&mod->local_map, (u64) *expr, local_allocate(mod->local_alloc, *expr));
-
     forll (AstNode, stmt, block->body, next) {
         emit_statement(mod, &code, stmt);
     }
 
     emit_deferred_stmts(mod, &code, (AstNode *) block);
-
-    bh_arr_each(AstTyped *, expr, block->allocate_exprs)
-        local_free(mod->local_alloc, *expr);
+    emit_free_local_allocations(mod, &code);
 
     if (generate_block_headers)
         emit_leave_structured_block(mod, &code);
@@ -377,12 +388,35 @@ EMIT_FUNC(statement, AstNode* stmt) {
         case Ast_Kind_Jump:       emit_structured_jump(mod, &code, (AstJump *) stmt); break;
         case Ast_Kind_Block:      emit_block(mod, &code, (AstBlock *) stmt, 1); break;
         case Ast_Kind_Defer:      emit_defer(mod, &code, (AstDefer *) stmt); break;
+        case Ast_Kind_Local:      emit_local_allocation(mod, &code, (AstTyped *) stmt); break;
         default:                  emit_expression(mod, &code, (AstTyped *) stmt); break;
     }
 
     *pcode = code;
 }
 
+EMIT_FUNC(local_allocation, AstTyped* stmt) {
+    bh_imap_put(&mod->local_map, (u64) stmt, local_allocate(mod->local_alloc, stmt));
+
+    bh_arr_push(mod->local_allocations, ((AllocatedSpace) {
+        .depth = bh_arr_length(mod->structured_jump_target),
+        .expr  = stmt,
+    }));
+}
+
+EMIT_FUNC_NO_ARGS(free_local_allocations) {
+    if (bh_arr_length(mod->local_allocations) == 0) return;
+
+    u64 depth = bh_arr_length(mod->structured_jump_target);
+    while (bh_arr_length(mod->local_allocations) > 0 && bh_arr_last(mod->local_allocations).depth == depth) {
+        // CHECK: Not sure this next line is okay to be here...
+        bh_imap_delete(&mod->local_map, (u64) bh_arr_last(mod->local_allocations).expr);
+
+        local_free(mod->local_alloc, bh_arr_last(mod->local_allocations).expr);
+        bh_arr_pop(mod->local_allocations);
+    }
+}
+
 EMIT_FUNC(assignment, AstBinaryOp* assign) {
     bh_arr(WasmInstruction) code = *pcode;
 
@@ -2189,6 +2223,7 @@ EMIT_FUNC(expression, AstTyped* expr) {
         }
 
         case Ast_Kind_Array_Literal: {
+            emit_local_allocation(mod, &code, expr);
             emit_array_literal(mod, &code, (AstArrayLiteral *) expr);
             break;
         }
@@ -2585,21 +2620,20 @@ static i32 generate_type_idx(OnyxWasmModule* mod, Type* ft) {
         if (type_get_param_pass(*param_type) == Param_Pass_By_Implicit_Pointer) {
             *(t++) = (char) onyx_type_to_wasm_type(&basic_types[Basic_Kind_Rawptr]);
 
-        } else {
-            if (type_is_structlike_strict(*param_type)) {
-                u32 mem_count = type_structlike_mem_count(*param_type);
-                StructMember smem;
+        }
+        else if (type_is_structlike_strict(*param_type)) {
+            u32 mem_count = type_structlike_mem_count(*param_type);
+            StructMember smem;
 
-                fori (i, 0, mem_count) {
-                    type_lookup_member_by_idx(*param_type, i, &smem);
-                    *(t++) = (char) onyx_type_to_wasm_type(smem.type);
-                }
+            fori (i, 0, mem_count) {
+                type_lookup_member_by_idx(*param_type, i, &smem);
+                *(t++) = (char) onyx_type_to_wasm_type(smem.type);
+            }
 
-                param_count += mem_count - 1;
+            param_count += mem_count - 1;
 
-            } else {
-                *(t++) = (char) onyx_type_to_wasm_type(*param_type);
-            }
+        } else {
+            *(t++) = (char) onyx_type_to_wasm_type(*param_type);
         }
 
         param_type++;
@@ -3124,6 +3158,7 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) {
     bh_imap_init(&module.elem_map,  global_heap_allocator, 16);
 
     bh_arr_new(global_heap_allocator, module.deferred_stmts, 4);
+    bh_arr_new(global_heap_allocator, module.local_allocations, 4);
 
     WasmExport mem_export = {
         .kind = WASM_FOREIGN_MEMORY,