structures that wrap a basic type are treated differently
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 16 Jan 2023 19:08:08 +0000 (13:08 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 16 Jan 2023 19:08:08 +0000 (13:08 -0600)
compiler/include/astnodes.h
compiler/include/types.h
compiler/src/types.c
compiler/src/wasm_emit.c
core/onyx/cptr.onyx

index 21dc6ea50ce58f460a8aa6f57d2f6e03b1a6119f..cb0a4bdf78abcbc158a4fe73c38d1a217c3be014 100644 (file)
@@ -1887,7 +1887,7 @@ static inline CallingConvention type_function_get_cc(Type* type) {
 }
 
 static inline ParamPassType type_get_param_pass(Type* type) {
-    if (type_is_structlike_strict(type)) {
+    if (type_is_structlike_strict(type) && !type_struct_is_just_one_basic_value(type)) {
         if (type_structlike_is_simple(type)) return Param_Pass_By_Multiple_Values;
         else                                 return Param_Pass_By_Implicit_Pointer;
     }
index b62ca12eef6bfc9cbfc15ee2cf86cd15a6c2ea41..6b164d2e59074a1be887c2784a8cf700cd3503c0 100644 (file)
@@ -244,5 +244,6 @@ u32 type_structlike_mem_count(Type* type);
 u32 type_structlike_is_simple(Type* type);
 b32 type_is_sl_constructable(Type* type);
 b32 type_struct_constructed_from_poly_struct(Type* struct_type, struct AstType* from);
+Type* type_struct_is_just_one_basic_value(Type *type);
 
 #endif // #ifndef ONYX_TYPES
index 887c73ecfb41747ff36b4abb6ce155cdb32f5bbf..b12f7c67a20a2430f60c5113ab84f5a55981ceba 100644 (file)
@@ -1449,7 +1449,7 @@ u32 type_structlike_is_simple(Type* type) {
         case Type_Kind_Slice:    return 1;
         case Type_Kind_VarArgs:  return 1;
         case Type_Kind_DynArray: return 0;
-        case Type_Kind_Struct:   return 0; // :StructAsm type_struct_is_simple(type);
+        case Type_Kind_Struct:   return 0;
         default: return 0;
     }
 }
@@ -1470,3 +1470,11 @@ b32 type_struct_constructed_from_poly_struct(Type* struct_type, struct AstType*
 
     return struct_type->Struct.constructed_from == from;
 }
+
+Type* type_struct_is_just_one_basic_value(Type *type) {
+    if (!type)                                                 return NULL;
+    if (type->kind != Type_Kind_Struct)                        return NULL;
+    if (bh_arr_length(type->Struct.memarr) != 1)               return NULL;
+    if (type->Struct.memarr[0]->type->kind != Type_Kind_Basic) return NULL;
+    return type->Struct.memarr[0]->type;
+}
index 12f6235d7129cffb1333682d13fe7322ed9f9423..1a9c7065fbc3e2b651496212f8ce360b11dd74a5 100644 (file)
@@ -27,6 +27,8 @@
 #define WASM_TYPE_VOID    0x00
 
 static b32 onyx_type_is_stored_in_memory(Type *type) {
+    if (type_struct_is_just_one_basic_value(type)) return 0;
+
     return type->kind == Type_Kind_Struct
         || type->kind == Type_Kind_DynArray;
 }
@@ -34,6 +36,11 @@ static b32 onyx_type_is_stored_in_memory(Type *type) {
 static WasmType onyx_type_to_wasm_type(Type* type) {
     if (onyx_type_is_stored_in_memory(type)) return WASM_TYPE_PTR;
 
+    if (type_struct_is_just_one_basic_value(type)) {
+        Type *asdf = type_struct_is_just_one_basic_value(type);
+        return onyx_type_to_wasm_type(asdf);
+    }
+
     if (type->kind == Type_Kind_Slice)    return WASM_TYPE_VOID;
     if (type->kind == Type_Kind_Compound) return WASM_TYPE_VOID;
     if (type->kind == Type_Kind_Enum)     return onyx_type_to_wasm_type(type->Enum.backing);
@@ -821,7 +828,7 @@ EMIT_FUNC(assignment, AstBinaryOp* assign) {
 
             u64 localidx = bh_imap_get(&mod->local_map, (u64) lval);
 
-            if (lval->kind == Ast_Kind_Param && type_is_structlike_strict(lval->type)) {
+            if (lval->kind == Ast_Kind_Param && onyx_type_is_multiple_wasm_values(lval->type)) {
                 u32 mem_count = type_structlike_mem_count(lval->type);
                 fori (i, 0, mem_count) WIL(assign->token, WI_LOCAL_SET, localidx + i);
 
@@ -951,10 +958,13 @@ EMIT_FUNC(store_instruction, Type* type, u32 offset) {
         return;
     }
 
+    if (type->kind == Type_Kind_Struct)   type = type_struct_is_just_one_basic_value(type);
     if (type->kind == Type_Kind_Enum)     type = type->Enum.backing;
     if (type->kind == Type_Kind_Distinct) type = type->Distinct.base_type;
     if (type->kind == Type_Kind_Function) type = &basic_types[Basic_Kind_U32];
 
+    assert(type);
+
     u32 alignment = type_get_alignment_log2(type);
 
     i32 store_size  = type_size_of(type);
@@ -1060,10 +1070,13 @@ EMIT_FUNC(load_instruction, Type* type, u32 offset) {
         return;
     }
 
+    if (type->kind == Type_Kind_Struct)   type = type_struct_is_just_one_basic_value(type);
     if (type->kind == Type_Kind_Enum)     type = type->Enum.backing;
     if (type->kind == Type_Kind_Distinct) type = type->Distinct.base_type;
     if (type->kind == Type_Kind_Function) type = &basic_types[Basic_Kind_U32];
 
+    assert(type);
+
     i32 load_size   = type_size_of(type);
     i32 is_basic    = type->kind == Type_Kind_Basic || type->kind == Type_Kind_Pointer;
 
@@ -1694,7 +1707,6 @@ EMIT_FUNC(defer_code, WasmInstruction* deferred_code, u32 code_count) {
 
 EMIT_FUNC(deferred_stmt, DeferredStmt deferred_stmt) {
     bh_arr(WasmInstruction) code = *pcode;
-
     if (deferred_stmt.defer_node) {
         WI(deferred_stmt.defer_node->token, WI_NOP);
     }
@@ -2983,32 +2995,8 @@ EMIT_FUNC(array_store, Type* type, u32 offset) {
     WI(NULL, WI_I32_NE);
     emit_enter_structured_block(mod, &code, SBT_Basic_If, NULL);
 
-    //
-    // CLEANUP: Most of these cases could be much shorter if they used existing intrinsics.
-    //
-    if (elem_count <= 2) {
-        // Inline copying for a small number of elements. It still may be faster to do this in a tight loop.
-
-        fori (i, 0, elem_count) {
-            if (bh_arr_last(code).type == WI_LOCAL_SET && (u64) bh_arr_last(code).data.l == lptr_local)
-                bh_arr_last(code).type = WI_LOCAL_TEE;
-            else
-                WIL(NULL, WI_LOCAL_GET, lptr_local);
-
-            WIL(NULL, WI_LOCAL_GET, rptr_local);
-            emit_load_instruction(mod, &code, elem_type, i * elem_size);
-
-            emit_store_instruction(mod, &code, elem_type, i * elem_size + offset);
-        }
-
-    } else if (context.options->use_post_mvp_features) {
-        // Use a simple memory copy if it is available. This may be what happens in the case below too at a later time.
-
-        if (bh_arr_last(code).type == WI_LOCAL_SET && (u64) bh_arr_last(code).data.l == lptr_local)
-            bh_arr_last(code).type = WI_LOCAL_TEE;
-        else
-            WIL(NULL, WI_LOCAL_GET, lptr_local);
-
+    {
+        WIL(NULL, WI_LOCAL_GET, lptr_local);
         if (offset != 0) {
             WIL(NULL, WI_PTR_CONST, offset);
             WI(NULL, WI_PTR_ADD);
@@ -3016,43 +3004,7 @@ EMIT_FUNC(array_store, Type* type, u32 offset) {
 
         WIL(NULL, WI_LOCAL_GET, rptr_local);
         WIL(NULL, WI_I32_CONST, elem_count * elem_size);
-        WI(NULL, WI_MEMORY_COPY);
-
-    } else {
-        // Emit a loop that copies the memory. This could be switched to a tight loop that just copies word per word.
-
-        u64 offset_local = local_raw_allocate(mod->local_alloc, WASM_TYPE_PTR);
-        WIL(NULL, WI_PTR_CONST, 0);
-        WIL(NULL, WI_LOCAL_SET, offset_local);
-
-        WID(NULL, WI_BLOCK_START, 0x40);
-        WID(NULL, WI_LOOP_START, 0x40);
-            WIL(NULL, WI_LOCAL_GET, offset_local);
-            WIL(NULL, WI_LOCAL_GET, lptr_local);
-            WI(NULL, WI_PTR_ADD);
-
-            WIL(NULL, WI_LOCAL_GET, offset_local);
-            WIL(NULL, WI_LOCAL_GET, rptr_local);
-            WI(NULL, WI_PTR_ADD);
-
-            emit_load_instruction(mod, &code, elem_type, 0);
-            emit_store_instruction(mod, &code, elem_type, offset);
-
-            WIL(NULL, WI_LOCAL_GET, offset_local);
-            WIL(NULL, WI_PTR_CONST, elem_size);
-            WI(NULL, WI_PTR_ADD);
-            WIL(NULL, WI_LOCAL_TEE, offset_local);
-
-            WIL(NULL, WI_PTR_CONST, elem_count * elem_size);
-            WI(NULL, WI_PTR_GE);
-            WID(NULL, WI_COND_JUMP, 0x01);
-
-            WID(NULL, WI_JUMP, 0x00);
-
-        WI(NULL, WI_LOOP_END);
-        WI(NULL, WI_BLOCK_END);
-
-        local_raw_free(mod->local_alloc, WASM_TYPE_PTR);
+        emit_wasm_copy(mod, &code, NULL);
     }
 
     WI(NULL, WI_ELSE);
@@ -3449,6 +3401,12 @@ EMIT_FUNC(expression, AstTyped* expr) {
                 WIL(NULL, WI_LOCAL_GET, localidx);
             }
 
+            else if (field->expr->kind == Ast_Kind_Param && type_struct_is_just_one_basic_value(field->expr->type)) {
+                u64 localidx = bh_imap_get(&mod->local_map, (u64) field->expr);
+                assert(localidx & LOCAL_IS_WASM);
+                WIL(NULL, WI_LOCAL_GET, localidx);
+            }
+
             else if (is_lval((AstNode *) field->expr) || type_is_pointer(field->expr->type)) {
                 u64 offset = 0;
                 emit_field_access_location(mod, &code, field, &offset);
@@ -3986,13 +3944,6 @@ static i32 generate_type_idx(OnyxWasmModule* mod, Type* ft) {
 
     WasmType return_type = onyx_type_to_wasm_type(ft->Function.return_type);
 
-    /*
-    if (ft->Function.return_type->kind == Type_Kind_Struct
-        && type_linear_member_count(ft->Function.return_type) == 1) {
-        return_type = onyx_type_to_wasm_type(ft->Function.return_type->Struct.linear_members[0].type);
-    }
-    */
-
     *(t++) = (char) return_type;
     *t = '\0';
 
index f1713f002985aa0469faa2e7f19c3c80b5ef10d4..a27aab1d20a03880b98032760515352bf31915a4 100644 (file)
@@ -1,9 +1,11 @@
 package core
 
-#tag conv.Custom_Format.{ #solidify cptr.format {T=T} }
+@conv.Custom_Format.{ #solidify cptr.format {T=T} }
 cptr :: struct (T: type_expr) {
     data: u64;
+}
 
+#inject cptr {
     make :: macro (ptr: ^$T) -> cptr(T) {
         __cptr_make :: __cptr_make
         return .{ __cptr_make(ptr) };