From: Brendan Hansen Date: Fri, 18 Sep 2020 16:43:28 +0000 (-0500) Subject: added ability to pass complicated structs by value X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=b737da03e40b19471a06bcd12cee8bcb02dca23e;p=onyx.git added ability to pass complicated structs by value --- diff --git a/CHANGELOG b/CHANGELOG index 8567f3d0..1b18ec8e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,16 @@ +Release v0.0.4 +-------------- +Additions: +* Ability to pass complicated structs by value. Very useful in polymorphic data types. + +Removals: + +Changes: + +Bug fixes: + + + Release v0.0.3 -------------- Additions: diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index b5307cea..02646b6b 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -392,6 +392,13 @@ typedef enum ForLoopType { For_Loop_DynArr, } ForLoopType; +typedef enum ParamPassType { + Param_Pass_Invalid, + Param_Pass_By_Value, + Param_Pass_By_VarArg, + Param_Pass_By_Implicit_Pointer, +} ParamPassType; + // Base Nodes #define AstNode_base \ AstKind kind; \ @@ -422,7 +429,7 @@ struct AstBinOp { AstTyped_base; BinaryOp operation; AstTyped *left, *ri struct AstUnaryOp { AstTyped_base; UnaryOp operation; AstTyped *expr; }; struct AstNumLit { AstTyped_base; union { i32 i; i64 l; f32 f; f64 d; } value; }; struct AstStrLit { AstTyped_base; u64 addr; u64 length; }; -struct AstLocal { AstTyped_base; AstLocal *prev_local; }; +struct AstLocal { AstTyped_base; ParamPassType ppt; }; struct AstCall { AstTyped_base; AstArgument *arguments; u64 arg_count; AstTyped *callee; }; struct AstIntrinsicCall { AstTyped_base; AstArgument *arguments; u64 arg_count; OnyxIntrinsic intrinsic; }; struct AstArgument { AstTyped_base; AstTyped *value; }; @@ -597,6 +604,9 @@ struct AstGlobal { }; }; struct AstParam { + // HACK CLEANUP: This does not need to have a local buried inside of it. + // Convert this to be AstTyped_base and pull the ParamPassType from AstLocal + // to here. - brendanfh 2020/09/18 AstLocal *local; AstTyped *default_value; diff --git a/onyx b/onyx index f722c77d..f93ebfa0 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/poly_struct.onyx b/progs/poly_struct.onyx index a64d6a2c..138b1a48 100644 --- a/progs/poly_struct.onyx +++ b/progs/poly_struct.onyx @@ -5,21 +5,18 @@ package main use package core main :: proc (args: [] cstring) { - imap : I32Map(^string); + imap : I32Map(string); i32map_init(^imap); defer i32map_free(^imap); - hello := "Hello "; - world := "World!"; - - i32map_put(^imap, 50, ^hello); - i32map_put(^imap, 1234, ^world); + i32map_put(^imap, 50, "Hello "); + i32map_put(^imap, 1234, "World!"); println(i32map_has(^imap, 50)); println(i32map_has(^imap, 51)); // i32map_delete(^imap, 50); - print( *i32map_get(^imap, 50)); - println(*i32map_get(^imap, 1234)); + print( i32map_get(^imap, 50, "")); + println(i32map_get(^imap, 1234, "")); } diff --git a/src/onyxchecker.c b/src/onyxchecker.c index 0b3991b8..6e4510d6 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -303,13 +303,15 @@ b32 check_call(AstCall* call) { return 1; } - if (type_is_structlike_strict(actual->value->type)) { - if (!type_structlike_is_simple(actual->value->type)) { - onyx_report_error(actual->token->pos, - "Can only pass simple structs as parameters (no nested structures). passing by pointer is the only way for now."); - return 1; - } - } + // NOTE: This restricts you to only passing simple structures as parameters. + // At one point in time it was okay, but there are some necessary complexities. + // if (type_is_structlike_strict(actual->value->type)) { + // if (!type_structlike_is_simple(actual->value->type)) { + // onyx_report_error(actual->token->pos, + // "Can only pass simple structs as parameters (no nested structures). passing by pointer is the only way for now."); + // return 1; + // } + // } if (actual->value->kind == Ast_Kind_Polymorphic_Proc) has_polymorphic_args = 1; @@ -1266,6 +1268,14 @@ b32 check_function_header(AstFunction* func) { return 1; } + local->ppt = Param_Pass_By_Value; + + if (type_is_structlike_strict(local->type) + && !type_structlike_is_simple(local->type)) { + // local->type = type_make_pointer(semstate.node_allocator, local->type); + local->ppt = Param_Pass_By_Implicit_Pointer; + } + if (param->is_vararg) has_had_varargs = 1; if (local->type->kind != Type_Kind_Array diff --git a/src/onyxwasm.c b/src/onyxwasm.c index f75a143a..f3cdc524 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -922,8 +922,10 @@ EMIT_FUNC(for_array, AstFor* for_node, u64 iter_local) { WI(WI_BLOCK_END); WIL(WI_LOCAL_GET, ptr_local); - WIL(WI_I32_CONST, elem_size); - WI(WI_I32_ADD); + if (elem_size != 1) { + WIL(WI_I32_CONST, elem_size); + WI(WI_I32_ADD); + } WIL(WI_LOCAL_SET, ptr_local); bh_arr_pop(mod->structured_jump_target); @@ -1018,8 +1020,10 @@ EMIT_FUNC(for_slice, AstFor* for_node, u64 iter_local) { WI(WI_BLOCK_END); WIL(WI_LOCAL_GET, ptr_local); - WIL(WI_I32_CONST, elem_size); - WI(WI_I32_ADD); + if (elem_size != 1) { + WIL(WI_I32_CONST, elem_size); + WI(WI_I32_ADD); + } WIL(WI_LOCAL_SET, ptr_local); bh_arr_pop(mod->structured_jump_target); @@ -1316,6 +1320,18 @@ EMIT_FUNC(call, AstCall* call) { stack_grow_amm += type_size_of(arg->type); vararg_count += 1; } + + // CLEANUP structs-by-value + else if (type_is_structlike_strict(arg->type) && !type_structlike_is_simple(arg->type)) { + WID(WI_GLOBAL_GET, stack_top_idx); + emit_store_instruction(mod, &code, arg->type, stack_grow_amm); + + WID(WI_GLOBAL_GET, stack_top_idx); + WID(WI_I32_CONST, stack_grow_amm); + WI(WI_I32_ADD); + + stack_grow_amm += type_size_of(arg->type); + } } if (vararg_count > 0) { @@ -1333,7 +1349,7 @@ EMIT_FUNC(call, AstCall* call) { stack_grow_amm += return_size; - b32 needs_stack = (cc == CC_Return_Stack) || (vararg_count > 0); + b32 needs_stack = (cc == CC_Return_Stack) || (stack_grow_amm > 0); if (needs_stack) { WID(WI_GLOBAL_GET, stack_top_idx); @@ -1791,14 +1807,17 @@ EMIT_FUNC(field_access_location, AstFieldAccess* field, u64* offset_return) { u64 o2 = 0; emit_array_access_location(mod, &code, (AstArrayAccess *) source_expr, &o2); offset += o2; + } else if ((source_expr->kind == Ast_Kind_Local || source_expr->kind == Ast_Kind_Param) && source_expr->type->kind != Type_Kind_Pointer) { u64 o2 = 0; emit_local_location(mod, &code, (AstLocal *) source_expr, &o2); offset += o2; + } else if (source_expr->kind == Ast_Kind_Memres && source_expr->type->kind != Type_Kind_Pointer) { emit_memory_reservation_location(mod, &code, (AstMemRes *) source_expr); + } else { emit_expression(mod, &code, source_expr); } @@ -1822,10 +1841,9 @@ EMIT_FUNC(local_location, AstLocal* local, u64* offset_return) { u64 local_offset = (u64) bh_imap_get(&mod->local_map, (u64) local); if (local_offset & LOCAL_IS_WASM) { - // HACK: This case doesn't feel quite right. I think the - // only way to end up here is if you are taking the slice - // off a pointer that is a local. But this still feels - // like the wrong long term solution. + // CLEANUP structs-by-value + // This is a weird condition but it is relied on in a couple places including + // passing non-simple structs by value. -brendanfh 2020/09/18 WIL(WI_LOCAL_GET, local_offset); } else { @@ -1990,13 +2008,6 @@ EMIT_FUNC(location, AstTyped* expr) { case Ast_Kind_Field_Access: { AstFieldAccess* field = (AstFieldAccess *) expr; - if (field->expr->kind == Ast_Kind_Param && type_is_structlike_strict(field->expr->type)) { - u64 localidx = bh_imap_get(&mod->local_map, (u64) field->expr) + field->idx; - - WIL(WI_LOCAL_GET, localidx); - break; - } - u64 offset = 0; emit_field_access_location(mod, &code, field, &offset); if (offset != 0) { @@ -2026,17 +2037,28 @@ EMIT_FUNC(expression, AstTyped* expr) { switch (expr->kind) { case Ast_Kind_Param: { - u64 localidx = bh_imap_get(&mod->local_map, (u64) expr); - - if (type_is_structlike_strict(expr->type)) { - u32 mem_count = type_structlike_mem_count(expr->type); + AstLocal* param = (AstLocal *) expr; + u64 localidx = bh_imap_get(&mod->local_map, (u64) param); + + switch (param->ppt) { + case Param_Pass_By_Value: { + if (type_is_structlike_strict(expr->type)) { + u32 mem_count = type_structlike_mem_count(expr->type); + fori (idx, 0, mem_count) WIL(WI_LOCAL_GET, localidx + idx); + + } else { + WIL(WI_LOCAL_GET, localidx); + } + break; + } - fori (idx, 0, mem_count) { - WIL(WI_LOCAL_GET, localidx + idx); + case Param_Pass_By_Implicit_Pointer: { + WIL(WI_LOCAL_GET, localidx); + emit_load_instruction(mod, &code, expr->type, 0); + break; } - } else { - WIL(WI_LOCAL_GET, localidx); + default: assert(0); } break; @@ -2144,14 +2166,20 @@ EMIT_FUNC(expression, AstTyped* expr) { case Ast_Kind_Field_Access: { AstFieldAccess* field = (AstFieldAccess* ) expr; - if (field->expr->kind == Ast_Kind_Param && type_is_structlike_strict(field->expr->type)) { - u64 localidx = bh_imap_get(&mod->local_map, (u64) field->expr) + field->idx; + // CLEANUP structs-by-value + if (field->expr->kind == Ast_Kind_Param) { + AstLocal* param = (AstLocal *) field->expr; - WIL(WI_LOCAL_GET, localidx); - break; + if (param->ppt == Param_Pass_By_Value && !type_is_pointer(param->type)) { + u64 localidx = bh_imap_get(&mod->local_map, (u64) field->expr) + field->idx; + WIL(WI_LOCAL_GET, localidx); + break; + } } - if (field->expr->kind == Ast_Kind_StrLit) { + + // HACK + else if (field->expr->kind == Ast_Kind_StrLit) { StructMember smem; token_toggle_end(field->token); @@ -2462,15 +2490,23 @@ static i32 generate_type_idx(OnyxWasmModule* mod, Type* ft) { i32 params_left = param_count; while (params_left-- > 0) { if (type_is_structlike_strict(*param_type)) { - u32 mem_count = type_structlike_mem_count(*param_type); - StructMember smem; + if (!type_structlike_is_simple(*param_type)) { + // HACK!! + // CLEANUP structs-by-value + *(t++) = WASM_TYPE_INT32; - fori (i, 0, mem_count) { - type_lookup_member_by_idx(*param_type, i, &smem); - *(t++) = (char) onyx_type_to_wasm_type(smem.type); + } else { + 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); + } + + param_count += mem_count - 1; } - param_count += mem_count - 1; } else { *(t++) = (char) onyx_type_to_wasm_type(*param_type); } @@ -2582,12 +2618,23 @@ static void emit_function(OnyxWasmModule* mod, AstFunction* fd) { // NOTE: Generate the local map u64 localidx = 0; bh_arr_each(AstParam, param, fd->params) { - if (type_is_structlike_strict(param->local->type)) { - bh_imap_put(&mod->local_map, (u64) param->local, localidx | LOCAL_IS_WASM); - localidx += type_structlike_mem_count(param->local->type); + switch (param->local->ppt) { + case Param_Pass_By_Value: { + if (type_is_structlike_strict(param->local->type)) { + bh_imap_put(&mod->local_map, (u64) param->local, localidx | LOCAL_IS_WASM); + localidx += type_structlike_mem_count(param->local->type); + + break; + } + // fallthrough + } - } else { - bh_imap_put(&mod->local_map, (u64) param->local, localidx++ | LOCAL_IS_WASM); + case Param_Pass_By_Implicit_Pointer: { + bh_imap_put(&mod->local_map, (u64) param->local, localidx++ | LOCAL_IS_WASM); + break; + } + + default: assert(0); } } diff --git a/tests/i32map.onyx b/tests/i32map.onyx index 7425a97c..92385c87 100644 --- a/tests/i32map.onyx +++ b/tests/i32map.onyx @@ -5,24 +5,21 @@ package main use package core main :: proc (args: [] cstring) { - imap : I32Map(^string); + imap : I32Map(string); i32map_init(^imap); defer { print("Freeing map\n"); i32map_free(^imap); } - hello := "Hello "; - world := "World!"; - - i32map_put(^imap, 50, ^hello); - i32map_put(^imap, 1234, ^world); + i32map_put(^imap, 50, "Hello "); + i32map_put(^imap, 1234, "World!"); println(i32map_has(^imap, 50)); println(i32map_has(^imap, 51)); - print(*i32map_get(^imap, 50)); - println(*i32map_get(^imap, 1234)); + print(i32map_get(^imap, 50, "")); + println(i32map_get(^imap, 1234, "")); i32map_delete(^imap, 50); println(i32map_has(^imap, 50));