From: Brendan Hansen Date: Tue, 18 Aug 2020 01:23:49 +0000 (-0500) Subject: added returning structs; much easier than anticipated X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=bfe5f2673f14c30e74614b9aa8dd77432648e487;p=onyx.git added returning structs; much easier than anticipated --- diff --git a/core/alloc.onyx b/core/alloc.onyx index e70f900d..377b7589 100644 --- a/core/alloc.onyx +++ b/core/alloc.onyx @@ -206,15 +206,6 @@ scratch_alloc_init :: proc (a: ^Allocator, ss: ^ScratchState) { } -#private return_scratch_size :: 256 -#private return_scratch_buff : [return_scratch_size] u8 -#private return_scratch_state : ScratchState; - -return_scratch_alloc : Allocator; - memory_init :: proc { heap_init(); - - scratch_state_init(^return_scratch_state, return_scratch_buff, return_scratch_size); - scratch_alloc_init(^return_scratch_alloc, ^return_scratch_state); } \ No newline at end of file diff --git a/docs/plan b/docs/plan index 614d56fe..2f58f7e8 100644 --- a/docs/plan +++ b/docs/plan @@ -181,6 +181,12 @@ HOW: [X] #size on structs + [X] multiple return value + - Returning on the stack + + [X] returning structs + - This will put forward a lot of the work that will be done for multiple return values + [ ] 'use' enums and packages at an arbitrary scope [ ] 'when' statements @@ -215,16 +221,6 @@ HOW: - Dynamic resizing? - They are just very hard to use at the moment - [ ] multiple return values - - THIS IS NOT GOING TO BE FUN. - - Wasm multi-value proposal is not finalized and nothing has implemented it yet - - This means other methods of returning multiple things would be needed: - - globals - - on the stack - - [ ] returning structs - - This will put forward a lot of the work that will be done for multiple return values - [X] Start work on evaluating compile time known values. - An expression marked COMPTIME will be reduced to its value in the parse tree. diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index ca9e7499..06225a02 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -240,6 +240,12 @@ typedef enum OnyxIntrinsic { ONYX_INTRINSIC_F64_COPYSIGN, } OnyxIntrinsic; +typedef enum CallingConvention { + CC_Undefined, + CC_Return_Wasm, + CC_Return_Stack +} CallingConvention; + // Base Nodes #define AstNode_members { \ @@ -543,4 +549,11 @@ static inline b32 node_is_type(AstNode* node) { return (node->kind > Ast_Kind_Type_Start) && (node->kind < Ast_Kind_Type_End); } +static inline CallingConvention type_function_get_cc(Type* type) { + if (type == NULL) return CC_Undefined; + if (type->kind != Type_Kind_Function) return CC_Undefined; + if (type->Function.return_type->kind == Type_Kind_Struct) return CC_Return_Stack; + return CC_Return_Wasm; +} + #endif // #ifndef ONYXASTNODES_H diff --git a/include/onyxwasm.h b/include/onyxwasm.h index b99798ad..c448a303 100644 --- a/include/onyxwasm.h +++ b/include/onyxwasm.h @@ -340,6 +340,7 @@ typedef struct OnyxWasmModule { i32 *stack_top_ptr; u64 stack_base_idx; + CallingConvention curr_cc; b32 has_stack_locals : 1; } OnyxWasmModule; diff --git a/onyx b/onyx index 3e28fe9a..7e7a4a81 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/stack_based.onyx b/progs/stack_based.onyx index 5301b59a..8842eaff 100644 --- a/progs/stack_based.onyx +++ b/progs/stack_based.onyx @@ -60,12 +60,6 @@ mag_squared :: proc (use v: Vec3) -> i32 { return x * x + y * y + z * z; } -vec_add :: proc (v: Vec3, u: Vec3, use out: ^Vec3) { - x = v.x + u.x; - y = v.y + u.y; - z = v.z + u.z; -} - clamp :: proc (v: i32, lo: i32, hi: i32) -> i32 { if v < lo do return lo; if v > hi do return hi; @@ -154,7 +148,7 @@ start :: proc #export { mag_squared(varr[2]) |> print(); v1 := Vec3.{}; - v2 := *vadd(v1, Vec3.{ 0, 0, 0 }); + v2 := vmul(vadd(v1, Vec3.{ 1, 2, 3 }), 3); print(v2.x); print(v2.y); @@ -167,15 +161,16 @@ start :: proc #export { print_hex(cast(u64) un.i); } -vadd :: proc (v1: Vec3, v2: Vec3) -> ^Vec3 { - out := cast(^Vec3) alloc(return_scratch_alloc, sizeof Vec3); - *out = Vec3.{ +vadd :: proc (v1: Vec3, v2: Vec3) -> Vec3 { + return Vec3.{ x = v1.x + v2.x, y = v1.y + v2.y, z = v1.z + v2.z, }; +} - return out; +vmul :: proc (use v: Vec3, s: i32) -> Vec3 { + return Vec3.{ x = x * s, y = y * s, z = z * s }; } UnionTest :: struct #union { diff --git a/src/onyxwasm.c b/src/onyxwasm.c index fe1de9d3..f526e6b9 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -363,7 +363,8 @@ COMPILE_FUNC(field_access_location, AstFieldAccess* field, u64* offset_r COMPILE_FUNC(local_location, AstLocal* local, u64* offset_return); COMPILE_FUNC(memory_reservation_location, AstMemRes* memres); COMPILE_FUNC(struct_load, Type* type, u64 offset); -COMPILE_FUNC(struct_store, AstTyped* lval); +COMPILE_FUNC(struct_lval, AstTyped* lval); +COMPILE_FUNC(struct_store, Type* type, u64 offset); COMPILE_FUNC(struct_literal, AstStructLiteral* sl); COMPILE_FUNC(expression, AstTyped* expr); COMPILE_FUNC(cast, AstUnaryOp* cast); @@ -457,7 +458,7 @@ COMPILE_FUNC(assignment, AstBinaryOp* assign) { if (assign->right->type->kind == Type_Kind_Struct) { compile_expression(mod, &code, assign->right); - compile_struct_store(mod, &code, assign->left); + compile_struct_lval(mod, &code, assign->left); *pcode = code; return; @@ -526,9 +527,10 @@ COMPILE_FUNC(assignment, AstBinaryOp* assign) { COMPILE_FUNC(store_instruction, Type* type, u32 offset) { bh_arr(WasmInstruction) code = *pcode; - assert(("Should use compile_struct_store instead", type->kind != Type_Kind_Struct)); - - u32 alignment = type_get_alignment_log2(type); + if (type->kind == Type_Kind_Struct) { + compile_struct_store(mod, pcode, type, offset); + return; + } if (type->kind == Type_Kind_Enum) { type = type->Enum.backing; @@ -538,6 +540,8 @@ COMPILE_FUNC(store_instruction, Type* type, u32 offset) { type = &basic_types[Basic_Kind_U32]; } + u32 alignment = type_get_alignment_log2(type); + i32 store_size = type_size_of(type); i32 is_basic = type->kind == Type_Kind_Basic || type->kind == Type_Kind_Pointer; i32 is_pointer = is_basic && (type->Basic.flags & Basic_Flag_Pointer); @@ -909,9 +913,24 @@ COMPILE_FUNC(call, AstCall* call) { compile_expression(mod, &code, arg->value); } + CallingConvention cc = type_function_get_cc(call->callee->type); + assert(cc != CC_Undefined); + + Type* return_type = call->callee->type->Function.return_type; + u32 return_size = type_size_of(return_type); + u64 stack_top_idx = bh_imap_get(&mod->index_map, (u64) &builtin_stack_top); + + if (cc == CC_Return_Stack) { + WID(WI_GLOBAL_GET, stack_top_idx); + WID(WI_I32_CONST, return_size); + WI(WI_I32_ADD); + WID(WI_GLOBAL_SET, stack_top_idx); + } + if (call->callee->kind == Ast_Kind_Function) { i32 func_idx = (i32) bh_imap_get(&mod->index_map, (u64) call->callee); bh_arr_push(code, ((WasmInstruction){ WI_CALL, func_idx })); + } else { compile_expression(mod, &code, call->callee); @@ -919,6 +938,16 @@ COMPILE_FUNC(call, AstCall* call) { WID(WI_CALL_INDIRECT, ((WasmInstructionData) { type_idx, 0x00 })); } + if (cc == CC_Return_Stack) { + WID(WI_GLOBAL_GET, stack_top_idx); + WID(WI_I32_CONST, return_size); + WI(WI_I32_SUB); + WID(WI_GLOBAL_SET, stack_top_idx); + + WID(WI_GLOBAL_GET, stack_top_idx); + compile_load_instruction(mod, &code, return_type, 0); + } + *pcode = code; } @@ -1108,7 +1137,7 @@ COMPILE_FUNC(struct_load, Type* type, u64 offset) { *pcode = code; } -COMPILE_FUNC(struct_store, AstTyped* lval) { +COMPILE_FUNC(struct_lval, AstTyped* lval) { // NOTE: Expects the stack to look like: // mem_1 // mem_2 @@ -1131,10 +1160,27 @@ COMPILE_FUNC(struct_store, AstTyped* lval) { default: assert(0); } + compile_struct_store(mod, &code, lval->type, offset); + + *pcode = code; +} + +COMPILE_FUNC(struct_store, Type* type, u64 offset) { + // NOTE: Expects the stack to look like: + // mem_1 + // mem_2 + // ... + // mem_n + // loc + + bh_arr(WasmInstruction) code = *pcode; + + assert(type->kind == Type_Kind_Struct); + u64 loc_idx = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32); WIL(WI_LOCAL_SET, loc_idx); - bh_arr_rev_each(StructMember *, smem, lval->type->Struct.memarr) { + bh_arr_rev_each(StructMember *, smem, type->Struct.memarr) { WasmType wt = onyx_type_to_wasm_type((*smem)->type); u64 tmp_idx = local_raw_allocate(mod->local_alloc, wt); @@ -1505,7 +1551,28 @@ COMPILE_FUNC(return, AstReturn* ret) { bh_arr(WasmInstruction) code = *pcode; if (ret->expr) { - compile_expression(mod, &code, ret->expr); + if (mod->curr_cc == CC_Return_Stack) { + if (ret->expr->type->kind == Type_Kind_Struct) { + compile_expression(mod, &code, ret->expr); + + WIL(WI_LOCAL_GET, mod->stack_base_idx); + WID(WI_I32_CONST, type_size_of(ret->expr->type)); + WI(WI_I32_SUB); + + compile_store_instruction(mod, &code, ret->expr->type, 0); + + } else { + WIL(WI_LOCAL_GET, mod->stack_base_idx); + WID(WI_I32_CONST, type_size_of(ret->expr->type)); + WI(WI_I32_SUB); + + compile_expression(mod, &code, ret->expr); + compile_store_instruction(mod, &code, ret->expr->type, 0); + } + + } else { + compile_expression(mod, &code, ret->expr); + } } compile_deferred_stmts(mod, &code, (AstNode *) ret); @@ -1544,7 +1611,7 @@ COMPILE_FUNC(stack_enter, u64 stacksize) { COMPILE_FUNC(stack_leave, u32 unused) { bh_arr(WasmInstruction) code = *pcode; - u32 stack_top_idx = bh_imap_get(&mod->index_map, (u64) &builtin_stack_top); + 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); @@ -1577,6 +1644,7 @@ static i32 generate_type_idx(OnyxWasmModule* mod, Type* ft) { } *(t++) = ':'; + // HACK: Slightly: the wasm type for structs has to be 0x00 WasmType return_type = onyx_type_to_wasm_type(ft->Function.return_type); *(t++) = (char) return_type; *t = '\0'; @@ -1705,7 +1773,10 @@ static void compile_function(OnyxWasmModule* mod, AstFunction* fd) { mod->local_alloc = &wasm_func.locals; mod->local_alloc->param_count = localidx; - mod->has_stack_locals = 0; + 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(AstLocal *, local, fd->locals) mod->has_stack_locals |= !local_is_wasm_local(*local); @@ -1716,7 +1787,6 @@ static void compile_function(OnyxWasmModule* mod, AstFunction* fd) { mod->stack_base_idx = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32); } - // Generate code compile_function_body(mod, &wasm_func.code, fd);