Skip to content

Commit 9816091

Browse files
committed
Add support for Unsafe.BitCast to mono interp
1 parent 4402ee9 commit 9816091

File tree

2 files changed

+97
-11
lines changed

2 files changed

+97
-11
lines changed

src/mono/mono/mini/interp/transform.c

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2165,6 +2165,103 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas
21652165
return TRUE;
21662166
} else if (!strcmp (tm, "AreSame")) {
21672167
*op = MINT_CEQ_P;
2168+
} else if (!strcmp (tm, "BitCast")) {
2169+
MonoGenericContext *ctx = mono_method_get_context (target_method);
2170+
g_assert (ctx);
2171+
g_assert (ctx->method_inst);
2172+
g_assert (ctx->method_inst->type_argc == 2);
2173+
g_assert (csignature->param_count == 1);
2174+
2175+
// We explicitly do not handle gsharedvt as it is meant as a slow fallback strategy
2176+
// instead we fallback to the managed implementation which will do the right things
2177+
2178+
MonoType *tfrom = ctx->method_inst->type_argv [0];
2179+
if (mini_is_gsharedvt_variable_type (tfrom)) {
2180+
return FALSE;
2181+
}
2182+
2183+
MonoType *tto = ctx->method_inst->type_argv [1];
2184+
if (mini_is_gsharedvt_variable_type (tto)) {
2185+
return FALSE;
2186+
}
2187+
2188+
// The underlying API always throws for reference type inputs, so we
2189+
// fallback to the managed implementation to let that handling occur
2190+
2191+
MonoTypeEnum tfrom_type = tfrom->type;
2192+
if (MONO_TYPE_IS_REFERENCE (tfrom)) {
2193+
return FALSE;
2194+
}
2195+
2196+
MonoTypeEnum tto_type = tto->type;
2197+
if (MONO_TYPE_IS_REFERENCE (tto)) {
2198+
return FALSE;
2199+
}
2200+
2201+
MonoClass *tfrom_klass = mono_class_from_mono_type_internal (tfrom);
2202+
if (mono_class_is_nullable (tfrom_klass)) {
2203+
return FALSE;
2204+
}
2205+
2206+
// We also always throw for Nullable<T> inputs, so fallback to the
2207+
// managed implementation here as well.
2208+
2209+
MonoClass *tto_klass = mono_class_from_mono_type_internal (tto);
2210+
if (mono_class_is_nullable (tto_klass)) {
2211+
return FALSE;
2212+
}
2213+
2214+
// The same applies for when the type sizes do not match, as this will always throw
2215+
// and so its not an expected case and we can fallback to the managed implementation
2216+
2217+
int tfrom_align, tto_align;
2218+
if (mono_type_size (tfrom, &tfrom_align) != mono_type_size (tto, &tto_align)) {
2219+
return FALSE;
2220+
}
2221+
2222+
// We have several different move opcodes to handle the data depending on the
2223+
// source and target types, so detect and optimize the most common ones falling
2224+
// back to what is effectively `ReadUnaligned<TTo>(ref As<TFrom, byte>(ref source))`
2225+
// for anything that can't be special cased as potentially zero-cost move.
2226+
2227+
if (tfrom_type == MONO_TYPE_I4) {
2228+
if (tto_type == MONO_TYPE_R4) {
2229+
*op = MINT_BITCAST_R4_I4;
2230+
} else if (tto_type == MONO_TYPE_I4) {
2231+
*op = MINT_MOV_4;
2232+
}
2233+
} else if (tfrom_type == MONO_TYPE_I8) {
2234+
if (tto_type == MONO_TYPE_R8) {
2235+
*op = MINT_BITCAST_R8_I8;
2236+
} else if (tto_type == MONO_TYPE_I8) {
2237+
*op = MINT_MOV_8;
2238+
}
2239+
} else if (tfrom_type == MONO_TYPE_R4) {
2240+
if (tto_type == MONO_TYPE_I4) {
2241+
*op = MINT_BITCAST_I4_R4;
2242+
} else if (tto_type == MONO_TYPE_R4) {
2243+
*op = MINT_MOV_4;
2244+
}
2245+
} else if (tfrom_type == MONO_TYPE_R8) {
2246+
if (tto_type == MONO_TYPE_I8) {
2247+
*op = MINT_BITCAST_I8_R8;
2248+
} else if (tto_type == MONO_TYPE_R8) {
2249+
*op = MINT_MOV_8;
2250+
}
2251+
}
2252+
2253+
if (*op == -1) {
2254+
gint32 size = mono_class_value_size (tfrom_klass, NULL);
2255+
g_assert (size < G_MAXUINT16);
2256+
2257+
interp_add_ins (td, MINT_MOV_VT);
2258+
interp_ins_set_sreg (td->last_ins, td->sp [-1].var);
2259+
push_type_vt (td, tto_klass, size);
2260+
interp_ins_set_dreg (td->last_ins, td->sp [-1].var);
2261+
td->last_ins->data [0] = GINT32_TO_UINT16 (size);
2262+
td->ip++;
2263+
return TRUE;
2264+
}
21682265
} else if (!strcmp (tm, "ByteOffset")) {
21692266
#if SIZEOF_VOID_P == 4
21702267
interp_add_ins (td, MINT_SUB_I4);

src/mono/mono/mini/mini-llvm.c

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5757,23 +5757,12 @@ emit_handler_start (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef builder
57575757
static LLVMValueRef
57585758
get_double_const (MonoCompile *cfg, double val)
57595759
{
5760-
//#ifdef TARGET_WASM
5761-
#if 0
5762-
//Wasm requires us to canonicalize NaNs.
5763-
if (mono_isnan (val))
5764-
*(gint64 *)&val = 0x7FF8000000000000ll;
5765-
#endif
57665760
return LLVMConstReal (LLVMDoubleType (), val);
57675761
}
57685762

57695763
static LLVMValueRef
57705764
get_float_const (MonoCompile *cfg, float val)
57715765
{
5772-
//#ifdef TARGET_WASM
5773-
#if 0
5774-
if (mono_isnan (val))
5775-
*(int *)&val = 0x7FC00000;
5776-
#endif
57775766
return LLVMConstReal (LLVMFloatType (), val);
57785767
}
57795768

0 commit comments

Comments
 (0)