Skip to content

Commit

Permalink
Add support for Unsafe.BitCast to mono interp
Browse files Browse the repository at this point in the history
  • Loading branch information
tannergooding committed Jun 27, 2024
1 parent 4402ee9 commit 9816091
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 11 deletions.
97 changes: 97 additions & 0 deletions src/mono/mono/mini/interp/transform.c
Original file line number Diff line number Diff line change
Expand Up @@ -2165,6 +2165,103 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas
return TRUE;
} else if (!strcmp (tm, "AreSame")) {
*op = MINT_CEQ_P;
} else if (!strcmp (tm, "BitCast")) {
MonoGenericContext *ctx = mono_method_get_context (target_method);
g_assert (ctx);
g_assert (ctx->method_inst);
g_assert (ctx->method_inst->type_argc == 2);
g_assert (csignature->param_count == 1);

// We explicitly do not handle gsharedvt as it is meant as a slow fallback strategy
// instead we fallback to the managed implementation which will do the right things

MonoType *tfrom = ctx->method_inst->type_argv [0];
if (mini_is_gsharedvt_variable_type (tfrom)) {
return FALSE;
}

MonoType *tto = ctx->method_inst->type_argv [1];
if (mini_is_gsharedvt_variable_type (tto)) {
return FALSE;
}

// The underlying API always throws for reference type inputs, so we
// fallback to the managed implementation to let that handling occur

MonoTypeEnum tfrom_type = tfrom->type;
if (MONO_TYPE_IS_REFERENCE (tfrom)) {
return FALSE;
}

MonoTypeEnum tto_type = tto->type;
if (MONO_TYPE_IS_REFERENCE (tto)) {
return FALSE;
}

MonoClass *tfrom_klass = mono_class_from_mono_type_internal (tfrom);
if (mono_class_is_nullable (tfrom_klass)) {
return FALSE;
}

// We also always throw for Nullable<T> inputs, so fallback to the
// managed implementation here as well.

MonoClass *tto_klass = mono_class_from_mono_type_internal (tto);
if (mono_class_is_nullable (tto_klass)) {
return FALSE;
}

// The same applies for when the type sizes do not match, as this will always throw
// and so its not an expected case and we can fallback to the managed implementation

int tfrom_align, tto_align;
if (mono_type_size (tfrom, &tfrom_align) != mono_type_size (tto, &tto_align)) {
return FALSE;
}

// We have several different move opcodes to handle the data depending on the
// source and target types, so detect and optimize the most common ones falling
// back to what is effectively `ReadUnaligned<TTo>(ref As<TFrom, byte>(ref source))`
// for anything that can't be special cased as potentially zero-cost move.

if (tfrom_type == MONO_TYPE_I4) {
if (tto_type == MONO_TYPE_R4) {
*op = MINT_BITCAST_R4_I4;
} else if (tto_type == MONO_TYPE_I4) {
*op = MINT_MOV_4;
}
} else if (tfrom_type == MONO_TYPE_I8) {
if (tto_type == MONO_TYPE_R8) {
*op = MINT_BITCAST_R8_I8;
} else if (tto_type == MONO_TYPE_I8) {
*op = MINT_MOV_8;
}
} else if (tfrom_type == MONO_TYPE_R4) {
if (tto_type == MONO_TYPE_I4) {
*op = MINT_BITCAST_I4_R4;
} else if (tto_type == MONO_TYPE_R4) {
*op = MINT_MOV_4;
}
} else if (tfrom_type == MONO_TYPE_R8) {
if (tto_type == MONO_TYPE_I8) {
*op = MINT_BITCAST_I8_R8;
} else if (tto_type == MONO_TYPE_R8) {
*op = MINT_MOV_8;
}
}

if (*op == -1) {
gint32 size = mono_class_value_size (tfrom_klass, NULL);
g_assert (size < G_MAXUINT16);

interp_add_ins (td, MINT_MOV_VT);
interp_ins_set_sreg (td->last_ins, td->sp [-1].var);
push_type_vt (td, tto_klass, size);
interp_ins_set_dreg (td->last_ins, td->sp [-1].var);
td->last_ins->data [0] = GINT32_TO_UINT16 (size);
td->ip++;
return TRUE;
}
} else if (!strcmp (tm, "ByteOffset")) {
#if SIZEOF_VOID_P == 4
interp_add_ins (td, MINT_SUB_I4);
Expand Down
11 changes: 0 additions & 11 deletions src/mono/mono/mini/mini-llvm.c
Original file line number Diff line number Diff line change
Expand Up @@ -5757,23 +5757,12 @@ emit_handler_start (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef builder
static LLVMValueRef
get_double_const (MonoCompile *cfg, double val)
{
//#ifdef TARGET_WASM
#if 0
//Wasm requires us to canonicalize NaNs.
if (mono_isnan (val))
*(gint64 *)&val = 0x7FF8000000000000ll;
#endif
return LLVMConstReal (LLVMDoubleType (), val);
}

static LLVMValueRef
get_float_const (MonoCompile *cfg, float val)
{
//#ifdef TARGET_WASM
#if 0
if (mono_isnan (val))
*(int *)&val = 0x7FC00000;
#endif
return LLVMConstReal (LLVMFloatType (), val);
}

Expand Down

0 comments on commit 9816091

Please sign in to comment.