From: Brendan Hansen Date: Wed, 3 Mar 2021 19:58:13 +0000 (-0600) Subject: added '__initialize' intrinsic X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=86485168c49a092f2e48a4f4527f217f32ee1545;p=onyx.git added '__initialize' intrinsic --- diff --git a/bin/onyx b/bin/onyx index 9cf22eb9..b99437ea 100755 Binary files a/bin/onyx and b/bin/onyx differ diff --git a/core/builtin.onyx b/core/builtin.onyx index a0733bab..48635ad4 100644 --- a/core/builtin.onyx +++ b/core/builtin.onyx @@ -102,11 +102,18 @@ calloc :: (size: u32) -> rawptr do return raw_alloc(context.allocator, size); cresize :: (ptr: rawptr, size: u32) -> rawptr do return raw_resize(context.allocator, ptr, size); cfree :: (ptr: rawptr) do raw_free(context.allocator, ptr); -new :: ($T: type_expr, allocator := context.allocator) -> ^T { - res := cast(^T) calloc(sizeof T); - - // At some point, it would be nice to initialize the resulting memory, i.e. - // *res = T.{}; - - return res; +use package build_opts as build_opts +#if build_opts.Runtime != build_opts.Runtime_Custom { + use package core.intrinsics.wasm { __initialize } + + new :: ($T: type_expr, allocator := context.allocator, initialize := true) -> ^T { + res := cast(^T) calloc(sizeof T); + + // @Robustness: This should be a '#if' when those are added in procedures because + // otherwise the __initialize intrinsic is going to be generated no matter what. + // This could be a problem if the type is not something that can be initialized. + if initialize do __initialize(res); + + return res; + } } diff --git a/core/intrinsics/wasm.onyx b/core/intrinsics/wasm.onyx index 0d2d115d..fd7174e4 100644 --- a/core/intrinsics/wasm.onyx +++ b/core/intrinsics/wasm.onyx @@ -5,6 +5,8 @@ memory_grow :: (val: i32) -> i32 #intrinsic --- memory_copy :: (dst: rawptr, src: rawptr, count: i32) -> void #intrinsic --- memory_fill :: (dst: rawptr, byte: u8, count: i32) -> void #intrinsic --- +__initialize :: (val: ^$T) -> void #intrinsic --- + clz_i32 :: (val: i32) -> i32 #intrinsic --- ctz_i32 :: (val: i32) -> i32 #intrinsic --- popcnt_i32 :: (val: i32) -> i32 #intrinsic --- diff --git a/docs/bugs b/docs/bugs index a1ae819c..a0fa4ac2 100644 --- a/docs/bugs +++ b/docs/bugs @@ -4,6 +4,17 @@ List of known bugs: enum { Foo, Bar, Baz }; enum { Foo; Bar; Baz }; +[ ] Using a package in the middle of a procedures removes all remaining statements in the procedure. + This is mostly likely due to the changes made with use package statements being treated as entities now. + + use_package_breaking :: () { + println("Test 1"); + + use package foo + + println("Test 2"); + } + [ ] Aliasing in many cases does not work. For example: SomeNamespace :: struct { diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index 5ef1184d..7303159b 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -287,6 +287,8 @@ typedef enum OnyxIntrinsic { ONYX_INTRINSIC_MEMORY_SIZE, ONYX_INTRINSIC_MEMORY_GROW, ONYX_INTRINSIC_MEMORY_COPY, ONYX_INTRINSIC_MEMORY_FILL, + ONYX_INTRINSIC_INITIALIZE, + ONYX_INTRINSIC_I32_CLZ, ONYX_INTRINSIC_I32_CTZ, ONYX_INTRINSIC_I32_POPCNT, ONYX_INTRINSIC_I32_AND, ONYX_INTRINSIC_I32_OR, ONYX_INTRINSIC_I32_XOR, ONYX_INTRINSIC_I32_SHL, ONYX_INTRINSIC_I32_SLR, ONYX_INTRINSIC_I32_SAR, diff --git a/src/onyxastnodes.c b/src/onyxastnodes.c index 5bef0fcc..c1ae983c 100644 --- a/src/onyxastnodes.c +++ b/src/onyxastnodes.c @@ -490,6 +490,8 @@ b32 type_check_or_auto_cast(AstTyped** pnode, Type* type) { } Type* resolve_expression_type(AstTyped* node) { + if (node == NULL) return NULL; + if (node->kind == Ast_Kind_Compound) { bh_arr_each(AstTyped *, expr, ((AstCompound *) node)->exprs) { resolve_expression_type(*expr); diff --git a/src/onyxbuiltins.c b/src/onyxbuiltins.c index a0936dc6..0d8a9b4c 100644 --- a/src/onyxbuiltins.c +++ b/src/onyxbuiltins.c @@ -86,6 +86,8 @@ static IntrinsicMap builtin_intrinsics[] = { { "memory_copy", ONYX_INTRINSIC_MEMORY_COPY }, { "memory_fill", ONYX_INTRINSIC_MEMORY_FILL }, + { "__initialize", ONYX_INTRINSIC_INITIALIZE }, + { "clz_i32", ONYX_INTRINSIC_I32_CLZ }, { "ctz_i32", ONYX_INTRINSIC_I32_CTZ }, { "popcnt_i32", ONYX_INTRINSIC_I32_POPCNT }, @@ -385,4 +387,4 @@ void introduce_build_options(bh_allocator a) { AstNumLit* runtime_type = make_int_literal(a, context.options->runtime); symbol_builtin_introduce(p->scope, "Runtime", (AstNode *) runtime_type); -} \ No newline at end of file +} diff --git a/src/onyxchecker.c b/src/onyxchecker.c index 244c202b..1f5c7b06 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -1638,9 +1638,14 @@ CheckStatus check_overloaded_function(AstOverloadedFunction* func) { CheckStatus check_struct(AstStructType* s_node) { bh_arr_each(AstStructMember *, smem, s_node->members) { if ((*smem)->type_node == NULL && (*smem)->initial_value != NULL) { - check_expression(&(*smem)->initial_value); + CHECK(expression, &(*smem)->initial_value); fill_in_type((*smem)->initial_value); (*smem)->type = resolve_expression_type((*smem)->initial_value); + + if ((*smem)->type == NULL) { + onyx_report_error((*smem)->initial_value->token->pos, "Unable to deduce type of initial value. This is probably a compiler bug."); + return Check_Error; + } } } @@ -1658,6 +1663,26 @@ CheckStatus check_struct(AstStructType* s_node) { return Check_Success; } +CheckStatus check_struct_defaults(AstStructType* s_node) { + bh_arr_each(StructMember *, smem, s_node->stcache->Struct.memarr) { + if ((*smem)->initial_value && *(*smem)->initial_value) { + CHECK(expression, (*smem)->initial_value); + + if (!type_check_or_auto_cast((*smem)->initial_value, (*smem)->type)) { + onyx_report_error((*(*smem)->initial_value)->token->pos, + "Mismatched type for initial value, expected '%s', got '%s'.", + type_get_name((*smem)->type), + type_get_name((*(*smem)->initial_value)->type)); + return Check_Error; + } + + resolve_expression_type(*(*smem)->initial_value); + } + } + + return Check_Success; +} + CheckStatus check_function_header(AstFunction* func) { b32 expect_default_param = 0; b32 has_had_varargs = 0; @@ -1905,6 +1930,10 @@ void check_entity(Entity* ent) { cs = check_type(ent->type_alias); break; + case Entity_Type_Struct_Member_Default: + cs = check_struct_defaults((AstStructType *) ent->type_alias); + break; + case Entity_Type_Memory_Reservation_Type: cs = check_memres_type(ent->mem_res); break; diff --git a/src/onyxwasm.c b/src/onyxwasm.c index 505d00bf..2f9dc402 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -239,6 +239,7 @@ 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(enter_structured_block, StructuredBlockType sbt); EMIT_FUNC_NO_ARGS(leave_structured_block); @@ -1385,6 +1386,12 @@ EMIT_FUNC(intrinsic_call, AstCall* call) { } break; + case ONYX_INTRINSIC_INITIALIZE: { + Type* type_to_initialize = ((AstArgument *) call->args.values[0])->value->type->Pointer.elem; + emit_initialize_type(mod, &code, type_to_initialize, call->token); + break; + } + case ONYX_INTRINSIC_I32_CLZ: WI(WI_I32_CLZ); break; case ONYX_INTRINSIC_I32_CTZ: WI(WI_I32_CTZ); break; case ONYX_INTRINSIC_I32_POPCNT: WI(WI_I32_POPCNT); break; @@ -2424,6 +2431,24 @@ EMIT_FUNC(stack_leave, u32 unused) { *pcode = code; } +EMIT_FUNC(zero_value, WasmType wt) { + bh_arr(WasmInstruction) code = *pcode; + + switch (wt) { + case WASM_TYPE_INT32: WIL(WI_I32_CONST, 0); break; + case WASM_TYPE_INT64: WIL(WI_I64_CONST, 0); break; + case WASM_TYPE_FLOAT32: WIL(WI_F32_CONST, 0); break; + case WASM_TYPE_FLOAT64: WIL(WI_F64_CONST, 0); break; + case WASM_TYPE_VAR128: { + static u8 zero_v128[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + WIP(WI_V128_CONST, &zero_v128); + break; + } + } + + *pcode = code; +} + static i32 generate_type_idx(OnyxWasmModule* mod, Type* ft) { if (ft->kind != Type_Kind_Function) return -1; @@ -2608,20 +2633,8 @@ static void emit_function(OnyxWasmModule* mod, AstFunction* fd) { } } - { - WasmFuncType* ft = mod->types[type_idx]; - switch (ft->return_type) { - case WASM_TYPE_INT32: bh_arr_push(wasm_func.code, ((WasmInstruction){ WI_I32_CONST, 0x00 })); break; - case WASM_TYPE_INT64: bh_arr_push(wasm_func.code, ((WasmInstruction){ WI_I64_CONST, 0x00 })); break; - case WASM_TYPE_FLOAT32: bh_arr_push(wasm_func.code, ((WasmInstruction){ WI_F32_CONST, 0x00 })); break; - case WASM_TYPE_FLOAT64: bh_arr_push(wasm_func.code, ((WasmInstruction){ WI_F64_CONST, 0x00 })); break; - case WASM_TYPE_VAR128: { - static u8 zero_v128[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - bh_arr_push(wasm_func.code, ((WasmInstruction){ WI_V128_CONST, { .p = &zero_v128 } })); - break; - } - } - } + WasmFuncType* ft = mod->types[type_idx]; + emit_zero_value(mod, &wasm_func.code, ft->return_type); bh_arr_push(wasm_func.code, ((WasmInstruction){ WI_BLOCK_END, 0x00 })); diff --git a/src/onyxwasm_intrinsics.c b/src/onyxwasm_intrinsics.c index c65a3e8a..b39fad86 100644 --- a/src/onyxwasm_intrinsics.c +++ b/src/onyxwasm_intrinsics.c @@ -112,3 +112,42 @@ EMIT_FUNC_NO_ARGS(intrinsic_memory_fill) { *pcode = code; } + +EMIT_FUNC(initialize_type, Type* type, OnyxToken* where) { + bh_arr(WasmInstruction) code = *pcode; + + switch (type->kind) { + case Type_Kind_Pointer: + case Type_Kind_Basic: { + WasmType basic_type = onyx_type_to_wasm_type(type); + emit_zero_value(mod, &code, basic_type); + emit_store_instruction(mod, &code, type, 0); + break; + } + + case Type_Kind_Struct: { + u64 value_ptr = local_raw_allocate(mod->local_alloc, WASM_TYPE_PTR); + WIL(WI_LOCAL_SET, value_ptr); + + bh_arr_each(StructMember *, psmem, type->Struct.memarr) { + StructMember* smem = *psmem; + if (smem->initial_value == NULL || *smem->initial_value == NULL) continue; + + WIL(WI_LOCAL_GET, value_ptr); + emit_expression(mod, &code, *smem->initial_value); + emit_store_instruction(mod, &code, smem->type, smem->offset); + } + + local_raw_free(mod->local_alloc, WASM_TYPE_PTR); + break; + } + + default: + onyx_report_error(where->pos, + "Unable to initialize type, '%s'. The reason for this is largely due to the compiler not knowing what the initial value should be.", + type_get_name(type)); + break; + } + + *pcode = code; +} diff --git a/tests/operator_overload.onyx b/tests/operator_overload.onyx index f3aa5a90..41e6b3e4 100644 --- a/tests/operator_overload.onyx +++ b/tests/operator_overload.onyx @@ -103,4 +103,4 @@ main :: proc (args: [] cstr) { test_overload :: proc { proc (x: $T, y: T) -> T { return x; }, proc (x: $T, y: $R) -> R { return y; }, -} \ No newline at end of file +}