From: Brendan Hansen Date: Sat, 17 Apr 2021 03:06:56 +0000 (-0500) Subject: refactored for cleaner code generation. X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=5560aa3b2eb6843b4a1675e62c67ce211dc02c94;p=onyx.git refactored for cleaner code generation. --- diff --git a/bin/onyx b/bin/onyx index 80e1155d..5e002a9d 100755 Binary files a/bin/onyx and b/bin/onyx differ diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index 2ef12781..efbee081 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -755,7 +755,6 @@ struct AstFunction { AstType* return_type; AstBlock *body; - bh_arr(AstTyped *) allocate_exprs; OnyxToken* name; diff --git a/include/onyxwasm.h b/include/onyxwasm.h index a369cfb2..872f002e 100644 --- a/include/onyxwasm.h +++ b/include/onyxwasm.h @@ -507,6 +507,10 @@ typedef struct StrLitInfo { u32 len; } StrLitInfo; +typedef struct PatchInfo { + u32 instruction_index; +} PatchInfo; + typedef struct OnyxWasmModule { bh_allocator allocator; @@ -527,6 +531,8 @@ typedef struct OnyxWasmModule { bh_arr(DeferredStmt) deferred_stmts; bh_arr(AllocatedSpace) local_allocations; + bh_arr(PatchInfo) stack_leave_patches; + // NOTE: Used internally as a map from strings that represent function types, // 0x7f 0x7f : 0x7f ( (i32, i32) -> i32 ) // to the function type index if it has been created. diff --git a/src/onyxchecker.c b/src/onyxchecker.c index b33617e6..7e5bdaf4 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -1492,6 +1492,9 @@ CheckStatus check_statement_chain(AstNode** start) { CheckStatus check_block(AstBlock* block) { CHECK(statement_chain, &block->body); + // CLEANUP: There will need to be some other method of + // checking the following conditions. + // // bh_arr_each(AstTyped *, value, block->allocate_exprs) { // fill_in_type(*value); diff --git a/src/onyxclone.c b/src/onyxclone.c index 4a7617d3..26c46732 100644 --- a/src/onyxclone.c +++ b/src/onyxclone.c @@ -365,9 +365,6 @@ AstNode* ast_clone(bh_allocator a, void* n) { df->return_type = (AstType *) ast_clone(a, sf->return_type); df->body = (AstBlock *) ast_clone(a, sf->body); - df->allocate_exprs = NULL; - bh_arr_new(global_heap_allocator, df->allocate_exprs, 4); - df->params = NULL; bh_arr_new(global_heap_allocator, df->params, bh_arr_length(sf->params)); @@ -460,7 +457,4 @@ void clone_function_body(bh_allocator a, AstFunction* dest, AstFunction* source) if (source->kind != Ast_Kind_Function) return; dest->body = (AstBlock *) ast_clone(a, source->body); - - dest->allocate_exprs = NULL; - bh_arr_new(global_heap_allocator, dest->allocate_exprs, 4); } diff --git a/src/onyxparser.c b/src/onyxparser.c index 79a689f6..f2325b8e 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -1869,7 +1869,6 @@ static AstFunction* parse_function_definition(OnyxParser* parser, OnyxToken* tok AstFunction* func_def = make_node(AstFunction, Ast_Kind_Function); func_def->token = token; - bh_arr_new(global_heap_allocator, func_def->allocate_exprs, 4); bh_arr_new(global_heap_allocator, func_def->params, 4); bh_arr(AstPolyParam) polymorphic_vars = NULL; diff --git a/src/onyxsymres.c b/src/onyxsymres.c index a7aadca7..240a06ce 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -249,8 +249,6 @@ static SymresStatus symres_type(AstType** type) { static SymresStatus symres_local(AstLocal** local) { SYMRES(type, &(*local)->type_node); - bh_arr_push(curr_function->allocate_exprs, (AstTyped *) *local); - if ((*local)->token != NULL) symbol_introduce(curr_scope, (*local)->token, (AstNode *) *local); @@ -402,9 +400,6 @@ static SymresStatus symres_array_literal(AstArrayLiteral* al) { bh_arr_each(AstTyped *, expr, al->values) SYMRES(expression, expr); - if (curr_function != NULL) - bh_arr_push(curr_function->allocate_exprs, (AstTyped *) al); - return Symres_Success; } diff --git a/src/onyxwasm.c b/src/onyxwasm.c index 05e26b9d..2368fafe 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -1,13 +1,15 @@ // // 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. +// [x] 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 +// [x] 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. +// +// [ ] Change the calling convention so it is easier to use from both JS and in the compiler. @@ -217,6 +219,7 @@ enum StructuredBlockType { local_raw_free(mod->local_alloc, type1); \ local_raw_free(mod->local_alloc, type2); \ } +#define SUBMIT_PATCH(patch_arr, offset) bh_arr_push((patch_arr), ((PatchInfo) { bh_arr_length(code) - offset })) EMIT_FUNC(function_body, AstFunction* fd); EMIT_FUNC(block, AstBlock* block, b32 generate_block_headers); @@ -255,7 +258,6 @@ EMIT_FUNC(expression, AstTyped* expr); EMIT_FUNC(cast, AstUnaryOp* cast); EMIT_FUNC(return, AstReturn* ret); EMIT_FUNC(stack_enter, u64 stacksize); -EMIT_FUNC(stack_leave, u32 unused); EMIT_FUNC(zero_value, WasmType wt); EMIT_FUNC(zero_value_for_type, Type* type, OnyxToken* where); @@ -2516,8 +2518,9 @@ EMIT_FUNC(return, AstReturn* ret) { } } - if (mod->has_stack_locals) - emit_stack_leave(mod, &code, 0); + SUBMIT_PATCH(mod->stack_leave_patches, 0); + WI(WI_NOP); + WI(WI_NOP); WI(WI_RETURN); @@ -2545,16 +2548,6 @@ EMIT_FUNC(stack_enter, u64 stacksize) { code[3] = (WasmInstruction) { WI_I32_ADD, 0 }; code[4] = (WasmInstruction) { WI_GLOBAL_SET, { .l = stack_top_idx } }; } - *pcode = code; -} - -EMIT_FUNC(stack_leave, u32 unused) { - bh_arr(WasmInstruction) code = *pcode; - - u64 stack_top_idx = bh_imap_get(&mod->index_map, (u64) &builtin_stack_top); - - WIL(WI_LOCAL_GET, mod->stack_base_idx); - WID(WI_GLOBAL_SET, stack_top_idx); *pcode = code; } @@ -2768,23 +2761,29 @@ static void emit_function(OnyxWasmModule* mod, AstFunction* fd) { mod->curr_cc = type_function_get_cc(fd->type); assert(mod->curr_cc != CC_Undefined); - mod->has_stack_locals = (mod->curr_cc == CC_Return_Stack); - bh_arr_each(AstTyped *, expr, fd->allocate_exprs) - mod->has_stack_locals |= !local_is_wasm_local(*expr); + bh_arr_clear(mod->stack_leave_patches); - if (mod->has_stack_locals) { - // NOTE: '5' needs to match the number of instructions it takes - // to setup a stack frame - bh_arr_insert_end(wasm_func.code, 5); - mod->stack_base_idx = local_raw_allocate(mod->local_alloc, WASM_TYPE_PTR); - } + bh_arr_insert_end(wasm_func.code, 5); + fori (i, 0, 5) wasm_func.code[i] = (WasmInstruction) { WI_NOP, 0 }; + + mod->stack_base_idx = local_raw_allocate(mod->local_alloc, WASM_TYPE_PTR); // Generate code emit_function_body(mod, &wasm_func.code, fd); - if (mod->has_stack_locals) { + if (mod->local_alloc->max_stack > 0 || mod->curr_cc == CC_Return_Stack) { emit_stack_enter(mod, &wasm_func.code, mod->local_alloc->max_stack); - emit_stack_leave(mod, &wasm_func.code, 0); + + // Place all stack leaves in patch locations. These will (probably) all be + // right before a "return" instruction. + u64 stack_top_idx = bh_imap_get(&mod->index_map, (u64) &builtin_stack_top); + bh_arr_push(wasm_func.code, ((WasmInstruction) { WI_LOCAL_GET, { .l = mod->stack_base_idx } })); + bh_arr_push(wasm_func.code, ((WasmInstruction) { WI_GLOBAL_SET, { .l = stack_top_idx } })); + + bh_arr_each(PatchInfo, patch, mod->stack_leave_patches) { + wasm_func.code[patch->instruction_index + 0] = (WasmInstruction) { WI_LOCAL_GET, { .l = mod->stack_base_idx } }; + wasm_func.code[patch->instruction_index + 1] = (WasmInstruction) { WI_GLOBAL_SET, { .l = stack_top_idx } }; + } } } @@ -3124,6 +3123,8 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) { .next_elem_idx = 0, .structured_jump_target = NULL, + .local_allocations = NULL, + .stack_leave_patches = NULL, .stack_top_ptr = NULL, .stack_base_idx = 0, @@ -3159,11 +3160,13 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) { bh_arr_new(global_heap_allocator, module.deferred_stmts, 4); bh_arr_new(global_heap_allocator, module.local_allocations, 4); + bh_arr_new(global_heap_allocator, module.stack_leave_patches, 4); WasmExport mem_export = { .kind = WASM_FOREIGN_MEMORY, .idx = 0, }; + // :ArbitraryConstant bh_table_put(WasmExport, module.exports, "memory", mem_export); module.export_count++;