From 57085686bf7223e2305720383f4e00695321919a Mon Sep 17 00:00:00 2001 From: Zoltan Varga Date: Mon, 20 Nov 2023 01:28:42 -0500 Subject: [PATCH] [wasm] Allow scalar valuetypes with r4/r8 members. (#94969) --- src/mono/mono/mini/interp/interp.c | 6 +++- src/mono/mono/mini/mini-generic-sharing.c | 40 +++++++++++++---------- src/mono/mono/mini/mini-llvm.c | 8 ++--- src/mono/mono/mini/mini-wasm.c | 31 +++++++++++++----- src/mono/mono/mini/mini-wasm.h | 2 +- src/mono/mono/mini/mini.h | 2 ++ 6 files changed, 57 insertions(+), 32 deletions(-) diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index c35a61ded1167..1e6903672b475 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -1466,9 +1466,13 @@ build_args_from_sig (MonoMethodSignature *sig, InterpFrame *frame) #ifdef HOST_WASM { + MonoType *etype; + /* Scalar vtypes are passed by value */ - if (mini_wasm_is_scalar_vtype (sig->params [i])) + // FIXME: r4/r8 + if (mini_wasm_is_scalar_vtype (sig->params [i], &etype) && etype->type != MONO_TYPE_R4 && etype->type != MONO_TYPE_R8) { margs->iargs [int_i] = *(gpointer*)margs->iargs [int_i]; + } } #endif int_i++; diff --git a/src/mono/mono/mini/mini-generic-sharing.c b/src/mono/mono/mini/mini-generic-sharing.c index 3e059b4173085..0c741ca48918e 100644 --- a/src/mono/mono/mini/mini-generic-sharing.c +++ b/src/mono/mono/mini/mini-generic-sharing.c @@ -1172,6 +1172,9 @@ get_wrapper_shared_vtype (MonoType *t) MonoClass *klass; MonoClass *tuple_class = NULL; int findex = 0; +#ifdef TARGET_WASM + gboolean has_fp = FALSE; +#endif // FIXME: Map 1 member structs to primitive types on platforms where its supported @@ -1199,29 +1202,31 @@ get_wrapper_shared_vtype (MonoType *t) args [findex ++] = ftype; if (findex >= 16) break; +#ifdef TARGET_WASM + if (ftype->type == MONO_TYPE_R4 || ftype->type == MONO_TYPE_R8 || MONO_TYPE_ISSTRUCT (ftype)) + has_fp = TRUE; +#endif } #ifdef TARGET_WASM - guint32 align; - int size = mono_class_value_size (klass, &align); - - /* Other platforms might pass small valuestypes or valuetypes with non-int fields differently */ - if (align == 4 && size <= 4 * 5) { - findex = size / align; - for (int i = 0; i < findex; ++i) - args [i] = m_class_get_byval_arg (mono_get_int32_class ()); - } else if (align == 8 && size <= 8 * 5) { - findex = size / align; - for (int i = 0; i < findex; ++i) - args [i] = m_class_get_byval_arg (mono_get_int64_class ()); - } else { - if (findex > 7) - return NULL; + if (!has_fp) { + guint32 align; + int size = mono_class_value_size (klass, &align); + + /* Other platforms might pass small valuetypes or valuetypes with non-int fields differently */ + if (align == 4 && size <= 4 * 5) { + findex = size / align; + for (int i = 0; i < findex; ++i) + args [i] = m_class_get_byval_arg (mono_get_int32_class ()); + } else if (align == 8 && size <= 8 * 5) { + findex = size / align; + for (int i = 0; i < findex; ++i) + args [i] = m_class_get_byval_arg (mono_get_int64_class ()); + } } -#else +#endif if (findex > 7) return NULL; -#endif switch (findex) { case 0: @@ -1395,7 +1400,6 @@ get_wrapper_shared_type (MonoType *t) return get_wrapper_shared_type_full (t, FALSE); } - /* Returns the intptr type for types that are passed in a single register */ static MonoType* get_wrapper_shared_type_reg (MonoType *t, gboolean pinvoke) diff --git a/src/mono/mono/mini/mini-llvm.c b/src/mono/mono/mini/mini-llvm.c index 80d420f1f4b18..069cf7fa60353 100644 --- a/src/mono/mono/mini/mini-llvm.c +++ b/src/mono/mono/mini/mini-llvm.c @@ -1609,7 +1609,7 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo * break; case LLVMArgWasmVtypeAsScalar: g_assert (cinfo->ret.esize); - ret_type = LLVMIntType (cinfo->ret.esize * 8); + ret_type = type_to_llvm_type (ctx, cinfo->ret.etype); break; default: break; @@ -1741,7 +1741,7 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo * break; case LLVMArgWasmVtypeAsScalar: g_assert (ainfo->esize); - param_types [pindex ++] = LLVMIntType (ainfo->esize * 8); + param_types [pindex ++] = type_to_llvm_type (ctx, ainfo->etype); break; case LLVMArgGsharedvtFixed: case LLVMArgGsharedvtFixedVtype: @@ -4021,7 +4021,7 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder) /* The argument is received as a scalar */ ctx->addresses [reg] = build_alloca_address (ctx, t); - LLVMValueRef dest = convert (ctx, ctx->addresses [reg]->value, pointer_type (LLVMIntType (ainfo->esize * 8))); + LLVMValueRef dest = convert (ctx, ctx->addresses [reg]->value, pointer_type (LLVMTypeOf (arg))); LLVMBuildStore (ctx->builder, arg, dest); break; } @@ -4684,7 +4684,7 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, break; case LLVMArgWasmVtypeAsScalar: { g_assert (addresses [reg]); - LLVMTypeRef etype = LLVMIntType (ainfo->esize * 8); + LLVMTypeRef etype = type_to_llvm_type (ctx, ainfo->etype); args [pindex] = LLVMBuildLoad2 (ctx->builder, etype, convert (ctx, addresses [reg]->value, pointer_type (etype)), ""); break; } diff --git a/src/mono/mono/mini/mini-wasm.c b/src/mono/mono/mini/mini-wasm.c index 0ea20e8397292..e0849ba463623 100644 --- a/src/mono/mono/mini/mini-wasm.c +++ b/src/mono/mono/mini/mini-wasm.c @@ -35,7 +35,7 @@ typedef enum { typedef struct { ArgStorage storage : 8; - MonoType *type; + MonoType *type, *etype; } ArgInfo; struct CallInfo { @@ -49,7 +49,7 @@ struct CallInfo { // WASM ABI: https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md static ArgStorage -get_storage (MonoType *type, gboolean is_return) +get_storage (MonoType *type, MonoType **etype, gboolean is_return) { switch (type->type) { case MONO_TYPE_I1: @@ -84,7 +84,7 @@ get_storage (MonoType *type, gboolean is_return) /* fall through */ case MONO_TYPE_VALUETYPE: case MONO_TYPE_TYPEDBYREF: { - if (mini_wasm_is_scalar_vtype (type)) + if (mini_wasm_is_scalar_vtype (type, etype)) return ArgVtypeAsScalar; return is_return ? ArgValuetypeAddrInIReg : ArgValuetypeAddrOnStack; } @@ -117,7 +117,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) /* return value */ cinfo->ret.type = mini_get_underlying_type (sig->ret); - cinfo->ret.storage = get_storage (cinfo->ret.type, TRUE); + cinfo->ret.storage = get_storage (cinfo->ret.type, &cinfo->ret.etype, TRUE); if (sig->hasthis) cinfo->args [0].storage = ArgOnStack; @@ -128,7 +128,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) int i; for (i = 0; i < sig->param_count; ++i) { cinfo->args [i + sig->hasthis].type = mini_get_underlying_type (sig->params [i]); - cinfo->args [i + sig->hasthis].storage = get_storage (cinfo->args [i + sig->hasthis].type, FALSE); + cinfo->args [i + sig->hasthis].storage = get_storage (cinfo->args [i + sig->hasthis].type, &cinfo->args [i + sig->hasthis].etype, FALSE); } return cinfo; @@ -348,6 +348,7 @@ mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig) if (cinfo->ret.storage == ArgVtypeAsScalar) { linfo->ret.storage = LLVMArgWasmVtypeAsScalar; + linfo->ret.etype = cinfo->ret.etype; linfo->ret.esize = mono_class_value_size (mono_class_from_mono_type_internal (cinfo->ret.type), NULL); } else if (mini_type_is_vtype (sig->ret)) { /* Vtype returned using a hidden argument */ @@ -374,6 +375,7 @@ mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig) case ArgVtypeAsScalar: linfo->args [i].storage = LLVMArgWasmVtypeAsScalar; linfo->args [i].type = ainfo->type; + linfo->args [i].etype = ainfo->etype; linfo->args [i].esize = mono_class_value_size (mono_class_from_mono_type_internal (ainfo->type), NULL); break; case ArgValuetypeAddrInIReg: @@ -739,19 +741,22 @@ mono_wasm_get_debug_level (void) /* Return whenever TYPE represents a vtype with only one scalar member */ gboolean -mini_wasm_is_scalar_vtype (MonoType *type) +mini_wasm_is_scalar_vtype (MonoType *type, MonoType **etype) { MonoClass *klass; MonoClassField *field; gpointer iter; + if (etype) + *etype = NULL; + if (!MONO_TYPE_ISSTRUCT (type)) return FALSE; klass = mono_class_from_mono_type_internal (type); mono_class_init_internal (klass); int size = mono_class_value_size (klass, NULL); - if (size == 0 || size >= 8) + if (size == 0 || size > 8) return FALSE; iter = NULL; @@ -765,12 +770,22 @@ mini_wasm_is_scalar_vtype (MonoType *type) return FALSE; MonoType *t = mini_get_underlying_type (field->type); if (MONO_TYPE_ISSTRUCT (t)) { - if (!mini_wasm_is_scalar_vtype (t)) + if (!mini_wasm_is_scalar_vtype (t, etype)) return FALSE; } else if (!((MONO_TYPE_IS_PRIMITIVE (t) || MONO_TYPE_IS_REFERENCE (t) || MONO_TYPE_IS_POINTER (t)))) { return FALSE; + } else if (size == 8 && t->type != MONO_TYPE_R8) { + return FALSE; + } else { + if (etype) + *etype = t; } } + if (etype) { + if (!(*etype)) + *etype = mono_get_int32_type (); + } + return TRUE; } diff --git a/src/mono/mono/mini/mini-wasm.h b/src/mono/mono/mini/mini-wasm.h index 48e6906c10c51..77c7f3a78fa5c 100644 --- a/src/mono/mono/mini/mini-wasm.h +++ b/src/mono/mono/mini/mini-wasm.h @@ -107,6 +107,6 @@ void mono_wasm_main_thread_schedule_timer (void *timerHandler, int shortestDueTi void mono_wasm_print_stack_trace (void); gboolean -mini_wasm_is_scalar_vtype (MonoType *type); +mini_wasm_is_scalar_vtype (MonoType *type, MonoType **etype); #endif /* __MONO_MINI_WASM_H__ */ diff --git a/src/mono/mono/mini/mini.h b/src/mono/mono/mini/mini.h index 4924a0be9d489..d62eb6b5f227e 100644 --- a/src/mono/mono/mini/mini.h +++ b/src/mono/mono/mini/mini.h @@ -678,6 +678,8 @@ typedef struct { /* Parameter index in the LLVM signature */ int pindex; MonoType *type; + /* Only if storage == LLVMArgWasmVtypeAsScalar */ + MonoType *etype; /* Only if storage == LLVMArgAsFpArgs. Dummy fp args to insert before this arg */ int ndummy_fpargs; } LLVMArgInfo;