From: Brendan Hansen Date: Wed, 12 Aug 2020 16:03:29 +0000 (-0500) Subject: much refactoring; changed passing structs by value; stack frame management; added... X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=71f39ce49a3956c59ccd3be55ba331a26bdcb0a8;p=onyx.git much refactoring; changed passing structs by value; stack frame management; added onyxbuiltins --- diff --git a/Makefile b/Makefile index 6a575b28..f88f1fec 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,7 @@ OBJ_FILES=\ build/onyxlex.o \ build/onyxparser.o \ build/onyxtypes.o \ + build/onyxbuiltins.o \ build/onyxsempass.o \ build/onyxsymres.o \ build/onyxchecker.o \ diff --git a/docs/plan b/docs/plan index d0424cfe..fe7948b1 100644 --- a/docs/plan +++ b/docs/plan @@ -95,9 +95,6 @@ HOW: [X] Output 'drop' instruction for functions whose return value isn't used - [ ] Devise and implement a simple set of implicit type casting rules. - - Numeric literals always type cast to whatever type is needed (very flexible). - [X] Strings should work as pointers to data. - Literals should be placed in data section with pointers to the start. - Should strings be null-terminated or a length at the start of the string? @@ -161,13 +158,43 @@ HOW: [X] Include other directories to search for files + [X] remove struct splatting at parameters + - structs can still be passed by value however + - removed the implicit splatting feature + + [ ] package builtin + - Place to store builtin types and values + __heap_start + __stack_base + __stack_top + etc + + [ ] multiple return values + + [ ] multiple lvals and compound assignment + a := 2 + b := 5 + a, b = b, a; + + [ ] 'use' enums and packages at an arbitrary scope + + [ ] All code paths return correct value + + [ ] Add slices + - Arrays without a size + - Converted to a struct that looks like: + []T :: struct { + count : u32; + data : ^T; + } + [ ] Arrays need to be much better - Currently, they are basically just a pointer. - The length should be stored with the pointer - Dynamic resizing? - They are just very hard to use at the moment - [ ] 'use' enums and packages at an arbitrary scope + [ ] Type parameterized structs [ ] Array literals @@ -176,17 +203,15 @@ HOW: [ ] Top level variable initialization - Works for numeric literals - [ ] Better checking for casts - - Checking which things are allowed to cast to/from should be checked in the checker, - not in the wasm generatation - [X] Start work on evaluating compile time known values. - An expression marked COMPTIME will be reduced to its value in the parse tree. - [ ] All code paths return correct value - [ ] #initialize structs + [ ] Better checking for casts + - Checking which things are allowed to cast to/from should be checked in the checker, + not in the wasm generatation + [ ] Variadic arguments [ ] Switch statements diff --git a/include/bh.h b/include/bh.h index 6dbf7d1b..da64fb1e 100644 --- a/include/bh.h +++ b/include/bh.h @@ -545,6 +545,7 @@ typedef struct bh__arr { #define bh_arr_pop(arr) ((arr)[--bh__arrhead(arr)->length]) #define bh_arr_last(arr) ((arr)[bh__arrhead(arr)->length - 1]) #define bh_arr_end(arr, i) ((i) >= &(arr)[bh_arr_length(arr)]) +#define bh_arr_start(arr, i) ((i) < (arr)) #define bh_arr_new(allocator_, arr, cap) (bh__arr_grow((allocator_), (void**) &(arr), sizeof(*(arr)), cap)) #define bh_arr_free(arr) (bh__arr_free((void**) &(arr))) @@ -573,6 +574,7 @@ typedef struct bh__arr { #define bh_arr_fastdelete(arr, i) (arr[i] = arr[--bh__arrhead(arr)->length]) #define bh_arr_each(T, var, arr) for (T* var = (arr); !bh_arr_end((arr), var); var++) +#define bh_arr_rev_each(T, var, arr) for (T* var = &bh_arr_last((arr)); !bh_arr_start((arr), var); var--) b32 bh__arr_grow(bh_allocator alloc, void** arr, i32 elemsize, i32 cap); b32 bh__arr_shrink(void** arr, i32 elemsize, i32 cap); diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index 52032a45..ebb99d5e 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -149,7 +149,6 @@ typedef enum AstFlags { // Expression flags 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), @@ -485,7 +484,6 @@ extern AstBasicType basic_type_f64; extern AstBasicType basic_type_rawptr; extern AstNumLit builtin_heap_start; -extern AstGlobal builtin_stack_base; extern AstGlobal builtin_stack_top; typedef struct BuiltinSymbol { @@ -495,6 +493,8 @@ typedef struct BuiltinSymbol { extern const BuiltinSymbol builtin_symbols[]; +void initialize_builtins(); + // NOTE: Useful not inlined functions AstTyped* ast_reduce(bh_allocator a, AstTyped* node); diff --git a/include/onyxwasm.h b/include/onyxwasm.h index 911b63a7..b7998c82 100644 --- a/include/onyxwasm.h +++ b/include/onyxwasm.h @@ -334,7 +334,8 @@ typedef struct OnyxWasmModule { u32 next_datum_offset; u32 next_elem_idx; - u32 *stack_top_ptr, *stack_base_ptr; + i32 *stack_top_ptr; + u32 stack_base_idx; b32 has_stack_locals : 1; } OnyxWasmModule; diff --git a/onyx b/onyx index bbd03345..efe6385a 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/heap_resize_test.onyx b/progs/heap_resize_test.onyx index 75e3783f..a81de580 100644 --- a/progs/heap_resize_test.onyx +++ b/progs/heap_resize_test.onyx @@ -6,40 +6,63 @@ use package memory use package printing -proc #export "start" { - heap_init(); - - print("Creating initial memories"); - arr1 := cast(^u32) malloc(sizeof [10] u32); - print_hex(cast(u64) arr1); - - arr2 := cast(^u32) malloc(sizeof [40] u32); - print_hex(cast(u64) arr2); +Vec2 :: struct { + x : i32; + y : i32; +} - print("Freeing arr1"); - mfree(arr1); +other :: proc (use v: ^Vec2) -> i32 { + o : Vec2; + o.x = -100; + o.y = -10; - print("Resizing arr2 (shouldn't change location)"); - arr2 = cast(^u32) mresize(arr2, sizeof [60] u32); - print_hex(cast(u64) arr2); + return x * o.x + y * o.y; +} - print("Allocating arr3 (should be bigger than arr2)"); - arr3 := cast(^u32) malloc(sizeof [30] u32); - print_hex(cast(u64) arr3); - - print("Allocating arr1 (should be in the same place as before)"); - arr1 = cast(^u32) malloc(sizeof [5] u32); - print_hex(cast(u64) arr1); - for i: 0, 5 do arr1[i] = i; +proc #export "start" { + heap_init(); - print("Resizing arr1 (should be in the same place as before)"); - arr1 = cast(^u32) mresize(arr1, sizeof[10] u32); - print_hex(cast(u64) arr1); + v : Vec2; + v.x = 10; + v.y = 100; - print("Resizing arr1 (should have moved to after arr3)"); - arr1 = cast(^u32) mresize(arr1, sizeof[100] u32); - print_hex(cast(u64) arr1); + other(^v) |> print(); +} - print("Testing if the data was copied."); - for i: 0, 5 do print(arr1[i]); -} \ No newline at end of file +// proc #export "start2" { +// heap_init(); +// +// print("Creating initial memories"); +// arr1 := cast(^u32) malloc(sizeof [10] u32); +// print_hex(cast(u64) arr1); +// +// arr2 := cast(^u32) malloc(sizeof [40] u32); +// print_hex(cast(u64) arr2); +// +// print("Freeing arr1"); +// mfree(arr1); +// +// print("Resizing arr2 (shouldn't change location)"); +// arr2 = cast(^u32) mresize(arr2, sizeof [60] u32); +// print_hex(cast(u64) arr2); +// +// print("Allocating arr3 (should be bigger than arr2)"); +// arr3 := cast(^u32) malloc(sizeof [30] u32); +// print_hex(cast(u64) arr3); +// +// print("Allocating arr1 (should be in the same place as before)"); +// arr1 = cast(^u32) malloc(sizeof [5] u32); +// print_hex(cast(u64) arr1); +// for i: 0, 5 do arr1[i] = i; +// +// print("Resizing arr1 (should be in the same place as before)"); +// arr1 = cast(^u32) mresize(arr1, sizeof[10] u32); +// print_hex(cast(u64) arr1); +// +// print("Resizing arr1 (should have moved to after arr3)"); +// arr1 = cast(^u32) mresize(arr1, sizeof[100] u32); +// print_hex(cast(u64) arr1); +// +// print("Testing if the data was copied."); +// for i: 0, 5 do print(arr1[i]); +// }// \ No newline at end of file diff --git a/progs/stack_based.onyx b/progs/stack_based.onyx index a0643841..df4699c7 100644 --- a/progs/stack_based.onyx +++ b/progs/stack_based.onyx @@ -8,7 +8,7 @@ package main use package printing use package memory -sort :: proc (arr: [N]i32, cmp: proc (i32, i32) -> i32) -> [N]i32 { +sort :: proc (arr: [N]i32, cmp: proc (i32, i32) -> i32) -> [N] i32 { for i: 0, N { smallest_idx := i; @@ -66,6 +66,20 @@ clamp :: proc (v: i32, lo: i32, hi: i32) -> i32 { return v; } +// NOTE: Anonymous functions do NOT have closure, +// so in either of these function scopes, the +// parameter 'n' is not accessible. +// +// This is intended behavior since creating new +// procs at runtime is very difficult with WASM +stupid_idea :: proc (n: i32) -> proc () -> i32 { + if n == 1234 { + return proc -> i32 { return 5678; }; + } + + return proc -> i32 { return -1; }; +} + some_value := 20 + 30 * 4 + 15 / 5; start :: proc #export { @@ -75,7 +89,6 @@ start :: proc #export { print_hex(cast(u64) some_value); print("Hello, World!"); print_ptr(__heap_start); - print_ptr(__stack_base); print_ptr(__stack_top); print_bin(42l); print_hex(42l); @@ -96,25 +109,8 @@ start :: proc #export { print(arr[1]|>sumN()); print(summing(cast(^i32) arr[1])); - v1: Vec3; - v1.x = 2; - v1.y = 4; - v1.z = 10; - - v2: Vec3; - v2.x = 4; - v2.y = 2; - v2.z = 1; - - v3: Vec3; - vec_add(v1, v2, ^v3); - print(v3.x); - print(v3.y); - print(v3.z); - - print(v3|>mag_squared()); - print(10 |> ret_val(4)); + print(11 |> ret_val(5)); for i: 0, N do print(arr[1][i]); @@ -141,5 +137,10 @@ start :: proc #export { |> clamp(30, 100); print(val); - for i: 0, N do print(something[i] |> clamp(3, 6)); + for i: 0, N do + something[i] + |> clamp(3, 6) + |> print(); + + stupid_idea(1234)() |> print(); } \ No newline at end of file diff --git a/src/onyx.c b/src/onyx.c index 9c969e11..51c9a03c 100644 --- a/src/onyx.c +++ b/src/onyx.c @@ -350,19 +350,13 @@ static i32 onyx_compile(CompilerState* compiler_state) { bh_arr_fastdelete(compiler_state->queued_files, 0); } + initialize_builtins(); + // Add builtin one-time entities - bh_arr_push(compiler_state->prog_info.entities, ((Entity) { - .type = Entity_Type_Global_Header, - .global = &builtin_stack_base - })); bh_arr_push(compiler_state->prog_info.entities, ((Entity) { .type = Entity_Type_Global_Header, .global = &builtin_stack_top })); - bh_arr_push(compiler_state->prog_info.entities, ((Entity) { - .type = Entity_Type_Global, - .global = &builtin_stack_base - })); bh_arr_push(compiler_state->prog_info.entities, ((Entity) { .type = Entity_Type_Global, .global = &builtin_stack_top diff --git a/src/onyxbuiltins.c b/src/onyxbuiltins.c new file mode 100644 index 00000000..1a8c7bcc --- /dev/null +++ b/src/onyxbuiltins.c @@ -0,0 +1,45 @@ +#include "onyxastnodes.h" +#include "onyxtypes.h" + +AstBasicType basic_type_void = { { Ast_Kind_Basic_Type, 0, NULL, "void" }, &basic_types[Basic_Kind_Void] }; +AstBasicType basic_type_bool = { { Ast_Kind_Basic_Type, 0, NULL, "bool" }, &basic_types[Basic_Kind_Bool] }; +AstBasicType basic_type_i8 = { { Ast_Kind_Basic_Type, 0, NULL, "i8" }, &basic_types[Basic_Kind_I8] }; +AstBasicType basic_type_u8 = { { Ast_Kind_Basic_Type, 0, NULL, "u8" }, &basic_types[Basic_Kind_U8] }; +AstBasicType basic_type_i16 = { { Ast_Kind_Basic_Type, 0, NULL, "i16" }, &basic_types[Basic_Kind_I16] }; +AstBasicType basic_type_u16 = { { Ast_Kind_Basic_Type, 0, NULL, "u16" }, &basic_types[Basic_Kind_U16] }; +AstBasicType basic_type_i32 = { { Ast_Kind_Basic_Type, 0, NULL, "i32" }, &basic_types[Basic_Kind_I32] }; +AstBasicType basic_type_u32 = { { Ast_Kind_Basic_Type, 0, NULL, "u32" }, &basic_types[Basic_Kind_U32] }; +AstBasicType basic_type_i64 = { { Ast_Kind_Basic_Type, 0, NULL, "i64" }, &basic_types[Basic_Kind_I64] }; +AstBasicType basic_type_u64 = { { Ast_Kind_Basic_Type, 0, NULL, "u64" }, &basic_types[Basic_Kind_U64] }; +AstBasicType basic_type_f32 = { { Ast_Kind_Basic_Type, 0, NULL, "f32" }, &basic_types[Basic_Kind_F32] }; +AstBasicType basic_type_f64 = { { Ast_Kind_Basic_Type, 0, NULL, "f64" }, &basic_types[Basic_Kind_F64] }; +AstBasicType basic_type_rawptr = { { Ast_Kind_Basic_Type, 0, NULL, "rawptr" }, &basic_types[Basic_Kind_Rawptr] }; + +static OnyxToken builtin_heap_start_token = { Token_Type_Symbol, 12, "__heap_start ", { 0 } }; +static OnyxToken builtin_stack_top_token = { Token_Type_Symbol, 11, "__stack_top ", { 0 } }; +AstNumLit builtin_heap_start = { Ast_Kind_NumLit, Ast_Flag_Const, &builtin_heap_start_token, NULL, (AstType *) &basic_type_rawptr, NULL, 0 }; +AstGlobal builtin_stack_top = { Ast_Kind_Global, Ast_Flag_Const | Ast_Flag_Global_Stack_Top, &builtin_stack_top_token, NULL, (AstType *) &basic_type_rawptr, NULL }; + +const BuiltinSymbol builtin_symbols[] = { + { "void", (AstNode *) &basic_type_void }, + { "bool", (AstNode *) &basic_type_bool }, + { "i8", (AstNode *) &basic_type_i8 }, + { "u8", (AstNode *) &basic_type_u8 }, + { "i16", (AstNode *) &basic_type_i16 }, + { "u16", (AstNode *) &basic_type_u16 }, + { "i32", (AstNode *) &basic_type_i32 }, + { "u32", (AstNode *) &basic_type_u32 }, + { "i64", (AstNode *) &basic_type_i64 }, + { "u64", (AstNode *) &basic_type_u64 }, + { "f32", (AstNode *) &basic_type_f32 }, + { "f64", (AstNode *) &basic_type_f64 }, + { "rawptr", (AstNode *) &basic_type_rawptr }, + + { "__heap_start", (AstNode *) &builtin_heap_start }, + { "__stack_top", (AstNode *) &builtin_stack_top }, + + { NULL, NULL }, +}; + +void initialize_builtins() { +} \ No newline at end of file diff --git a/src/onyxchecker.c b/src/onyxchecker.c index 881b0cfa..99292d96 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -192,7 +192,7 @@ CHECK(call, AstCall* call) { if (check_expression(&call->callee)) return 1; - // NOTE: Check arguments and splat structs + // NOTE: Check arguments AstNode** prev_param = (AstNode **) &call->arguments; AstArgument* actual_param = call->arguments; while (actual_param != NULL) { @@ -205,43 +205,7 @@ CHECK(call, AstCall* call) { return 1; } - // NOTE: Splat structures into multiple arguments - if (actual_param->type->kind == Type_Kind_Struct) { - if (!type_struct_is_simple(actual_param->type)) { - onyx_message_add(Msg_Type_Literal, - actual_param->token->pos, - "can only splat simple structure. nested structures or struct of arrays is not allowed."); - return 1; - } - - bh_arr_each(StructMember *, smem, actual_param->type->Struct.memarr) { - AstFieldAccess* field = onyx_ast_node_new(semstate.node_allocator, sizeof(AstFieldAccess), Ast_Kind_Field_Access); - field->expr = actual_param->value; - - // HACK: Since dereferences are not used for struct types, we need a - // special case here. - if (field->expr->kind == Ast_Kind_Dereference) { - field->expr = ((AstDereference *) field->expr)->expr; - } - - field->offset = (*smem)->offset; - field->type = (*smem)->type; - - AstArgument* arg = onyx_ast_node_new(semstate.node_allocator, sizeof(AstArgument), Ast_Kind_Argument); - arg->value = (AstTyped *) field; - arg->type = field->type; - arg->token = actual_param->token; - arg->next = actual_param->next; - - call->arg_count++; - - *prev_param = (AstNode *) arg; - prev_param = (AstNode **) &arg->next; - } - } else { - prev_param = (AstNode **) &actual_param->next; - } - + prev_param = (AstNode **) &actual_param->next; actual_param = (AstArgument *) actual_param->next; } @@ -752,18 +716,6 @@ CHECK(field_access, AstFieldAccess** pfield) { return 1; } - if (field->expr->flags & Ast_Flag_Param_Splatted) { - AstLocal* param = (AstLocal *) field->expr; - - u32 steps = smem.idx + 1; - while (steps--) param = (AstLocal *) param->next; - - // NOTE: Not actually a field access - *pfield = (AstFieldAccess *) param; - token_toggle_end(field->token); - return 0; - } - field->offset = smem.offset; field->type = smem.type; @@ -1008,9 +960,6 @@ CHECK(struct, AstStructType* s_node) { } CHECK(function_header, AstFunction* func) { - i32 changed_params = 0; - - AstLocal **prev_param = &func->params; AstLocal *param = func->params; while (param != NULL) { fill_in_type((AstTyped *) param); @@ -1030,55 +979,10 @@ CHECK(function_header, AstFunction* func) { return 1; } - if (param->type->kind == Type_Kind_Struct) { - param->flags |= Ast_Flag_Param_Splatted; - - if (!type_struct_is_simple(param->type)) { - onyx_message_add(Msg_Type_Literal, - param->token->pos, - "only simple structures can be passed by value"); - return 1; - } - - changed_params = 1; - - AstLocal *first_new_param = NULL, *last_new_param = NULL; - AstLocal** insertion = prev_param; - bh_arr_each(StructMember *, smem, param->type->Struct.memarr) { - AstLocal* new_param = onyx_ast_node_new(semstate.node_allocator, sizeof(AstLocal), Ast_Kind_Param); - new_param->token = param->token; - new_param->type = (*smem)->type; - new_param->flags |= Ast_Flag_Const; - - if (first_new_param == NULL) first_new_param = new_param; - last_new_param = new_param; - - *insertion = new_param; - insertion = (AstLocal **) &new_param->next; - } - - *prev_param = first_new_param; - last_new_param->next = param->next; - param->next = (AstNode *) first_new_param; - - prev_param = (AstLocal **) &last_new_param->next; - } else { - prev_param = (AstLocal **) ¶m->next; - } - param = (AstLocal *) param->next; } - if (changed_params) { - // NOTE: Need to rebuild the function parameters in a special way once the are modified. - // This may/will get cleaned up at a later point. - - func->type = type_build_function_type( - semstate.node_allocator, func, - ((AstFunctionType *) func->type_node)->return_type); - } else { - fill_in_type((AstTyped *) func); - } + fill_in_type((AstTyped *) func); if ((func->flags & Ast_Flag_Exported) != 0) { if ((func->flags & Ast_Flag_Foreign) != 0) { diff --git a/src/onyxparser.c b/src/onyxparser.c index cbafcff7..f0d0279b 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -939,6 +939,7 @@ static AstType* parse_type(OnyxParser* parser) { bh_arr(AstType *) params = NULL; bh_arr_new(global_scratch_allocator, params, 4); + bh_arr_set_length(params, 0); expect_token(parser, '('); while (parser->curr->type != ')') { @@ -966,7 +967,8 @@ static AstType* parse_type(OnyxParser* parser) { new->param_count = param_count; new->return_type = return_type; - fori (i, 0, param_count - 1) new->params[i] = params[i]; + if (param_count > 0) + fori (i, 0, param_count - 1) new->params[i] = params[i]; *next_insertion = (AstType *) new; next_insertion = NULL; diff --git a/src/onyxsymres.c b/src/onyxsymres.c index 32821b07..a4a855ae 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -4,48 +4,6 @@ #include "onyxutils.h" -AstBasicType basic_type_void = { { Ast_Kind_Basic_Type, 0, NULL, "void" }, &basic_types[Basic_Kind_Void] }; -AstBasicType basic_type_bool = { { Ast_Kind_Basic_Type, 0, NULL, "bool" }, &basic_types[Basic_Kind_Bool] }; -AstBasicType basic_type_i8 = { { Ast_Kind_Basic_Type, 0, NULL, "i8" }, &basic_types[Basic_Kind_I8] }; -AstBasicType basic_type_u8 = { { Ast_Kind_Basic_Type, 0, NULL, "u8" }, &basic_types[Basic_Kind_U8] }; -AstBasicType basic_type_i16 = { { Ast_Kind_Basic_Type, 0, NULL, "i16" }, &basic_types[Basic_Kind_I16] }; -AstBasicType basic_type_u16 = { { Ast_Kind_Basic_Type, 0, NULL, "u16" }, &basic_types[Basic_Kind_U16] }; -AstBasicType basic_type_i32 = { { Ast_Kind_Basic_Type, 0, NULL, "i32" }, &basic_types[Basic_Kind_I32] }; -AstBasicType basic_type_u32 = { { Ast_Kind_Basic_Type, 0, NULL, "u32" }, &basic_types[Basic_Kind_U32] }; -AstBasicType basic_type_i64 = { { Ast_Kind_Basic_Type, 0, NULL, "i64" }, &basic_types[Basic_Kind_I64] }; -AstBasicType basic_type_u64 = { { Ast_Kind_Basic_Type, 0, NULL, "u64" }, &basic_types[Basic_Kind_U64] }; -AstBasicType basic_type_f32 = { { Ast_Kind_Basic_Type, 0, NULL, "f32" }, &basic_types[Basic_Kind_F32] }; -AstBasicType basic_type_f64 = { { Ast_Kind_Basic_Type, 0, NULL, "f64" }, &basic_types[Basic_Kind_F64] }; -AstBasicType basic_type_rawptr = { { Ast_Kind_Basic_Type, 0, NULL, "rawptr" }, &basic_types[Basic_Kind_Rawptr] }; - -static OnyxToken builtin_heap_start_token = { Token_Type_Symbol, 12, "__heap_start ", { 0 } }; -static OnyxToken builtin_stack_base_token = { Token_Type_Symbol, 12, "__stack_base ", { 0 } }; -static OnyxToken builtin_stack_top_token = { Token_Type_Symbol, 11, "__stack_top ", { 0 } }; -AstNumLit builtin_heap_start = { Ast_Kind_NumLit, Ast_Flag_Const, &builtin_heap_start_token, NULL, (AstType *) &basic_type_rawptr, NULL, 0 }; -AstGlobal builtin_stack_base = { Ast_Kind_Global, Ast_Flag_Const | Ast_Flag_Global_Stack_Base, &builtin_stack_base_token, NULL, (AstType *) &basic_type_rawptr, NULL }; -AstGlobal builtin_stack_top = { Ast_Kind_Global, Ast_Flag_Const | Ast_Flag_Global_Stack_Top, &builtin_stack_top_token, NULL, (AstType *) &basic_type_rawptr, NULL }; - -const BuiltinSymbol builtin_symbols[] = { - { "void", (AstNode *) &basic_type_void }, - { "bool", (AstNode *) &basic_type_bool }, - { "i8", (AstNode *) &basic_type_i8 }, - { "u8", (AstNode *) &basic_type_u8 }, - { "i16", (AstNode *) &basic_type_i16 }, - { "u16", (AstNode *) &basic_type_u16 }, - { "i32", (AstNode *) &basic_type_i32 }, - { "u32", (AstNode *) &basic_type_u32 }, - { "i64", (AstNode *) &basic_type_i64 }, - { "u64", (AstNode *) &basic_type_u64 }, - { "f32", (AstNode *) &basic_type_f32 }, - { "f64", (AstNode *) &basic_type_f64 }, - { "rawptr", (AstNode *) &basic_type_rawptr }, - - { "__heap_start", (AstNode *) &builtin_heap_start }, - { "__stack_base", (AstNode *) &builtin_stack_base }, - { "__stack_top", (AstNode *) &builtin_stack_top }, - - { NULL, NULL }, -}; static void scope_enter(Scope* new_scope); static void scope_leave(); @@ -239,6 +197,7 @@ static void symres_ufc(AstBinaryOp** ufc) { AstArgument* implicit_arg = onyx_ast_node_new(semstate.node_allocator, sizeof(AstArgument), Ast_Kind_Argument); + implicit_arg->token = (*ufc)->left->token; implicit_arg->value = (*ufc)->left; implicit_arg->next = (AstNode *) call_node->arguments; diff --git a/src/onyxtypes.c b/src/onyxtypes.c index bf8d2ce1..a70fc5f4 100644 --- a/src/onyxtypes.c +++ b/src/onyxtypes.c @@ -168,8 +168,10 @@ b32 types_are_compatible(Type* t1, Type* t2) { if (!types_are_compatible(t1->Function.return_type, t2->Function.return_type)) return 0; - fori (i, 0, t1->Function.param_count - 1) { - if (!types_are_compatible(t1->Function.params[i], t2->Function.params[i])) return 0; + if (t1->Function.param_count > 0) { + fori (i, 0, t1->Function.param_count - 1) { + if (!types_are_compatible(t1->Function.params[i], t2->Function.params[i])) return 0; + } } return 1; diff --git a/src/onyxwasm.c b/src/onyxwasm.c index f3355734..452119a6 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -250,7 +250,7 @@ COMPILE_FUNC(function_body, AstFunction* fd); COMPILE_FUNC(block, AstBlock* block); COMPILE_FUNC(statement, AstNode* stmt); COMPILE_FUNC(assignment, AstBinaryOp* assign); -COMPILE_FUNC(store_instruction, Type* type, u32 alignment, u32 offset); +COMPILE_FUNC(store_instruction, Type* type, u32 offset); COMPILE_FUNC(load_instruction, Type* type, u32 offset); COMPILE_FUNC(if, AstIf* if_node); COMPILE_FUNC(while, AstWhile* while_node); @@ -364,7 +364,7 @@ COMPILE_FUNC(assignment, AstBinaryOp* assign) { 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); + compile_store_instruction(mod, &code, lval->type, offset); } } else if (lval->kind == Ast_Kind_Global) { @@ -378,10 +378,7 @@ COMPILE_FUNC(assignment, AstBinaryOp* assign) { compile_expression(mod, &code, deref->expr); compile_expression(mod, &code, assign->right); - compile_store_instruction(mod, &code, - deref->type, - type_get_alignment_log2(deref->type), - 0); + compile_store_instruction(mod, &code, deref->type, 0); } else if (lval->kind == Ast_Kind_Array_Access) { AstArrayAccess* aa = (AstArrayAccess *) lval; @@ -390,10 +387,7 @@ COMPILE_FUNC(assignment, AstBinaryOp* assign) { compile_array_access_location(mod, &code, aa, &offset); compile_expression(mod, &code, assign->right); - compile_store_instruction(mod, &code, - aa->type, - type_get_alignment_log2(aa->type), - offset); + compile_store_instruction(mod, &code, aa->type, offset); } else if (lval->kind == Ast_Kind_Field_Access) { AstFieldAccess* field = (AstFieldAccess *) lval; @@ -402,10 +396,7 @@ COMPILE_FUNC(assignment, AstBinaryOp* assign) { compile_field_access_location(mod, &code, field, &offset); compile_expression(mod, &code, assign->right); - compile_store_instruction(mod, &code, - field->type, - type_get_alignment_log2(field->type), - offset); + compile_store_instruction(mod, &code, field->type, offset); } else { assert(("Invalid lval", 0)); } @@ -413,9 +404,11 @@ COMPILE_FUNC(assignment, AstBinaryOp* assign) { *pcode = code; } -COMPILE_FUNC(store_instruction, Type* type, u32 alignment, u32 offset) { +COMPILE_FUNC(store_instruction, Type* type, u32 offset) { bh_arr(WasmInstruction) code = *pcode; + u32 alignment = type_get_alignment_log2(type); + if (type->kind == Type_Kind_Enum) { type = type->Enum.backing; } @@ -452,6 +445,8 @@ COMPILE_FUNC(store_instruction, Type* type, u32 alignment, u32 offset) { COMPILE_FUNC(load_instruction, Type* type, u32 offset) { bh_arr(WasmInstruction) code = *pcode; + assert(("Should use compile_struct_load instead", type->kind != Type_Kind_Struct)); + if (type->kind == Type_Kind_Array) { if (offset != 0) { WID(WI_I32_CONST, offset); @@ -591,7 +586,7 @@ COMPILE_FUNC(for, AstFor* for_node) { } 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); + compile_store_instruction(mod, &code, var->type, offset); } WID(WI_BLOCK_START, 0x40); @@ -628,7 +623,7 @@ COMPILE_FUNC(for, AstFor* for_node) { compile_load_instruction(mod, &code, var->type, offset); compile_expression(mod, &code, for_node->step); WI(add_instr); - compile_store_instruction(mod, &code, var->type, type_get_alignment_log2(var->type), offset); + compile_store_instruction(mod, &code, var->type, offset); } compile_deferred_stmts(mod, &code, (AstNode *) for_node); @@ -948,16 +943,40 @@ COMPILE_FUNC(field_access_location, AstFieldAccess* field, u64* offset_return) { COMPILE_FUNC(local_location, AstLocal* local, u64* offset_return) { bh_arr(WasmInstruction) code = *pcode; - i32 stack_base_idx = (i32) bh_imap_get(&mod->index_map, (u64) &builtin_stack_base); i32 local_offset = (i32) bh_imap_get(&mod->local_map, (u64) local); - WID(WI_GLOBAL_GET, stack_base_idx); + WID(WI_LOCAL_GET, mod->stack_base_idx); *offset_return += local_offset; *pcode = code; } +COMPILE_FUNC(struct_load, AstTyped* expr) { + bh_arr(WasmInstruction) code = *pcode; + + assert(expr->type->kind == Type_Kind_Struct); + + u64 offset = 0; + + bh_arr_each(StructMember *, smem, expr->type->Struct.memarr) { + offset = 0; + + switch (expr->kind) { + case Ast_Kind_Local: compile_local_location(mod, &code, (AstLocal *) expr, &offset); break; + case Ast_Kind_Dereference: compile_expression(mod, &code, ((AstDereference *) expr)->expr); break; + case Ast_Kind_Array_Access: compile_array_access_location(mod, &code, (AstArrayAccess *) expr, &offset); break; + case Ast_Kind_Field_Access: compile_field_access_location(mod, &code, (AstFieldAccess *) expr, &offset); break; + + default: assert(0); + } + + compile_load_instruction(mod, &code, (*smem)->type, offset + (*smem)->offset); + } + + *pcode = code; +} + COMPILE_FUNC(expression, AstTyped* expr) { bh_arr(WasmInstruction) code = *pcode; @@ -974,6 +993,11 @@ COMPILE_FUNC(expression, AstTyped* expr) { if (tmp & LOCAL_IS_WASM) { WID(WI_LOCAL_GET, (u32) (tmp & ~LOCAL_IS_WASM)); } else { + if (expr->type->kind == Type_Kind_Struct) { + compile_struct_load(mod, &code, expr); + break; + } + u64 offset = 0; compile_local_location(mod, &code, (AstLocal *) expr, &offset); @@ -1092,6 +1116,11 @@ COMPILE_FUNC(expression, AstTyped* expr) { } case Ast_Kind_Dereference: { + if (expr->type->kind == Type_Kind_Struct) { + compile_struct_load(mod, &code, expr); + break; + } + AstDereference* deref = (AstDereference *) expr; compile_expression(mod, &code, deref->expr); compile_load_instruction(mod, &code, deref->type, 0); @@ -1099,6 +1128,11 @@ COMPILE_FUNC(expression, AstTyped* expr) { } case Ast_Kind_Array_Access: { + if (expr->type->kind == Type_Kind_Struct) { + compile_struct_load(mod, &code, expr); + break; + } + AstArrayAccess* aa = (AstArrayAccess *) expr; u64 offset = 0; compile_array_access_location(mod, &code, aa, &offset); @@ -1107,8 +1141,26 @@ COMPILE_FUNC(expression, AstTyped* expr) { } case Ast_Kind_Field_Access: { + if (expr->type->kind == Type_Kind_Struct) { + compile_struct_load(mod, &code, expr); + break; + } + AstFieldAccess* field = (AstFieldAccess* ) expr; + if (field->expr->kind == Ast_Kind_Param && field->expr->type->kind == Type_Kind_Struct) { + StructMember smem; + + token_toggle_end(field->token); + type_struct_lookup_member(field->expr->type, field->token->text, &smem); + token_toggle_end(field->token); + + i32 localidx = (i32) bh_imap_get(&mod->local_map, (u64) field->expr) + smem.idx; + + WID(WI_LOCAL_GET, localidx); + break; + } + u64 offset = 0; compile_field_access_location(mod, &code, field, &offset); compile_load_instruction(mod, &code, field->type, offset); @@ -1302,21 +1354,12 @@ COMPILE_FUNC(stack_enter, u64 stacksize) { bh_arr(WasmInstruction) code = *pcode; u32 stack_top_idx = bh_imap_get(&mod->index_map, (u64) &builtin_stack_top); - u32 stack_base_idx = bh_imap_get(&mod->index_map, (u64) &builtin_stack_base); WID(WI_GLOBAL_GET, stack_top_idx); - WID(WI_GLOBAL_GET, stack_base_idx); - WID(WI_I32_STORE, ((WasmInstructionData) { 2, 0 })); - WID(WI_GLOBAL_GET, stack_top_idx); - WID(WI_I32_CONST, 4); - WI(WI_I32_ADD); - WID(WI_GLOBAL_SET, stack_top_idx); - WID(WI_GLOBAL_GET, stack_top_idx); - WID(WI_GLOBAL_SET, stack_base_idx); - WID(WI_GLOBAL_GET, stack_top_idx); + WID(WI_LOCAL_TEE, mod->stack_base_idx); WID(WI_I32_CONST, stacksize); WI(WI_I32_ADD); - WID(WI_GLOBAL_SET, stack_top_idx); + WID(WI_GLOBAL_SET, stack_top_idx); *pcode = code; } @@ -1325,20 +1368,10 @@ 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); - u32 stack_base_idx = bh_imap_get(&mod->index_map, (u64) &builtin_stack_base); - - WID(WI_GLOBAL_GET, stack_base_idx); - WID(WI_GLOBAL_SET, stack_top_idx); - WID(WI_GLOBAL_GET, stack_top_idx); - WID(WI_I32_CONST, 4); - WI(WI_I32_SUB); + WID(WI_LOCAL_GET, mod->stack_base_idx); WID(WI_GLOBAL_SET, stack_top_idx); - WID(WI_GLOBAL_GET, stack_top_idx); - WID(WI_I32_LOAD, ((WasmInstructionData) { 2, 0 })); - WID(WI_GLOBAL_SET, stack_base_idx); - *pcode = code; } @@ -1352,9 +1385,17 @@ static i32 generate_type_idx(OnyxWasmModule* mod, Type* ft) { i32 param_count = ft->Function.param_count; i32 params_left = param_count; while (params_left-- > 0) { - // HACK: Using these directly as part of a string feels weird but they are - // valid characters so I don't think it is going to be much of an issue - *(t++) = (char) onyx_type_to_wasm_type(*param_type); + if ((*param_type)->kind == Type_Kind_Struct) { + bh_arr_each(StructMember *, smem, (*param_type)->Struct.memarr) { + *(t++) = (char) onyx_type_to_wasm_type((*smem)->type); + } + + param_count += (*param_type)->Struct.mem_count - 1; + + } else { + *(t++) = (char) onyx_type_to_wasm_type(*param_type); + } + param_type++; } *(t++) = ':'; @@ -1448,7 +1489,7 @@ static void compile_function(OnyxWasmModule* mod, AstFunction* fd) { WasmFunc wasm_func = { .type_idx = type_idx, .locals = { - .i32_count = 0, + .i32_count = 1, // NOTE: for the old stack base .i64_count = 0, .f32_count = 0, .f64_count = 0, @@ -1478,11 +1519,19 @@ static void compile_function(OnyxWasmModule* mod, AstFunction* fd) { // 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++ | LOCAL_IS_WASM); + if (param->type->kind == Type_Kind_Struct) { + bh_imap_put(&mod->local_map, (u64) param, localidx); + localidx += param->type->Struct.mem_count; + + } else { + 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 }; + mod->stack_base_idx = 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; @@ -1588,8 +1637,6 @@ static void compile_global(OnyxWasmModule* module, AstGlobal* global) { if (global->flags & Ast_Flag_Global_Stack_Top) module->stack_top_ptr = &bh_arr_last(module->globals).initial_value[0].data.i1; - if (global->flags & Ast_Flag_Global_Stack_Base) - module->stack_base_ptr = &bh_arr_last(module->globals).initial_value[0].data.i1; } @@ -1785,7 +1832,7 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) { .structured_jump_target = NULL, .stack_top_ptr = NULL, - .stack_base_ptr = NULL, + .stack_base_idx = 0, }; bh_arr_new(alloc, module.types, 4); @@ -1826,17 +1873,14 @@ void onyx_wasm_module_compile(OnyxWasmModule* module, ProgramInfo* program) { bh_arr_each(Entity, entity, program->entities) { - if (module->stack_base_ptr) { - *module->stack_base_ptr = module->next_datum_offset; + if (module->stack_top_ptr) { + *module->stack_top_ptr = module->next_datum_offset; - if (*module->stack_base_ptr % 16 != 0) { - *module->stack_base_ptr += 16 - (*module->stack_base_ptr % 16); + if (*module->stack_top_ptr % 16 != 0) { + *module->stack_top_ptr += 16 - (*module->stack_top_ptr % 16); } - if (module->stack_top_ptr) - *module->stack_top_ptr = *module->stack_base_ptr; - - builtin_heap_start.value.i = *module->stack_base_ptr + (1 << 16); + builtin_heap_start.value.i = *module->stack_top_ptr + (1 << 16); if (builtin_heap_start.value.i % 16 != 0) { builtin_heap_start.value.i += 16 - (builtin_heap_start.value.i % 16); }