Skip to content

Commit

Permalink
[wasm] Allow scalar valuetypes with r4/r8 members. (#94969)
Browse files Browse the repository at this point in the history
  • Loading branch information
vargaz committed Nov 20, 2023
1 parent f0ba96a commit 5708568
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 32 deletions.
6 changes: 5 additions & 1 deletion src/mono/mono/mini/interp/interp.c
Expand Up @@ -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++;
Expand Down
40 changes: 22 additions & 18 deletions src/mono/mono/mini/mini-generic-sharing.c
Expand Up @@ -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

Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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)
Expand Down
8 changes: 4 additions & 4 deletions src/mono/mono/mini/mini-llvm.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down
31 changes: 23 additions & 8 deletions src/mono/mono/mini/mini-wasm.c
Expand Up @@ -35,7 +35,7 @@ typedef enum {

typedef struct {
ArgStorage storage : 8;
MonoType *type;
MonoType *type, *etype;
} ArgInfo;

struct CallInfo {
Expand All @@ -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:
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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 */
Expand All @@ -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:
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
2 changes: 1 addition & 1 deletion src/mono/mono/mini/mini-wasm.h
Expand Up @@ -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__ */
2 changes: 2 additions & 0 deletions src/mono/mono/mini/mini.h
Expand Up @@ -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;
Expand Down

0 comments on commit 5708568

Please sign in to comment.