From: Brendan Hansen Date: Sat, 8 Aug 2020 03:34:42 +0000 (-0500) Subject: using wasm local when possible again X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=c31b56fda0684ad4ec8f25ded7bb878c095f97af;p=onyx.git using wasm local when possible again --- diff --git a/docs/plan b/docs/plan index b26d4beb..94de23d3 100644 --- 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 diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index 63a1f95d..7844ecff 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -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), diff --git a/include/onyxwasm.h b/include/onyxwasm.h index 4ef2ea38..e0b74e71 100644 --- a/include/onyxwasm.h +++ b/include/onyxwasm.h @@ -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 8a908bc8..22752e46 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/alloc.onyx b/progs/alloc.onyx index e2dac415..b432d769 100644 --- a/progs/alloc.onyx +++ b/progs/alloc.onyx @@ -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); } diff --git a/progs/stack_based.onyx b/progs/stack_based.onyx index 52e495f0..f2f4f4ad 100644 --- a/progs/stack_based.onyx +++ b/progs/stack_based.onyx @@ -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 diff --git a/src/onyxchecker.c b/src/onyxchecker.c index 0b9a9c41..e5aace0b 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -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; diff --git a/src/onyxwasm.c b/src/onyxwasm.c index ad0d7811..2d617a1a 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -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 }));