is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
{
uint32_t align;
+ int param_size, return_size;
param_klass = mono_class_from_mono_type (mini_get_underlying_type (¶m_klass->byval_arg));
+ return_klass = mono_class_from_mono_type (mini_get_underlying_type (&return_klass->byval_arg));
- //Only allow for valuetypes
- if (!param_klass->valuetype || !return_klass->valuetype)
+ if (cfg->verbose_level > 3)
+ printf ("[UNSAFE-MOV-INTRISIC] %s <- %s\n", return_klass->name, param_klass->name);
+
+ //Don't allow mixing reference types with value types
+ if (param_klass->valuetype != return_klass->valuetype) {
+ if (cfg->verbose_level > 3)
+ printf ("[UNSAFE-MOV-INTRISIC]\tone of the args is a valuetype and the other is not\n");
return FALSE;
+ }
+
+ if (!param_klass->valuetype) {
+ if (cfg->verbose_level > 3)
+ printf ("[UNSAFE-MOV-INTRISIC]\targs are reference types\n");
+ return TRUE;
+ }
//That are blitable
if (param_klass->has_references || return_klass->has_references)
/* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
if ((MONO_TYPE_ISSTRUCT (¶m_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
- (!MONO_TYPE_ISSTRUCT (¶m_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)))
+ (!MONO_TYPE_ISSTRUCT (¶m_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg))) {
+ if (cfg->verbose_level > 3)
+ printf ("[UNSAFE-MOV-INTRISIC]\tmixing structs and scalars\n");
return FALSE;
+ }
if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
- return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8)
+ return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8) {
+ if (cfg->verbose_level > 3)
+ printf ("[UNSAFE-MOV-INTRISIC]\tfloat or double are not supported\n");
return FALSE;
+ }
- //And have the same size
- if (mono_class_value_size (param_klass, &align) != mono_class_value_size (return_klass, &align))
+ param_size = mono_class_value_size (param_klass, &align);
+ return_size = mono_class_value_size (return_klass, &align);
+
+ //We can do it if sizes match
+ if (param_size == return_size) {
+ if (cfg->verbose_level > 3)
+ printf ("[UNSAFE-MOV-INTRISIC]\tsame size\n");
+ return TRUE;
+ }
+
+ //No simple way to handle struct if sizes don't match
+ if (MONO_TYPE_ISSTRUCT (¶m_klass->byval_arg)) {
+ if (cfg->verbose_level > 3)
+ printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch and type is a struct\n");
return FALSE;
- return TRUE;
+ }
+
+ /*
+ * Same reg size category.
+ * A quick note on why we don't require widening here.
+ * The intrinsic is "R Array.UnsafeMov<S,R> (S s)".
+ *
+ * Since the source value comes from a function argument, the JIT will already have
+ * the value in a VREG and performed any widening needed before (say, when loading from a field).
+ */
+ if (param_size <= 4 && return_size <= 4) {
+ if (cfg->verbose_level > 3)
+ printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch but both are of the same reg class\n");
+ return TRUE;
+ }
+
+ return FALSE;
}
static MonoInst*
MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
- //Valuetypes that are semantically equivalent
+ //Valuetypes that are semantically equivalent or numbers than can be widened to
if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
return args [0];
+using System;
+using System.Collections.Generic;
+
namespace Test {
-public enum YaddaYadda {
- buba,
- birba,
- dadoom,
-};
-
-public enum byteenum : byte {
- zero,
- one,
- two,
- three
-}
+ enum ByteEnum : byte {
+ A = 10
+ }
-public enum longenum: long {
- s0 = 0,
- s1 = 1
-}
+ enum SByteEnum : sbyte {
+ A = -11
+ }
-public enum sbyteenum : sbyte {
- d0,
- d1
-}
+ enum ShortEnum : short {
+ A = -12
+ }
+
+ enum UShortEnum : ushort {
+ A = 13
+ }
+
+ enum IntEnum : int {
+ A = -15
+ }
+
+ enum UIntEnum : uint {
+ A = 16
+ }
+
+ enum LongEnum : long {
+ A = -153453525432334L
+ }
+
+ enum ULongEnum : ulong {
+ A = 164923797563459L
+ }
+
+ public enum YaddaYadda {
+ buba,
+ birba,
+ dadoom,
+ };
+
+ public enum byteenum : byte {
+ zero,
+ one,
+ two,
+ three
+ }
+
+ public enum longenum: long {
+ s0 = 0,
+ s1 = 1
+ }
+
+ public enum sbyteenum : sbyte {
+ d0,
+ d1
+ }
+
+ public class Tests {
+ public static int test_0_basic_enum_vals ()
+ {
+ YaddaYadda val = YaddaYadda.dadoom;
+ byteenum be = byteenum.one;
+ if (val != YaddaYadda.dadoom)
+ return 1;
+ if (be != (byteenum)1)
+ return 2;
+ return 0;
+ }
+
+ public static int test_0_byte_enum_hashcode ()
+ {
+ if (ByteEnum.A.GetHashCode () != EqualityComparer<ByteEnum>.Default.GetHashCode (ByteEnum.A))
+ return 1;
+ if (ByteEnum.A.GetHashCode () != ((byte)ByteEnum.A).GetHashCode () )
+ return 2;
+ return 0;
+ }
+
+ public static int test_0_sbyte_enum_hashcode ()
+ {
+ if (SByteEnum.A.GetHashCode () != EqualityComparer<SByteEnum>.Default.GetHashCode (SByteEnum.A))
+ return 1;
+ if (SByteEnum.A.GetHashCode () != ((sbyte)SByteEnum.A).GetHashCode () )
+ return 2;
+ return 0;
+ }
+
+ public static int test_0_short_enum_hashcode ()
+ {
+ if (ShortEnum.A.GetHashCode () != EqualityComparer<ShortEnum>.Default.GetHashCode (ShortEnum.A))
+ return 1;
+ if (ShortEnum.A.GetHashCode () != ((short)ShortEnum.A).GetHashCode () )
+ return 2;
+ return 0;
+ }
+
+ public static int test_0_ushort_enum_hashcode ()
+ {
+ if (UShortEnum.A.GetHashCode () != EqualityComparer<UShortEnum>.Default.GetHashCode (UShortEnum.A))
+ return 1;
+ if (UShortEnum.A.GetHashCode () != ((ushort)UShortEnum.A).GetHashCode () )
+ return 2;
+ return 0;
+ }
+
+ public static int test_0_int_enum_hashcode ()
+ {
+ if (IntEnum.A.GetHashCode () != EqualityComparer<IntEnum>.Default.GetHashCode (IntEnum.A))
+ return 1;
+ if (IntEnum.A.GetHashCode () != ((int)IntEnum.A).GetHashCode () )
+ return 2;
+ return 0;
+ }
+
+ public static int test_0_uint_enum_hashcode ()
+ {
+ if (UIntEnum.A.GetHashCode () != EqualityComparer<UIntEnum>.Default.GetHashCode (UIntEnum.A))
+ return 1;
+ if (UIntEnum.A.GetHashCode () != ((uint)UIntEnum.A).GetHashCode () )
+ return 2;
+ return 0;
+ }
+
+ public static int test_0_long_enum_hashcode ()
+ {
+ if (LongEnum.A.GetHashCode () != EqualityComparer<LongEnum>.Default.GetHashCode (LongEnum.A))
+ return 1;
+ if (LongEnum.A.GetHashCode () != ((long)LongEnum.A).GetHashCode () )
+ return 2;
+ return 0;
+ }
+
+ public static int test_0_ulong_enum_hashcode ()
+ {
+ if (ULongEnum.A.GetHashCode () != EqualityComparer<ULongEnum>.Default.GetHashCode (ULongEnum.A))
+ return 1;
+ if (ULongEnum.A.GetHashCode () != ((ulong)ULongEnum.A).GetHashCode () )
+ return 2;
+ return 0;
+ }
+
+ public static int Main (String[] args) {
+ return TestDriver.RunTests (typeof (Tests), args);
+ }
-public class test {
- public static int Main () {
- YaddaYadda val = YaddaYadda.dadoom;
- byteenum be = byteenum.one;
- if (val != YaddaYadda.dadoom)
- return 1;
- if (be != (byteenum)1)
- return 2;
- return 0;
}
-}
}