From: Brendan Hansen Date: Fri, 16 Apr 2021 22:40:30 +0000 (-0500) Subject: started refactoring how stack space is allocated X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=2a5f9514d78cc6d72712c0b9eeebdbbcae0398b1;p=onyx.git started refactoring how stack space is allocated --- diff --git a/bin/onyx b/bin/onyx index 62630b28..80e1155d 100755 Binary files a/bin/onyx and b/bin/onyx differ diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index d6f9aa2f..2ef12781 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -575,8 +575,6 @@ struct AstBlock { AstNode *body; Scope *scope; - bh_arr(AstTyped *) allocate_exprs; - Scope *binding_scope; }; struct AstDefer { AstNode_base; AstNode *stmt; }; diff --git a/include/onyxwasm.h b/include/onyxwasm.h index 2c81d93b..a369cfb2 100644 --- a/include/onyxwasm.h +++ b/include/onyxwasm.h @@ -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 ) diff --git a/src/onyxchecker.c b/src/onyxchecker.c index a15e17fe..b33617e6 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -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; } diff --git a/src/onyxclone.c b/src/onyxclone.c index e4a76f6a..4a7617d3 100644 --- a/src/onyxclone.c +++ b/src/onyxclone.c @@ -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: diff --git a/src/onyxparser.c b/src/onyxparser.c index e4bd7450..79a689f6 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -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) { diff --git a/src/onyxsymres.c b/src/onyxsymres.c index 99c356a5..a7aadca7 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -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: diff --git a/src/onyxwasm.c b/src/onyxwasm.c index 697152e2..05e26b9d 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -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,