瀏覽代碼

Merge pull request #10749 from lewurm/interp-fixes-for-native-type

[interp] fixes for native types

please look at single commits.

------------------------

[interp] fix op_implicit/op_explicit conversions for native types
    
Conversion operators have been mostly broken in the interpreter, for example conversion from nint to float didn't work. While some conversions are easy to intrinsify (like nint -> I8), there are harder cases like nint -> decimal. The JIT actually falls back to the managed implementation, so let's do this in the interpreter as well.
    
However the managed implementation expects a pointer to the value type, i.e. the container type System.nfloat instead of float/double primitives. In such cases the value is going to be stored in a local and then the address of its storage is pushed on the stack before invoking the managed implementation of the conversion.
    
Added test cases for scenarios observed in Xamarin.iOS.

-----------------------

[interp] support ntype.CompareTo ()

-----------------------

[interp] support ntype.Equals ()

-----------------------

 [interp] support nfloat.*Infinity

-----------------------

[interp] support ntype.ToString ()

-----------------------

The conversion issue creeped everywhere in Xamarin.iOS since it heavily relies on nint/nuint/nfloat. With this PR we are getting close to a green monotouch tests 😁 
<img width="874" alt="screen shot 2018-09-21 at 23 24 36" src="https://user-images.githubusercontent.com/75403/45907566-b457eb80-bdf8-11e8-9cc7-b8cf311dd269.png">

needs backporting to 2018-06 and 2018-08
monojenkins 7 年之前
父節點
當前提交
385b8a2783

+ 541 - 26
mono/mini/builtin-types.cs

@@ -1,5 +1,11 @@
 // #define ARCH_32
-#define NINT_JIT_OPTIMIZED
+
+/* This is _NOT_ set by Xamarin.iOS. We can enable it in order to make sure
+ * methods are intrinsified (by throwing NotImplementedException), but some
+ * methods aren't intrinsified by JIT/interp. For example, conversion to
+ * decimal. Therefore JIT/interp should fall back to managed implementation.
+ */
+// #define NINT_JIT_OPTIMIZED
 
 using System;
 using System.Diagnostics;
@@ -27,6 +33,7 @@ public class BuiltinTests {
 	{
 		var x = (nint)10;
 		var y = (nint)20L;
+		int z = 30;
 
 		if ((int)x != 10)
 			return 1;
@@ -36,6 +43,8 @@ public class BuiltinTests {
 			return 3;
 		if ((long)y != 20L)
 			return 4;
+		if ((nint)z != 30)
+			return 5;
 		return 0;
 	}
 
@@ -239,14 +248,47 @@ public class BuiltinTests {
 		return 0;
 	}
 
-	// static int test_0_nint_call_boxed_equals ()
-	// {
-	// 	object x = new nint (10);
-	// 	object y = new nint (10);
-	// 	if (!x.Equals (y))
-	// 		return 1;
-	// 	return 0;
-	// }
+	static int test_0_nint_compareto ()
+	{
+		if (((nint) 0).CompareTo ((nint) 0) != 0)
+			return 1;
+		if (((nint) 0).CompareTo ((nint) 1) != -1)
+			return 2;
+		if (((nint) 1).CompareTo ((nint) 0) != 1)
+			return 3;
+
+		if (((nint) 0).CompareTo ((object)(nint) 0) != 0)
+			return 4;
+		if (((nint) 0).CompareTo ((object)(nint) 1) != -1)
+			return 5;
+		if (((nint) 1).CompareTo ((object)(nint) 0) != 1)
+			return 6;
+
+		if (((nint) 1).CompareTo (null) != 1)
+			return 7;
+
+		return 0;
+	}
+
+	static int test_0_nint_call_boxed_equals ()
+	{
+		object x = new nint (10);
+		object y = new nint (10);
+		if (!x.Equals (y))
+			return 1;
+		return 0;
+	}
+
+	static int test_0_nint_equals ()
+	{
+		if (!((nint) 0).Equals ((nint) 0))
+			return 1;
+		if (!((nint) 0).Equals ((object) (nint) 0))
+			return 2;
+		if (((nint) 0).Equals (null))
+			return 3;
+		return 0;
+	}
 
 	static int test_0_nint_call_boxed_funs ()
 	{
@@ -259,6 +301,40 @@ public class BuiltinTests {
 		return 0;
 	}
 
+	static int test_0_nint_tostring ()
+	{
+		int x = 1337;
+		if (((nint) x).ToString () != "1337")
+			return 1;
+		x = -1337;
+		if (((nint) x).ToString () != "-1337")
+			return 2;
+
+		return 0;
+	}
+
+	[MethodImplAttribute (MethodImplOptions.NoInlining)]
+	static bool decimal_cmp (decimal a, decimal b)
+	{
+		return a == b;
+	}
+
+	static int test_0_nint_implicit_decimal ()
+	{
+		nint a = new nint (10);
+		nint b = new nint (9);
+		if (decimal_cmp (a, b))
+			return 1;
+		b++;
+		if (!decimal_cmp (a, b))
+			return 2;
+		if (!decimal_cmp ((nint) 10, b))
+			return 3;
+		if (!decimal_cmp (a, (nint) 10))
+			return 4;
+		return 0;
+	}
+
 	static int test_0_nint_unboxed_member_calls ()
 	{
 		var x = (nint)10;
@@ -271,6 +347,81 @@ public class BuiltinTests {
 		return 0;
 	}
 
+	struct SomeNativeStructWithNint {
+		public nint a;
+		public static nint b;
+
+		public SomeNativeStructWithNint (nint a)
+		{
+			this.a = a;
+			b = a + 1;
+		}
+
+		public static nint GetAStatic (SomeNativeStructWithNint x)
+		{
+			return x.a;
+		}
+
+		public nint GetA ()
+		{
+			return a;
+		}
+	}
+
+	class SomeClassWithNint {
+		public nint a;
+
+		public SomeClassWithNint (nint a)
+		{
+			this.a = a;
+		}
+
+		public virtual nint GetAVirtual ()
+		{
+			return a;
+		}
+	}
+
+	public int test_0_nint_fieldload ()
+	{
+		var x = new SomeNativeStructWithNint ((nint) 20f);
+
+		if ((float) x.a != 20f)
+			return 1;
+
+		if ((int) x.a != 20)
+			return 2;
+
+		if ((float) SomeNativeStructWithNint.GetAStatic (x) != 20f)
+			return 3;
+
+		if ((float) x.GetA () != 20f)
+			return 4;
+
+		if ((int) SomeNativeStructWithNint.GetAStatic (x) != 20)
+			return 5;
+
+		if ((int) x.GetA () != 20)
+			return 6;
+
+		if ((float) SomeNativeStructWithNint.b != 21f)
+			return 7;
+
+		if ((int) SomeNativeStructWithNint.b != 21)
+			return 8;
+
+		SomeClassWithNint y = new SomeClassWithNint ((nint) 30f);
+
+		if ((int) y.GetAVirtual () != 30)
+			return 9;
+
+		if ((float) y.GetAVirtual () != 30f)
+			return 10;
+
+		return 0;
+	}
+
+
 	static int test_0_nuint_ctor ()
 	{
 		var x = new nuint (10u);
@@ -289,6 +440,7 @@ public class BuiltinTests {
 	{
 		var x = (nuint)10;
 		var y = (nuint)20L;
+		int z = 30;
 
 		if ((uint)x != 10)
 			return 1;
@@ -298,6 +450,8 @@ public class BuiltinTests {
 			return 3;
 		if ((ulong)y != 20L)
 			return 4;
+		if ((nuint)z != 30)
+			return 5;
 		return 0;
 	}
 
@@ -501,14 +655,47 @@ public class BuiltinTests {
 		return 0;
 	}
 
-	// static int test_0_nuint_call_boxed_equals ()
-	// {
-	// 	object x = new nuint (10);
-	// 	object y = new nuint (10);
-	// 	if (!x.Equals (y))
-	// 		return 1;
-	// 	return 0;
-	// }
+	static int test_0_nuint_compareto ()
+	{
+		if (((nuint) 0).CompareTo ((nuint) 0) != 0)
+			return 1;
+		if (((nuint) 0).CompareTo ((nuint) 1) != -1)
+			return 2;
+		if (((nuint) 1).CompareTo ((nuint) 0) != 1)
+			return 3;
+
+		if (((nuint) 0).CompareTo ((object)(nuint) 0) != 0)
+			return 4;
+		if (((nuint) 0).CompareTo ((object)(nuint) 1) != -1)
+			return 5;
+		if (((nuint) 1).CompareTo ((object)(nuint) 0) != 1)
+			return 6;
+
+		if (((nuint) 1).CompareTo (null) != 1)
+			return 7;
+
+		return 0;
+	}
+
+	static int test_0_nuint_call_boxed_equals ()
+	{
+		object x = new nuint (10);
+		object y = new nuint (10);
+		if (!x.Equals (y))
+			return 1;
+		return 0;
+	}
+
+	static int test_0_nuint_equals ()
+	{
+		if (!((nuint) 0).Equals ((nuint) 0))
+			return 1;
+		if (!((nuint) 0).Equals ((object) (nuint) 0))
+			return 2;
+		if (((nuint) 0).Equals (null))
+			return 3;
+		return 0;
+	}
 
 	static int test_0_nuint_call_boxed_funs ()
 	{
@@ -521,6 +708,34 @@ public class BuiltinTests {
 		return 0;
 	}
 
+	static int test_0_nuint_tostring ()
+	{
+		int x = 1337;
+		if (((nuint) x).ToString () != "1337")
+			return 1;
+		x = -1337;
+		if (((nuint) x).ToString () == "-1337")
+			return 2;
+
+		return 0;
+	}
+
+	static int test_0_nuint_implicit_decimal ()
+	{
+		nuint a = new nuint (10);
+		nuint b = new nuint (9);
+		if (decimal_cmp (a, b))
+			return 1;
+		b++;
+		if (!decimal_cmp (a, b))
+			return 2;
+		if (!decimal_cmp ((nuint) 10, b))
+			return 3;
+		if (!decimal_cmp (a, (nuint) 10))
+			return 4;
+		return 0;
+	}
+
 	static int test_0_nuint_unboxed_member_calls ()
 	{
 		var x = (nuint)10;
@@ -533,6 +748,80 @@ public class BuiltinTests {
 		return 0;
 	}
 
+	struct SomeNativeStructWithNuint {
+		public nuint a;
+		public static nuint b;
+
+		public SomeNativeStructWithNuint (nuint a)
+		{
+			this.a = a;
+			b = a + 1;
+		}
+
+		public static nuint GetAStatic (SomeNativeStructWithNuint x)
+		{
+			return x.a;
+		}
+
+		public nuint GetA ()
+		{
+			return a;
+		}
+	}
+
+	class SomeClassWithNuint {
+		public nuint a;
+
+		public SomeClassWithNuint (nuint a)
+		{
+			this.a = a;
+		}
+
+		public virtual nuint GetAVirtual ()
+		{
+			return a;
+		}
+	}
+
+	public int test_0_nuint_fieldload ()
+	{
+		var x = new SomeNativeStructWithNuint ((nuint) 20f);
+
+		if ((float) x.a != 20f)
+			return 1;
+
+		if ((int) x.a != 20)
+			return 2;
+
+		if ((float) SomeNativeStructWithNuint.GetAStatic (x) != 20f)
+			return 3;
+
+		if ((float) x.GetA () != 20f)
+			return 4;
+
+		if ((int) SomeNativeStructWithNuint.GetAStatic (x) != 20)
+			return 5;
+
+		if ((int) x.GetA () != 20)
+			return 6;
+
+		if ((float) SomeNativeStructWithNuint.b != 21f)
+			return 7;
+
+		if ((int) SomeNativeStructWithNuint.b != 21)
+			return 8;
+
+		SomeClassWithNuint y = new SomeClassWithNuint ((nuint) 30f);
+
+		if ((int) y.GetAVirtual () != 30)
+			return 9;
+
+		if ((float) y.GetAVirtual () != 30f)
+			return 10;
+
+		return 0;
+	}
+
 	static int test_0_nfloat_ctor ()
 	{
 		var x = new nfloat (10.0f);
@@ -562,6 +851,12 @@ public class BuiltinTests {
 		if ((double)y != 20)
 			return 4;
 #endif
+		int z = 30;
+		if ((nfloat) z != 30f)
+			return 5;
+
+		if ((int) x != 10)
+			return 6;
 		return 0;
 	}
 
@@ -754,20 +1049,137 @@ public class BuiltinTests {
 		return 0;
 	}
 
+	static int test_0_nfloat_isinfinity ()
+	{
+		var x = (nfloat) float.NaN;
+		if (nfloat.IsInfinity (x))
+			return 1;
+		if (nfloat.IsInfinity (12))
+			return 2;
+		if (!nfloat.IsInfinity (nfloat.PositiveInfinity))
+			return 3;
+		if (!nfloat.IsInfinity (nfloat.NegativeInfinity))
+			return 4;
+
+		return 0;
+	}
+
+	static int test_0_nfloat_isnegativeinfinity ()
+	{
+		var x = (nfloat) float.NaN;
+		if (nfloat.IsNegativeInfinity (x))
+			return 1;
+		if (nfloat.IsNegativeInfinity (12))
+			return 2;
+		if (nfloat.IsNegativeInfinity (nfloat.PositiveInfinity))
+			return 3;
+		if (!nfloat.IsNegativeInfinity (nfloat.NegativeInfinity))
+			return 4;
+
+		float f = float.NegativeInfinity;
+		nfloat n = (nfloat) f;
+		if (!nfloat.IsNegativeInfinity (n))
+			return 5;
+
+		double d = double.NegativeInfinity;
+		n = (nfloat) d;
+		if (!nfloat.IsNegativeInfinity (n))
+			return 6;
+
+		return 0;
+	}
+
+	static int test_0_nfloat_ispositiveinfinity ()
+	{
+		var x = (nfloat) float.NaN;
+		if (nfloat.IsPositiveInfinity (x))
+			return 1;
+		if (nfloat.IsPositiveInfinity (12))
+			return 2;
+		if (!nfloat.IsPositiveInfinity (nfloat.PositiveInfinity))
+			return 3;
+		if (nfloat.IsPositiveInfinity (nfloat.NegativeInfinity))
+			return 4;
+
+		float f = float.PositiveInfinity;
+		nfloat n = (nfloat) f;
+		if (!nfloat.IsPositiveInfinity (n))
+			return 5;
+
+		double d = double.PositiveInfinity;
+		n = (nfloat) d;
+		if (!nfloat.IsPositiveInfinity (n))
+			return 6;
+
+		return 0;
+	}
+
 	static int test_0_nfloat_isnan ()
 	{
 		var x = (nfloat) float.NaN;
-		return nfloat.IsNaN (x) ? 0 : 1;
+		if (!nfloat.IsNaN (x))
+			return 1;
+		if (nfloat.IsNaN (12))
+			return 2;
+		if (nfloat.IsNaN (nfloat.PositiveInfinity))
+			return 3;
+		if (nfloat.IsNaN (nfloat.NegativeInfinity))
+			return 4;
+
+		float f = float.NaN;
+		nfloat n = (nfloat) f;
+		if (!nfloat.IsNaN (n))
+			return 5;
+
+		double d = double.NaN;
+		n = (nfloat) d;
+		if (!nfloat.IsNaN (n))
+			return 6;
+
+		return 0;
 	}
 
-	// static int test_0_nfloat_call_boxed_equals ()
-	// {
-	// 	object x = new nfloat (10f);
-	// 	object y = new nfloat (10f);
-	// 	if (!x.Equals (y))
-	// 		return 1;
-	// 	return 0;
-	// }
+	static int test_0_nfloat_compareto ()
+	{
+		if (((nfloat) 0).CompareTo ((nfloat) 0) != 0)
+			return 1;
+		if (((nfloat) 0).CompareTo ((nfloat) 1) != -1)
+			return 2;
+		if (((nfloat) 1).CompareTo ((nfloat) 0) != 1)
+			return 3;
+
+		if (((nfloat) 0).CompareTo ((object)(nfloat) 0) != 0)
+			return 4;
+		if (((nfloat) 0).CompareTo ((object)(nfloat) 1) != -1)
+			return 5;
+		if (((nfloat) 1).CompareTo ((object)(nfloat) 0) != 1)
+			return 6;
+
+		if (((nfloat) 1).CompareTo (null) != 1)
+			return 7;
+
+		return 0;
+	}
+
+	static int test_0_nfloat_call_boxed_equals ()
+	{
+		object x = new nfloat (10f);
+		object y = new nfloat (10f);
+		if (!x.Equals (y))
+			return 1;
+		return 0;
+	}
+
+	static int test_0_nfloat_equals ()
+	{
+		if (!((nfloat) 0).Equals ((nfloat) 0))
+			return 1;
+		if (!((nfloat) 0).Equals ((object) (nfloat) 0))
+			return 2;
+		if (((nfloat) 0).Equals (null))
+			return 3;
+		return 0;
+	}
 
 	static int test_0_nfloat_call_boxed_funs ()
 	{
@@ -780,6 +1192,35 @@ public class BuiltinTests {
 		return 0;
 	}
 
+	static int test_0_nfloat_tostring ()
+	{
+		float x = 1337.0f;
+		nfloat y = (nfloat) x;
+		if (y.ToString () != "1337")
+			return 1;
+		x = -1337.0f;
+		if (((nfloat) x).ToString () != "-1337")
+			return 2;
+
+		return 0;
+	}
+
+	static int test_0_nfloat_explicit_decimal ()
+	{
+		nfloat a = new nfloat (10);
+		nfloat b = new nfloat (9);
+		if (decimal_cmp ((decimal) a, (decimal) b))
+			return 1;
+		b += 1.0f;
+		if (!decimal_cmp ((decimal) a, (decimal) b))
+			return 2;
+		if (!decimal_cmp ((decimal) (nfloat) 10.0f, (decimal) b))
+			return 3;
+		if (!decimal_cmp ((decimal) a, (decimal) (nfloat) 10.0f))
+			return 4;
+		return 0;
+	}
+
 	static int test_0_nfloat_unboxed_member_calls ()
 	{
 		var x = (nfloat)10f;
@@ -792,6 +1233,80 @@ public class BuiltinTests {
 		return 0;
 	}
 
+	struct SomeNativeStructWithNfloat {
+		public nfloat a;
+		public static nfloat b;
+
+		public SomeNativeStructWithNfloat (nfloat a)
+		{
+			this.a = a;
+			b = a + 1;
+		}
+
+		public static nfloat GetAStatic (SomeNativeStructWithNfloat x)
+		{
+			return x.a;
+		}
+
+		public nfloat GetA ()
+		{
+			return a;
+		}
+	}
+
+	class SomeClassWithNfloat {
+		public nfloat a;
+
+		public SomeClassWithNfloat (nfloat a)
+		{
+			this.a = a;
+		}
+
+		public virtual nfloat GetAVirtual ()
+		{
+			return a;
+		}
+	}
+
+	public int test_0_nfloat_fieldload ()
+	{
+		var x = new SomeNativeStructWithNfloat ((nfloat) 20f);
+
+		if ((float) x.a != 20f)
+			return 1;
+
+		if ((int) x.a != 20)
+			return 2;
+
+		if ((float) SomeNativeStructWithNfloat.GetAStatic (x) != 20f)
+			return 3;
+
+		if ((float) x.GetA () != 20f)
+			return 4;
+
+		if ((int) SomeNativeStructWithNfloat.GetAStatic (x) != 20)
+			return 5;
+
+		if ((int) x.GetA () != 20)
+			return 6;
+
+		if ((float) SomeNativeStructWithNfloat.b != 21f)
+			return 7;
+
+		if ((int) SomeNativeStructWithNfloat.b != 21)
+			return 8;
+
+		SomeClassWithNfloat y = new SomeClassWithNfloat ((nfloat) 30f);
+
+		if ((int) y.GetAVirtual () != 30)
+			return 9;
+
+		if ((float) y.GetAVirtual () != 30f)
+			return 10;
+
+		return 0;
+	}
+
 #if !__MOBILE__
 	public static int Main (String[] args) {
 		return TestDriver.RunTests (typeof (BuiltinTests), args);

+ 1 - 0
mono/mini/interp/interp-internals.h

@@ -59,6 +59,7 @@ typedef struct {
 			gint32 lo;
 			gint32 hi;
 		} pair;
+		float f_r4;
 		double f;
 		/* native size integer and pointer types */
 		MonoObject *o;

+ 214 - 29
mono/mini/interp/interp.c

@@ -497,13 +497,10 @@ stackval_from_data (MonoType *type_, stackval *result, void *data, gboolean pinv
 	case MONO_TYPE_U4:
 		result->data.i = *(guint32*)data;
 		return;
-	case MONO_TYPE_R4: {
-		float tmp;
+	case MONO_TYPE_R4:
 		/* memmove handles unaligned case */
-		memmove (&tmp, data, sizeof (float));
-		result->data.f = tmp;
+		memmove (&result->data.f_r4, data, sizeof (float));
 		return;
-    }
 	case MONO_TYPE_I8:
 	case MONO_TYPE_U8:
 		memmove (&result->data.l, data, sizeof (gint64));
@@ -597,9 +594,8 @@ stackval_to_data (MonoType *type_, stackval *val, void *data, gboolean pinvoke)
 		return;
 	}
 	case MONO_TYPE_R4: {
-		float tmp = (float)val->data.f;
 		/* memmove handles unaligned case */
-		memmove (data, &tmp, sizeof (float));
+		memmove (data, &val->data.f_r4, sizeof (float));
 		return;
 	}
 	case MONO_TYPE_R8: {
@@ -673,6 +669,7 @@ stackval_to_data_addr (MonoType *type_, stackval *val)
 	case MONO_TYPE_U8:
 		return &val->data.l;
 	case MONO_TYPE_R4:
+		return &val->data.f_r4;
 	case MONO_TYPE_R8:
 		return &val->data.f;
 	case MONO_TYPE_STRING:
@@ -1066,7 +1063,7 @@ static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, Int
 		case MONO_TYPE_R4:
 		case MONO_TYPE_R8:
 			if (ptype == MONO_TYPE_R4)
-				* (float *) &(margs->fargs [int_f]) = (float) frame->stack_args [i].data.f;
+				* (float *) &(margs->fargs [int_f]) = frame->stack_args [i].data.f_r4;
 			else
 				margs->fargs [int_f] = frame->stack_args [i].data.f;
 #if DEBUG_INTERP
@@ -1399,6 +1396,8 @@ dump_stackval (GString *str, stackval *s, MonoType *type)
 			g_string_append_printf (str, "[vt:%p] ", s->data.p);
 		break;
 	case MONO_TYPE_R4:
+		g_string_append_printf (str, "[%g] ", s->data.f_r4);
+		break;
 	case MONO_TYPE_R8:
 		g_string_append_printf (str, "[%g] ", s->data.f);
 		break;
@@ -1988,12 +1987,9 @@ do_jit_call (stackval *sp, unsigned char *vt_sp, ThreadContext *context, InterpF
 			case MONO_TYPE_U8:
 				args [pindex ++] = &sval->data.l;
 				break;
-			case MONO_TYPE_R4: {
-				float tmp = (float)sval->data.f;
-				sval->data.i = *(int*)&tmp;
-				args [pindex ++] = &sval->data.i;
+			case MONO_TYPE_R4:
+				args [pindex ++] = &sval->data.f_r4;
 				break;
-			}
 			case MONO_TYPE_R8:
 				args [pindex ++] = &sval->data.f;
 				break;
@@ -2115,7 +2111,7 @@ do_jit_call (stackval *sp, unsigned char *vt_sp, ThreadContext *context, InterpF
 		sp->data.l = *(guint64*)res_buf;
 		break;
 	case MONO_TYPE_R4:
-		sp->data.f = *(float*)res_buf;
+		sp->data.f_r4 = *(float*)res_buf;
 		break;
 	case MONO_TYPE_R8:
 		sp->data.f = *(double*)res_buf;
@@ -2775,7 +2771,7 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 			guint32 val;
 			++ip;
 			val = READ32(ip);
-			sp->data.f = * (float *)&val;
+			sp->data.f_r4 = * (float *)&val;
 			ip += 2;
 			++sp;
 			MINT_IN_BREAK;
@@ -3134,6 +3130,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_BRFALSE_I8_S)
 			ZEROP_S(l, ==);
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_BRFALSE_R4_S)
+			ZEROP_S(f_r4, ==);
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_BRFALSE_R8_S)
 			ZEROP_S(f, ==);
 			MINT_IN_BREAK;
@@ -3143,6 +3142,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_BRFALSE_I8)
 			ZEROP(l, ==);
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_BRFALSE_R4)
+			ZEROP_S(f_r4, ==);
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_BRFALSE_R8)
 			ZEROP_S(f, ==);
 			MINT_IN_BREAK;
@@ -3152,6 +3154,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_BRTRUE_I8_S)
 			ZEROP_S(l, !=);
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_BRTRUE_R4_S)
+			ZEROP_S(f_r4, !=);
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_BRTRUE_R8_S)
 			ZEROP_S(f, !=);
 			MINT_IN_BREAK;
@@ -3161,6 +3166,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_BRTRUE_I8)
 			ZEROP(l, !=);
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_BRTRUE_R4)
+			ZEROP(f_r4, !=);
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_BRTRUE_R8)
 			ZEROP(f, !=);
 			MINT_IN_BREAK;
@@ -3189,6 +3197,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_BEQ_I8_S)
 			BRELOP_S(l, ==)
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_BEQ_R4_S)
+			CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4)
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_BEQ_R8_S)
 			CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
 			MINT_IN_BREAK;
@@ -3198,6 +3209,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_BEQ_I8)
 			BRELOP(l, ==)
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_BEQ_R4)
+			CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 == sp[1].data.f_r4)
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_BEQ_R8)
 			CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
 			MINT_IN_BREAK;
@@ -3207,6 +3221,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_BGE_I8_S)
 			BRELOP_S(l, >=)
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_BGE_R4_S)
+			CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 >= sp[1].data.f_r4)
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_BGE_R8_S)
 			CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
 			MINT_IN_BREAK;
@@ -3216,6 +3233,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_BGE_I8)
 			BRELOP(l, >=)
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_BGE_R4)
+			CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 >= sp[1].data.f_r4)
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_BGE_R8)
 			CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
 			MINT_IN_BREAK;
@@ -3225,6 +3245,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_BGT_I8_S)
 			BRELOP_S(l, >)
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_BGT_R4_S)
+			CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 > sp[1].data.f_r4)
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_BGT_R8_S)
 			CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
 			MINT_IN_BREAK;
@@ -3234,6 +3257,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_BGT_I8)
 			BRELOP(l, >)
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_BGT_R4)
+			CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 > sp[1].data.f_r4)
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_BGT_R8)
 			CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
 			MINT_IN_BREAK;
@@ -3243,6 +3269,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_BLT_I8_S)
 			BRELOP_S(l, <)
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_BLT_R4_S)
+			CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 < sp[1].data.f_r4)
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_BLT_R8_S)
 			CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
 			MINT_IN_BREAK;
@@ -3252,6 +3281,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_BLT_I8)
 			BRELOP(l, <)
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_BLT_R4)
+			CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 < sp[1].data.f_r4)
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_BLT_R8)
 			CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
 			MINT_IN_BREAK;
@@ -3261,6 +3293,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_BLE_I8_S)
 			BRELOP_S(l, <=)
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_BLE_R4_S)
+			CONDBR_S(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 <= sp[1].data.f_r4)
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_BLE_R8_S)
 			CONDBR_S(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
 			MINT_IN_BREAK;
@@ -3270,6 +3305,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_BLE_I8)
 			BRELOP(l, <=)
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_BLE_R4)
+			CONDBR(!isunordered (sp [0].data.f_r4, sp [1].data.f_r4) && sp[0].data.f_r4 <= sp[1].data.f_r4)
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_BLE_R8)
 			CONDBR(!mono_isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
 			MINT_IN_BREAK;
@@ -3279,6 +3317,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_BNE_UN_I8_S)
 			BRELOP_S(l, !=)
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_BNE_UN_R4_S)
+			CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 != sp[1].data.f_r4)
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_BNE_UN_R8_S)
 			CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
 			MINT_IN_BREAK;
@@ -3288,6 +3329,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_BNE_UN_I8)
 			BRELOP(l, !=)
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_BNE_UN_R4)
+			CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 != sp[1].data.f_r4)
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_BNE_UN_R8)
 			CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
 			MINT_IN_BREAK;
@@ -3312,6 +3356,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_BGE_UN_I8_S)
 			BRELOP_S_CAST(l, >=, guint64);
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_BGE_UN_R4_S)
+			CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4)
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_BGE_UN_R8_S)
 			CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
 			MINT_IN_BREAK;
@@ -3321,6 +3368,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_BGE_UN_I8)
 			BRELOP_CAST(l, >=, guint64);
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_BGE_UN_R4)
+			CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 >= sp[1].data.f_r4)
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_BGE_UN_R8)
 			CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
 			MINT_IN_BREAK;
@@ -3330,6 +3380,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_BGT_UN_I8_S)
 			BRELOP_S_CAST(l, >, guint64);
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_BGT_UN_R4_S)
+			CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 > sp[1].data.f_r4)
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_BGT_UN_R8_S)
 			CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
 			MINT_IN_BREAK;
@@ -3339,6 +3392,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_BGT_UN_I8)
 			BRELOP_CAST(l, >, guint64);
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_BGT_UN_R4)
+			CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 > sp[1].data.f_r4)
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_BGT_UN_R8)
 			CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
 			MINT_IN_BREAK;
@@ -3348,6 +3404,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_BLE_UN_I8_S)
 			BRELOP_S_CAST(l, <=, guint64);
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_BLE_UN_R4_S)
+			CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 <= sp[1].data.f_r4)
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_BLE_UN_R8_S)
 			CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
 			MINT_IN_BREAK;
@@ -3357,6 +3416,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_BLE_UN_I8)
 			BRELOP_CAST(l, <=, guint64);
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_BLE_UN_R4)
+			CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 <= sp[1].data.f_r4)
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_BLE_UN_R8)
 			CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
 			MINT_IN_BREAK;
@@ -3366,6 +3428,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_BLT_UN_I8_S)
 			BRELOP_S_CAST(l, <, guint64);
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_BLT_UN_R4_S)
+			CONDBR_S(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 < sp[1].data.f_r4)
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_BLT_UN_R8_S)
 			CONDBR_S(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
 			MINT_IN_BREAK;
@@ -3375,6 +3440,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_BLT_UN_I8)
 			BRELOP_CAST(l, <, guint64);
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_BLT_UN_R4)
+			CONDBR(isunordered (sp [0].data.f_r4, sp [1].data.f_r4) || sp[0].data.f_r4 < sp[1].data.f_r4)
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_BLT_UN_R8)
 			CONDBR(mono_isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
 			MINT_IN_BREAK;
@@ -3444,7 +3512,7 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 			if (!sp[-1].data.p)
 				THROW_EX (mono_get_exception_null_reference (), ip);
 			++ip;
-			sp[-1].data.f = *(gfloat*)sp[-1].data.p;
+			sp[-1].data.f_r4 = *(gfloat*)sp[-1].data.p;
 			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_LDIND_R8_CHECK)
 			if (!sp[-1].data.p)
@@ -3489,7 +3557,7 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_STIND_R4)
 			++ip;
 			sp -= 2;
-			* (float *) sp->data.p = (gfloat)sp[1].data.f;
+			* (float *) sp->data.p = sp[1].data.f_r4;
 			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_STIND_R8)
 			++ip;
@@ -3511,6 +3579,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_ADD_I8)
 			BINOP(l, +);
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_ADD_R4)
+			BINOP(f_r4, +);
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_ADD_R8)
 			BINOP(f, +);
 			MINT_IN_BREAK;
@@ -3528,6 +3599,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_SUB_I8)
 			BINOP(l, -);
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_SUB_R4)
+			BINOP(f_r4, -);
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_SUB_R8)
 			BINOP(f, -);
 			MINT_IN_BREAK;
@@ -3545,6 +3619,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_MUL_I8)
 			BINOP(l, *);
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_MUL_R4)
+			BINOP(f_r4, *);
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_MUL_R8)
 			BINOP(f, *);
 			MINT_IN_BREAK;
@@ -3562,6 +3639,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 				THROW_EX (mono_get_exception_overflow (), ip);
 			BINOP(l, /);
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_DIV_R4)
+			BINOP(f_r4, /);
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_DIV_R8)
 			BINOP(f, /);
 			MINT_IN_BREAK;
@@ -3594,6 +3674,12 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 				THROW_EX (mono_get_exception_overflow (), ip);
 			BINOP(l, %);
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_REM_R4)
+			/* FIXME: what do we actually do here? */
+			--sp;
+			sp [-1].data.f_r4 = fmodf (sp [-1].data.f_r4, sp [0].data.f_r4);
+			++ip;
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_REM_R8)
 			/* FIXME: what do we actually do here? */
 			--sp;
@@ -3664,6 +3750,10 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 			sp [-1].data.l = - sp [-1].data.l;
 			++ip;
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_NEG_R4)
+			sp [-1].data.f_r4 = - sp [-1].data.f_r4;
+			++ip;
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_NEG_R8)
 			sp [-1].data.f = - sp [-1].data.f;
 			++ip;
@@ -3684,6 +3774,10 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 			sp [-1].data.i = (gint8)sp [-1].data.l;
 			++ip;
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_CONV_I1_R4)
+			sp [-1].data.i = (gint8) (gint32) sp [-1].data.f_r4;
+			++ip;
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_CONV_I1_R8)
 			/* without gint32 cast, C compiler is allowed to use undefined
 			 * behaviour if data.f is bigger than >255. See conv.fpint section
@@ -3703,6 +3797,10 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 			sp [-1].data.i = (guint8)sp [-1].data.l;
 			++ip;
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_CONV_U1_R4)
+			sp [-1].data.i = (guint8) (guint32) sp [-1].data.f_r4;
+			++ip;
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_CONV_U1_R8)
 			sp [-1].data.i = (guint8) (guint32) sp [-1].data.f;
 			++ip;
@@ -3715,6 +3813,10 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 			sp [-1].data.i = (gint16)sp [-1].data.l;
 			++ip;
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_CONV_I2_R4)
+			sp [-1].data.i = (gint16) (gint32) sp [-1].data.f_r4;
+			++ip;
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_CONV_I2_R8)
 			sp [-1].data.i = (gint16) (gint32) sp [-1].data.f;
 			++ip;
@@ -3727,10 +3829,18 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 			sp [-1].data.i = (guint16)sp [-1].data.l;
 			++ip;
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_CONV_U2_R4)
+			sp [-1].data.i = (guint16) (guint32) sp [-1].data.f_r4;
+			++ip;
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_CONV_U2_R8)
 			sp [-1].data.i = (guint16) (guint32) sp [-1].data.f;
 			++ip;
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_CONV_I4_R4)
+			sp [-1].data.i = (gint32) sp [-1].data.f_r4;
+			++ip;
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_CONV_I4_R8)
 			sp [-1].data.i = (gint32)sp [-1].data.f;
 			++ip;
@@ -3744,6 +3854,17 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 			sp [-2].data.i = (gint32)sp [-2].data.l;
 			++ip;
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_CONV_U4_R4)
+			/* needed on arm64 */
+			if (isinf (sp [-1].data.f_r4))
+				sp [-1].data.i = 0;
+			/* needed by wasm */
+			else if (isnan (sp [-1].data.f_r4))
+				sp [-1].data.i = 0;
+			else
+				sp [-1].data.i = (guint32) sp [-1].data.f_r4;
+			++ip;
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_CONV_U4_R8)
 			/* needed on arm64 */
 			if (mono_isinf (sp [-1].data.f))
@@ -3767,20 +3888,24 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 			sp [-1].data.l = (guint32)sp [-1].data.i;
 			++ip;
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_CONV_I8_R4)
+			sp [-1].data.l = (gint64) sp [-1].data.f_r4;
+			++ip;
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_CONV_I8_R8)
 			sp [-1].data.l = (gint64)sp [-1].data.f;
 			++ip;
 			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_CONV_R4_I4)
-			sp [-1].data.f = (float)sp [-1].data.i;
+			sp [-1].data.f_r4 = (float)sp [-1].data.i;
 			++ip;
 			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_CONV_R4_I8)
-			sp [-1].data.f = (float)sp [-1].data.l;
+			sp [-1].data.f_r4 = (float)sp [-1].data.l;
 			++ip;
 			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_CONV_R4_R8)
-			sp [-1].data.f = (float)sp [-1].data.f;
+			sp [-1].data.f_r4 = (float)sp [-1].data.f;
 			++ip;
 			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_CONV_R8_I4)
@@ -3791,10 +3916,22 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 			sp [-1].data.f = (double)sp [-1].data.l;
 			++ip;
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_CONV_R8_R4)
+			sp [-1].data.f = (double) sp [-1].data.f_r4;
+			++ip;
+			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_CONV_R8_R4_SP)
+			sp [-2].data.f = (double) sp [-2].data.f_r4;
+			++ip;
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_CONV_U8_I4)
 			sp [-1].data.l = sp [-1].data.i & 0xffffffff;
 			++ip;
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_CONV_U8_R4)
+			sp [-1].data.l = (guint64) sp [-1].data.f_r4;
+			++ip;
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_CONV_U8_R8)
 			sp [-1].data.l = (guint64)sp [-1].data.f;
 			++ip;
@@ -4159,7 +4296,7 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_LDFLD_U2) LDFLD(i, guint16); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_LDFLD_I4) LDFLD(i, gint32); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_LDFLD_I8) LDFLD(l, gint64); MINT_IN_BREAK;
-		MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(f, float); MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(f_r4, float); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_LDFLD_R8) LDFLD(f, double); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_LDFLD_O) LDFLD(p, gpointer); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_LDFLD_P) LDFLD(p, gpointer); MINT_IN_BREAK;
@@ -4248,7 +4385,7 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_STFLD_U2) STFLD(i, guint16); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_STFLD_I4) STFLD(i, gint32); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_STFLD_I8) STFLD(l, gint64); MINT_IN_BREAK;
-		MINT_IN_CASE(MINT_STFLD_R4) STFLD(f, float); MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_STFLD_R4) STFLD(f_r4, float); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_STFLD_R8) STFLD(f, double); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_STFLD_P) STFLD(p, gpointer); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_STFLD_O)
@@ -4419,6 +4556,12 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 				THROW_EX (mono_get_exception_overflow (), ip);
 			++ip;
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_CONV_OVF_U8_R4)
+			if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT64)
+				THROW_EX (mono_get_exception_overflow (), ip);
+			sp [-1].data.l = (guint64)sp [-1].data.f_r4;
+			++ip;
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_CONV_OVF_U8_R8)
 			if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT64)
 				THROW_EX (mono_get_exception_overflow (), ip);
@@ -4431,6 +4574,12 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 			sp [-1].data.l = (gint64)sp [-1].data.f;
 			++ip;
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_CONV_OVF_I8_R4)
+			if (sp [-1].data.f_r4 < G_MININT64 || sp [-1].data.f_r4 > G_MAXINT64)
+				THROW_EX (mono_get_exception_overflow (), ip);
+			sp [-1].data.l = (gint64)sp [-1].data.f_r4;
+			++ip;
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_CONV_OVF_I8_R8)
 			if (sp [-1].data.f < G_MININT64 || sp [-1].data.f > G_MAXINT64)
 				THROW_EX (mono_get_exception_overflow (), ip);
@@ -4613,7 +4762,7 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 				sp [0].data.l = mono_array_get_fast (o, guint64, aindex);
 				break;
 			case MINT_LDELEM_R4:
-				sp [0].data.f = mono_array_get_fast (o, float, aindex);
+				sp [0].data.f_r4 = mono_array_get_fast (o, float, aindex);
 				break;
 			case MINT_LDELEM_R8:
 				sp [0].data.f = mono_array_get_fast (o, double, aindex);
@@ -4685,7 +4834,7 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 				mono_array_set_fast ((MonoArray *)o, gint64, aindex, sp [2].data.l);
 				break;
 			case MINT_STELEM_R4:
-				mono_array_set_fast ((MonoArray *)o, float, aindex, sp [2].data.f);
+				mono_array_set_fast ((MonoArray *)o, float, aindex, sp [2].data.f_r4);
 				break;
 			case MINT_STELEM_R8:
 				mono_array_set_fast ((MonoArray *)o, double, aindex, sp [2].data.f);
@@ -4732,6 +4881,12 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 			sp [-1].data.i = (gint32) sp [-1].data.l;
 			++ip;
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_CONV_OVF_I4_R4)
+			if (sp [-1].data.f_r4 < G_MININT32 || sp [-1].data.f_r4 > G_MAXINT32)
+				THROW_EX (mono_get_exception_overflow (), ip);
+			sp [-1].data.i = (gint32) sp [-1].data.f_r4;
+			++ip;
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_CONV_OVF_I4_R8)
 			if (sp [-1].data.f < G_MININT32 || sp [-1].data.f > G_MAXINT32)
 				THROW_EX (mono_get_exception_overflow (), ip);
@@ -4749,6 +4904,12 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 			sp [-1].data.i = (guint32) sp [-1].data.l;
 			++ip;
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_CONV_OVF_U4_R4)
+			if (sp [-1].data.f_r4 < 0 || sp [-1].data.f_r4 > G_MAXUINT32)
+				THROW_EX (mono_get_exception_overflow (), ip);
+			sp [-1].data.i = (guint32) sp [-1].data.f_r4;
+			++ip;
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_CONV_OVF_U4_R8)
 			if (sp [-1].data.f < 0 || sp [-1].data.f > G_MAXUINT32)
 				THROW_EX (mono_get_exception_overflow (), ip);
@@ -5208,6 +5369,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_CEQ_I8)
 			RELOP(l, ==);
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_CEQ_R4)
+			RELOP_FP(f_r4, ==, 0);
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_CEQ_R8)
 			RELOP_FP(f, ==, 0);
 			MINT_IN_BREAK;
@@ -5217,6 +5381,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_CNE_I8)
 			RELOP(l, !=);
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_CNE_R4)
+			RELOP_FP(f_r4, !=, 1);
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_CNE_R8)
 			RELOP_FP(f, !=, 1);
 			MINT_IN_BREAK;
@@ -5226,6 +5393,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_CGT_I8)
 			RELOP(l, >);
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_CGT_R4)
+			RELOP_FP(f_r4, >, 0);
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_CGT_R8)
 			RELOP_FP(f, >, 0);
 			MINT_IN_BREAK;
@@ -5235,6 +5405,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_CGE_I8)
 			RELOP(l, >=);
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_CGE_R4)
+			RELOP_FP(f_r4, >=, 0);
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_CGE_R8)
 			RELOP_FP(f, >=, 0);
 			MINT_IN_BREAK;
@@ -5257,6 +5430,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_CGT_UN_I8)
 			RELOP_CAST(l, >, guint64);
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_CGT_UN_R4)
+			RELOP_FP(f_r4, >, 1);
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_CGT_UN_R8)
 			RELOP_FP(f, >, 1);
 			MINT_IN_BREAK;
@@ -5266,6 +5442,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_CLT_I8)
 			RELOP(l, <);
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_CLT_R4)
+			RELOP_FP(f_r4, <, 0);
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_CLT_R8)
 			RELOP_FP(f, <, 0);
 			MINT_IN_BREAK;
@@ -5275,6 +5454,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_CLT_UN_I8)
 			RELOP_CAST(l, <, guint64);
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_CLT_UN_R4)
+			RELOP_FP(f_r4, <, 1);
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_CLT_UN_R8)
 			RELOP_FP(f, <, 1);
 			MINT_IN_BREAK;
@@ -5290,6 +5472,9 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_CLE_UN_I8)
 			RELOP_CAST(l, <=, guint64);
 			MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_CLE_R4)
+			RELOP_FP(f_r4, <=, 0);
+			MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_CLE_R8)
 			RELOP_FP(f, <=, 0);
 			MINT_IN_BREAK;
@@ -5327,7 +5512,7 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_LDARG_U2) LDARG(i, guint16); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_LDARG_I4) LDARG(i, gint32); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_LDARG_I8) LDARG(l, gint64); MINT_IN_BREAK;
-		MINT_IN_CASE(MINT_LDARG_R4) LDARG(f, float); MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_LDARG_R4) LDARG(f_r4, float); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_LDARG_R8) LDARG(f, double); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_LDARG_O) LDARG(p, gpointer); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_LDARG_P) LDARG(p, gpointer); MINT_IN_BREAK;
@@ -5352,7 +5537,7 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_STARG_U2) STARG(i, guint16); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_STARG_I4) STARG(i, gint32); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_STARG_I8) STARG(l, gint64); MINT_IN_BREAK;
-		MINT_IN_CASE(MINT_STARG_R4) STARG(f, float); MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_STARG_R4) STARG(f_r4, float); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_STARG_R8) STARG(f, double); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_STARG_O) STARG(p, gpointer); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_STARG_P) STARG(p, gpointer); MINT_IN_BREAK;
@@ -5378,7 +5563,7 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_STINARG_U2) STINARG(i, guint16); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_STINARG_I4) STINARG(i, gint32); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_STINARG_I8) STINARG(l, gint64); MINT_IN_BREAK;
-		MINT_IN_CASE(MINT_STINARG_R4) STINARG(f, float); MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_STINARG_R4) STINARG(f_r4, float); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_STINARG_R8) STINARG(f, double); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_STINARG_O) STINARG(p, gpointer); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_STINARG_P) STINARG(p, gpointer); MINT_IN_BREAK;
@@ -5428,7 +5613,7 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_LDLOC_U2) LDLOC(i, guint16); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_LDLOC_I4) LDLOC(i, gint32); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_LDLOC_I8) LDLOC(l, gint64); MINT_IN_BREAK;
-		MINT_IN_CASE(MINT_LDLOC_R4) LDLOC(f, float); MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_LDLOC_R4) LDLOC(f_r4, float); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_LDLOC_R8) LDLOC(f, double); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_LDLOC_O) LDLOC(p, gpointer); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_LDLOC_P) LDLOC(p, gpointer); MINT_IN_BREAK;
@@ -5459,7 +5644,7 @@ interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *st
 		MINT_IN_CASE(MINT_STLOC_U2) STLOC(i, guint16); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_STLOC_I4) STLOC(i, gint32); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_STLOC_I8) STLOC(l, gint64); MINT_IN_BREAK;
-		MINT_IN_CASE(MINT_STLOC_R4) STLOC(f, float); MINT_IN_BREAK;
+		MINT_IN_CASE(MINT_STLOC_R4) STLOC(f_r4, float); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_STLOC_R8) STLOC(f, double); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_STLOC_O) STLOC(p, gpointer); MINT_IN_BREAK;
 		MINT_IN_CASE(MINT_STLOC_P) STLOC(p, gpointer); MINT_IN_BREAK;

+ 52 - 0
mono/mini/interp/mintops.def

@@ -185,80 +185,104 @@ OPDEF(MINT_SAFEPOINT, "safepoint", 1, MintOpNoArgs)
 
 OPDEF(MINT_BRFALSE_I4, "brfalse.i4", 3, MintOpBranch)
 OPDEF(MINT_BRFALSE_I8, "brfalse.i8", 3, MintOpBranch)
+OPDEF(MINT_BRFALSE_R4, "brfalse.r4", 3, MintOpBranch)
 OPDEF(MINT_BRFALSE_R8, "brfalse.r8", 3, MintOpBranch)
 OPDEF(MINT_BRTRUE_I4, "brtrue.i4", 3, MintOpBranch)
 OPDEF(MINT_BRTRUE_I8, "brtrue.i8", 3, MintOpBranch)
+OPDEF(MINT_BRTRUE_R4, "brtrue.r4", 3, MintOpBranch)
 OPDEF(MINT_BRTRUE_R8, "brtrue.r8", 3, MintOpBranch)
 
 OPDEF(MINT_BRFALSE_I4_S, "brfalse.i4.s", 2, MintOpShortBranch)
 OPDEF(MINT_BRFALSE_I8_S, "brfalse.i8.s", 2, MintOpShortBranch)
+OPDEF(MINT_BRFALSE_R4_S, "brfalse.r4.s", 2, MintOpShortBranch)
 OPDEF(MINT_BRFALSE_R8_S, "brfalse.r8.s", 2, MintOpShortBranch)
 OPDEF(MINT_BRTRUE_I4_S, "brtrue.i4.s", 2, MintOpShortBranch)
 OPDEF(MINT_BRTRUE_I8_S, "brtrue.i8.s", 2, MintOpShortBranch)
+OPDEF(MINT_BRTRUE_R4_S, "brtrue.r4.s", 2, MintOpShortBranch)
 OPDEF(MINT_BRTRUE_R8_S, "brtrue.r8.s", 2, MintOpShortBranch)
 
 OPDEF(MINT_BEQ_I4, "beq.i4", 3, MintOpBranch)
 OPDEF(MINT_BEQ_I8, "beq.i8", 3, MintOpBranch)
+OPDEF(MINT_BEQ_R4, "beq.r4", 3, MintOpBranch)
 OPDEF(MINT_BEQ_R8, "beq.r8", 3, MintOpBranch)
 OPDEF(MINT_BGE_I4, "bge.i4", 3, MintOpBranch) 
 OPDEF(MINT_BGE_I8, "bge.i8", 3, MintOpBranch) 
+OPDEF(MINT_BGE_R4, "bge.r4", 3, MintOpBranch)
 OPDEF(MINT_BGE_R8, "bge.r8", 3, MintOpBranch) 
 OPDEF(MINT_BGT_I4, "bgt.i4", 3, MintOpBranch) 
 OPDEF(MINT_BGT_I8, "bgt.i8", 3, MintOpBranch) 
+OPDEF(MINT_BGT_R4, "bgt.r4", 3, MintOpBranch)
 OPDEF(MINT_BGT_R8, "bgt.r8", 3, MintOpBranch) 
 OPDEF(MINT_BLT_I4, "blt.i4", 3, MintOpBranch) 
 OPDEF(MINT_BLT_I8, "blt.i8", 3, MintOpBranch) 
+OPDEF(MINT_BLT_R4, "blt.r4", 3, MintOpBranch)
 OPDEF(MINT_BLT_R8, "blt.r8", 3, MintOpBranch) 
 OPDEF(MINT_BLE_I4, "ble.i4", 3, MintOpBranch) 
 OPDEF(MINT_BLE_I8, "ble.i8", 3, MintOpBranch) 
+OPDEF(MINT_BLE_R4, "ble.r4", 3, MintOpBranch)
 OPDEF(MINT_BLE_R8, "ble.r8", 3, MintOpBranch) 
 
 OPDEF(MINT_BNE_UN_I4, "bne.un.i4", 3, MintOpBranch)
 OPDEF(MINT_BNE_UN_I8, "bne.un.i8", 3, MintOpBranch)
+OPDEF(MINT_BNE_UN_R4, "bne.un.r4", 3, MintOpBranch)
 OPDEF(MINT_BNE_UN_R8, "bne.un.r8", 3, MintOpBranch)
 OPDEF(MINT_BGE_UN_I4, "bge.un.i4", 3, MintOpBranch) 
 OPDEF(MINT_BGE_UN_I8, "bge.un.i8", 3, MintOpBranch) 
+OPDEF(MINT_BGE_UN_R4, "bge.un.r4", 3, MintOpBranch)
 OPDEF(MINT_BGE_UN_R8, "bge.un.r8", 3, MintOpBranch) 
 OPDEF(MINT_BGT_UN_I4, "bgt.un.i4", 3, MintOpBranch) 
 OPDEF(MINT_BGT_UN_I8, "bgt.un.i8", 3, MintOpBranch) 
+OPDEF(MINT_BGT_UN_R4, "bgt.un.r4", 3, MintOpBranch)
 OPDEF(MINT_BGT_UN_R8, "bgt.un.r8", 3, MintOpBranch) 
 OPDEF(MINT_BLE_UN_I4, "ble.un.i4", 3, MintOpBranch) 
 OPDEF(MINT_BLE_UN_I8, "ble.un.i8", 3, MintOpBranch) 
+OPDEF(MINT_BLE_UN_R4, "ble.un.r4", 3, MintOpBranch)
 OPDEF(MINT_BLE_UN_R8, "ble.un.r8", 3, MintOpBranch) 
 OPDEF(MINT_BLT_UN_I4, "blt.un.i4", 3, MintOpBranch) 
 OPDEF(MINT_BLT_UN_I8, "blt.un.i8", 3, MintOpBranch) 
+OPDEF(MINT_BLT_UN_R4, "blt.un.r4", 3, MintOpBranch)
 OPDEF(MINT_BLT_UN_R8, "blt.un.r8", 3, MintOpBranch) 
 
 OPDEF(MINT_BEQ_I4_S, "beq.i4.s", 2, MintOpShortBranch)
 OPDEF(MINT_BEQ_I8_S, "beq.i8.s", 2, MintOpShortBranch)
+OPDEF(MINT_BEQ_R4_S, "beq.r4.s", 2, MintOpShortBranch)
 OPDEF(MINT_BEQ_R8_S, "beq.r8.s", 2, MintOpShortBranch)
 OPDEF(MINT_BGE_I4_S, "bge.i4.s", 2, MintOpShortBranch) 
 OPDEF(MINT_BGE_I8_S, "bge.i8.s", 2, MintOpShortBranch) 
+OPDEF(MINT_BGE_R4_S, "bge.r4.s", 2, MintOpShortBranch) 
 OPDEF(MINT_BGE_R8_S, "bge.r8.s", 2, MintOpShortBranch) 
 OPDEF(MINT_BGT_I4_S, "bgt.i4.s", 2, MintOpShortBranch) 
 OPDEF(MINT_BGT_I8_S, "bgt.i8.s", 2, MintOpShortBranch) 
+OPDEF(MINT_BGT_R4_S, "bgt.r4.s", 2, MintOpShortBranch) 
 OPDEF(MINT_BGT_R8_S, "bgt.r8.s", 2, MintOpShortBranch) 
 OPDEF(MINT_BLT_I4_S, "blt.i4.s", 2, MintOpShortBranch) 
 OPDEF(MINT_BLT_I8_S, "blt.i8.s", 2, MintOpShortBranch) 
+OPDEF(MINT_BLT_R4_S, "blt.r4.s", 2, MintOpShortBranch) 
 OPDEF(MINT_BLT_R8_S, "blt.r8.s", 2, MintOpShortBranch) 
 OPDEF(MINT_BLE_I4_S, "ble.i4.s", 2, MintOpShortBranch) 
 OPDEF(MINT_BLE_I8_S, "ble.i8.s", 2, MintOpShortBranch) 
+OPDEF(MINT_BLE_R4_S, "ble.r4.s", 2, MintOpShortBranch) 
 OPDEF(MINT_BLE_R8_S, "ble.r8.s", 2, MintOpShortBranch) 
 
 OPDEF(MINT_BNE_UN_I4_S, "bne.un.i4.s", 2, MintOpShortBranch)
 OPDEF(MINT_BNE_UN_I8_S, "bne.un.i8.s", 2, MintOpShortBranch)
+OPDEF(MINT_BNE_UN_R4_S, "bne.un.r4.s", 2, MintOpShortBranch)
 OPDEF(MINT_BNE_UN_R8_S, "bne.un.r8.s", 2, MintOpShortBranch)
 OPDEF(MINT_BGE_UN_I4_S, "bge.un.i4.s", 2, MintOpShortBranch) 
 OPDEF(MINT_BGE_UN_I8_S, "bge.un.i8.s", 2, MintOpShortBranch) 
+OPDEF(MINT_BGE_UN_R4_S, "bge.un.r4.s", 2, MintOpShortBranch) 
 OPDEF(MINT_BGE_UN_R8_S, "bge.un.r8.s", 2, MintOpShortBranch) 
 OPDEF(MINT_BGT_UN_I4_S, "bgt.un.i4.s", 2, MintOpShortBranch) 
 OPDEF(MINT_BGT_UN_I8_S, "bgt.un.i8.s", 2, MintOpShortBranch) 
+OPDEF(MINT_BGT_UN_R4_S, "bgt.un.r4.s", 2, MintOpShortBranch) 
 OPDEF(MINT_BGT_UN_R8_S, "bgt.un.r8.s", 2, MintOpShortBranch) 
 OPDEF(MINT_BLE_UN_I4_S, "ble.un.i4.s", 2, MintOpShortBranch) 
 OPDEF(MINT_BLE_UN_I8_S, "ble.un.i8.s", 2, MintOpShortBranch) 
+OPDEF(MINT_BLE_UN_R4_S, "ble.un.r4.s", 2, MintOpShortBranch) 
 OPDEF(MINT_BLE_UN_R8_S, "ble.un.r8.s", 2, MintOpShortBranch) 
 OPDEF(MINT_BLT_UN_I4_S, "blt.un.i4.s", 2, MintOpShortBranch) 
 OPDEF(MINT_BLT_UN_I8_S, "blt.un.i8.s", 2, MintOpShortBranch) 
+OPDEF(MINT_BLT_UN_R4_S, "blt.un.r4.s", 2, MintOpShortBranch) 
 OPDEF(MINT_BLT_UN_R8_S, "blt.un.r8.s", 2, MintOpShortBranch) 
 
 OPDEF(MINT_SWITCH, "switch", 0, MintOpSwitch)
@@ -338,6 +362,7 @@ OPDEF(MINT_GETITEM_SPAN, "getitem.span", 4, MintOpShortAndInt)
 
 OPDEF(MINT_ADD_I4, "add.i4", 1, MintOpNoArgs)
 OPDEF(MINT_ADD_I8, "add.i8", 1, MintOpNoArgs)
+OPDEF(MINT_ADD_R4, "add.r4", 1, MintOpNoArgs)
 OPDEF(MINT_ADD_R8, "add.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_ADD1_I4, "add1.i4", 1, MintOpNoArgs)
@@ -345,6 +370,7 @@ OPDEF(MINT_ADD1_I8, "add1.i8", 1, MintOpNoArgs)
 
 OPDEF(MINT_SUB_I4, "sub.i4", 1, MintOpNoArgs)
 OPDEF(MINT_SUB_I8, "sub.i8", 1, MintOpNoArgs)
+OPDEF(MINT_SUB_R4, "sub.r4", 1, MintOpNoArgs)
 OPDEF(MINT_SUB_R8, "sub.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_SUB1_I4, "sub1.i4", 1, MintOpNoArgs)
@@ -352,10 +378,12 @@ OPDEF(MINT_SUB1_I8, "sub1.i8", 1, MintOpNoArgs)
 
 OPDEF(MINT_MUL_I4, "mul.i4", 1, MintOpNoArgs)
 OPDEF(MINT_MUL_I8, "mul.i8", 1, MintOpNoArgs)
+OPDEF(MINT_MUL_R4, "mul.r4", 1, MintOpNoArgs)
 OPDEF(MINT_MUL_R8, "mul.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_DIV_I4, "div.i4", 1, MintOpNoArgs)
 OPDEF(MINT_DIV_I8, "div.i8", 1, MintOpNoArgs)
+OPDEF(MINT_DIV_R4, "div.r4", 1, MintOpNoArgs)
 OPDEF(MINT_DIV_R8, "div.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_DIV_UN_I4, "div.un.i4", 1, MintOpNoArgs)
@@ -381,6 +409,7 @@ OPDEF(MINT_SUB_OVF_UN_I8, "sub.ovf.un.i8", 1, MintOpNoArgs)
 
 OPDEF(MINT_NEG_I4, "neg.i4", 1, MintOpNoArgs)
 OPDEF(MINT_NEG_I8, "neg.i8", 1, MintOpNoArgs)
+OPDEF(MINT_NEG_R4, "neg.r4", 1, MintOpNoArgs)
 OPDEF(MINT_NEG_R8, "neg.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_NOT_I4, "not.i4", 1, MintOpNoArgs)
@@ -397,6 +426,7 @@ OPDEF(MINT_XOR_I8, "xor.i8", 1, MintOpNoArgs)
 
 OPDEF(MINT_REM_I4, "rem.i4", 1, MintOpNoArgs)
 OPDEF(MINT_REM_I8, "rem.i8", 1, MintOpNoArgs)
+OPDEF(MINT_REM_R4, "rem.r4", 1, MintOpNoArgs)
 OPDEF(MINT_REM_R8, "rem.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_REM_UN_I4, "rem.un.i4", 1, MintOpNoArgs)
@@ -414,28 +444,35 @@ OPDEF(MINT_CONV_R_UN_I8, "conv.r.un.i8", 1, MintOpNoArgs)
 
 OPDEF(MINT_CONV_I1_I4, "conv.i1.i4", 1, MintOpNoArgs)
 OPDEF(MINT_CONV_I1_I8, "conv.i1.i8", 1, MintOpNoArgs)
+OPDEF(MINT_CONV_I1_R4, "conv.i1.r4", 1, MintOpNoArgs)
 OPDEF(MINT_CONV_I1_R8, "conv.i1.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_CONV_U1_I4, "conv.u1.i4", 1, MintOpNoArgs)
 OPDEF(MINT_CONV_U1_I8, "conv.u1.i8", 1, MintOpNoArgs)
+OPDEF(MINT_CONV_U1_R4, "conv.u1.r4", 1, MintOpNoArgs)
 OPDEF(MINT_CONV_U1_R8, "conv.u1.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_CONV_I2_I4, "conv.i2.i4", 1, MintOpNoArgs)
 OPDEF(MINT_CONV_I2_I8, "conv.i2.i8", 1, MintOpNoArgs)
+OPDEF(MINT_CONV_I2_R4, "conv.i2.r4", 1, MintOpNoArgs)
 OPDEF(MINT_CONV_I2_R8, "conv.i2.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_CONV_U2_I4, "conv.u2.i4", 1, MintOpNoArgs)
 OPDEF(MINT_CONV_U2_I8, "conv.u2.i8", 1, MintOpNoArgs)
+OPDEF(MINT_CONV_U2_R4, "conv.u2.r4", 1, MintOpNoArgs)
 OPDEF(MINT_CONV_U2_R8, "conv.u2.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_CONV_I4_I8, "conv.i4.i8", 1, MintOpNoArgs)
+OPDEF(MINT_CONV_I4_R4, "conv.i4.r4", 1, MintOpNoArgs)
 OPDEF(MINT_CONV_I4_R8, "conv.i4.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_CONV_U4_I8, "conv.u4.i8", 1, MintOpNoArgs)
+OPDEF(MINT_CONV_U4_R4, "conv.u4.r4", 1, MintOpNoArgs)
 OPDEF(MINT_CONV_U4_R8, "conv.u4.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_CONV_I8_I4, "conv.i8.i4", 1, MintOpNoArgs)
 OPDEF(MINT_CONV_I8_U4, "conv.i8.u4", 1, MintOpNoArgs)
+OPDEF(MINT_CONV_I8_R4, "conv.i8.r4", 1, MintOpNoArgs)
 OPDEF(MINT_CONV_I8_R8, "conv.i8.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_CONV_R4_I4, "conv.r4.i4", 1, MintOpNoArgs)
@@ -444,11 +481,14 @@ OPDEF(MINT_CONV_R4_R8, "conv.r4.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_CONV_R8_I4, "conv.r8.i4", 1, MintOpNoArgs)
 OPDEF(MINT_CONV_R8_I8, "conv.r8.i8", 1, MintOpNoArgs)
+OPDEF(MINT_CONV_R8_R4, "conv.r8.r4", 1, MintOpNoArgs)
 
 OPDEF(MINT_CONV_I4_I8_SP, "conv.i4.i8.sp", 1, MintOpNoArgs) /* special for narrowing sp[-2] on 64 bits */
 OPDEF(MINT_CONV_I8_I4_SP, "conv.i8.i4.sp", 1, MintOpNoArgs) /* special for widening sp[-2] on 64 bits */
+OPDEF(MINT_CONV_R8_R4_SP, "conv.r8.r4.sp", 1, MintOpNoArgs)
 
 OPDEF(MINT_CONV_U8_I4, "conv.u8.i4", 1, MintOpNoArgs)
+OPDEF(MINT_CONV_U8_R4, "conv.u8.r4", 1, MintOpNoArgs)
 OPDEF(MINT_CONV_U8_R8, "conv.u8.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_CONV_OVF_I1_I4, "conv.ovf.i1.i4", 1, MintOpNoArgs)
@@ -478,6 +518,7 @@ OPDEF(MINT_CONV_OVF_U2_R8, "conv.ovf.u2.r8", 1, MintOpNoArgs)
 OPDEF(MINT_CONV_OVF_I4_U4, "conv.ovf.i4.u4", 1, MintOpNoArgs)
 OPDEF(MINT_CONV_OVF_I4_I8, "conv.ovf.i4.i8", 1, MintOpNoArgs)
 OPDEF(MINT_CONV_OVF_I4_U8, "conv.ovf.i4.u8", 1, MintOpNoArgs)
+OPDEF(MINT_CONV_OVF_I4_R4, "conv.ovf.i4.r4", 1, MintOpNoArgs)
 OPDEF(MINT_CONV_OVF_I4_R8, "conv.ovf.i4.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_CONV_OVF_I4_UN_I8, "conv.ovf.i4.un.i8", 1, MintOpNoArgs)
@@ -485,33 +526,40 @@ OPDEF(MINT_CONV_OVF_I4_UN_R8, "conv.ovf.i4.un.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_CONV_OVF_U4_I4, "conv.ovf.u4.i4", 1, MintOpNoArgs)
 OPDEF(MINT_CONV_OVF_U4_I8, "conv.ovf.u4.i8", 1, MintOpNoArgs)
+OPDEF(MINT_CONV_OVF_U4_R4, "conv.ovf.u4.r4", 1, MintOpNoArgs)
 OPDEF(MINT_CONV_OVF_U4_R8, "conv.ovf.u4.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_CONV_OVF_I8_U8, "conv.ovf.i8.u8", 1, MintOpNoArgs)
+OPDEF(MINT_CONV_OVF_I8_R4, "conv.ovf.i8.r4", 1, MintOpNoArgs)
 OPDEF(MINT_CONV_OVF_I8_R8, "conv.ovf.i8.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_CONV_OVF_I8_UN_R8, "conv.ovf.i8.un.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_CONV_OVF_U8_I4, "conv.ovf.u8.i4", 1, MintOpNoArgs)
 OPDEF(MINT_CONV_OVF_U8_I8, "conv.ovf.u8.i8", 1, MintOpNoArgs)
+OPDEF(MINT_CONV_OVF_U8_R4, "conv.ovf.u8.r4", 1, MintOpNoArgs)
 OPDEF(MINT_CONV_OVF_U8_R8, "conv.ovf.u8.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_CEQ_I4, "ceq.i4", 1, MintOpNoArgs)
 OPDEF(MINT_CEQ_I8, "ceq.i8", 1, MintOpNoArgs)
+OPDEF(MINT_CEQ_R4, "ceq.r4", 1, MintOpNoArgs)
 OPDEF(MINT_CEQ_R8, "ceq.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_CNE_I4, "cne.i4", 1, MintOpNoArgs)
 OPDEF(MINT_CNE_I8, "cne.i8", 1, MintOpNoArgs)
+OPDEF(MINT_CNE_R4, "cne.r4", 1, MintOpNoArgs)
 OPDEF(MINT_CNE_R8, "cne.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_CEQ0_I4, "ceq0.i4", 1, MintOpNoArgs)
 
 OPDEF(MINT_CGT_I4, "cgt.i4", 1, MintOpNoArgs)
 OPDEF(MINT_CGT_I8, "cgt.i8", 1, MintOpNoArgs)
+OPDEF(MINT_CGT_R4, "cgt.r4", 1, MintOpNoArgs)
 OPDEF(MINT_CGT_R8, "cgt.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_CGE_I4, "cge.i4", 1, MintOpNoArgs)
 OPDEF(MINT_CGE_I8, "cge.i8", 1, MintOpNoArgs)
+OPDEF(MINT_CGE_R4, "cge.r4", 1, MintOpNoArgs)
 OPDEF(MINT_CGE_R8, "cge.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_CGE_UN_I4, "cge.un.i4", 1, MintOpNoArgs)
@@ -519,14 +567,17 @@ OPDEF(MINT_CGE_UN_I8, "cge.un.i8", 1, MintOpNoArgs)
 
 OPDEF(MINT_CGT_UN_I4, "cgt.un.i4", 1, MintOpNoArgs)
 OPDEF(MINT_CGT_UN_I8, "cgt.un.i8", 1, MintOpNoArgs)
+OPDEF(MINT_CGT_UN_R4, "cgt.un.r4", 1, MintOpNoArgs)
 OPDEF(MINT_CGT_UN_R8, "cgt.un.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_CLT_I4, "clt.i4", 1, MintOpNoArgs)
 OPDEF(MINT_CLT_I8, "clt.i8", 1, MintOpNoArgs)
+OPDEF(MINT_CLT_R4, "clt.r4", 1, MintOpNoArgs)
 OPDEF(MINT_CLT_R8, "clt.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_CLE_I4, "cle.i4", 1, MintOpNoArgs)
 OPDEF(MINT_CLE_I8, "cle.i8", 1, MintOpNoArgs)
+OPDEF(MINT_CLE_R4, "cle.r4", 1, MintOpNoArgs)
 OPDEF(MINT_CLE_R8, "cle.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_CLE_UN_I4, "cle.un.i4", 1, MintOpNoArgs)
@@ -534,6 +585,7 @@ OPDEF(MINT_CLE_UN_I8, "cle.un.i8", 1, MintOpNoArgs)
 
 OPDEF(MINT_CLT_UN_I4, "clt.un.i4", 1, MintOpNoArgs)
 OPDEF(MINT_CLT_UN_I8, "clt.un.i8", 1, MintOpNoArgs)
+OPDEF(MINT_CLT_UN_R4, "clt.un.r4", 1, MintOpNoArgs)
 OPDEF(MINT_CLT_UN_R8, "clt.un.r8", 1, MintOpNoArgs)
 
 OPDEF(MINT_CKFINITE, "ckfinite", 1, MintOpNoArgs)

+ 206 - 75
mono/mini/interp/transform.c

@@ -106,13 +106,14 @@ typedef struct
 
 #define STACK_TYPE_I4 0
 #define STACK_TYPE_I8 1
-#define STACK_TYPE_R8 2
-#define STACK_TYPE_O  3
-#define STACK_TYPE_VT 4
-#define STACK_TYPE_MP 5
-#define STACK_TYPE_F  6
+#define STACK_TYPE_R4 2
+#define STACK_TYPE_R8 3
+#define STACK_TYPE_O  4
+#define STACK_TYPE_VT 5
+#define STACK_TYPE_MP 6
+#define STACK_TYPE_F  7
 
-static const char *stack_type_string [] = { "I4", "I8", "R8", "O ", "VT", "MP", "F " };
+static const char *stack_type_string [] = { "I4", "I8", "R4", "R8", "O ", "VT", "MP", "F " };
 
 #if SIZEOF_VOID_P == 8
 #define STACK_TYPE_I STACK_TYPE_I8
@@ -127,7 +128,7 @@ static int stack_type [] = {
 	STACK_TYPE_I4, /*U2*/
 	STACK_TYPE_I4, /*I4*/
 	STACK_TYPE_I8, /*I8*/
-	STACK_TYPE_R8, /*R4*/
+	STACK_TYPE_R4, /*R4*/
 	STACK_TYPE_R8, /*R8*/
 	STACK_TYPE_O,  /*O*/
 	STACK_TYPE_MP, /*P*/
@@ -183,7 +184,7 @@ static int stack_type [] = {
 #define MINT_NEG_P MINT_NEG_I4
 #define MINT_NOT_P MINT_NOT_I4
 
-#define MINT_NEG_FP MINT_NEG_R8
+#define MINT_NEG_FP MINT_NEG_R4
 
 #define MINT_ADD_P MINT_ADD_I4
 #define MINT_SUB_P MINT_SUB_I4
@@ -210,18 +211,18 @@ static int stack_type [] = {
 #define MINT_CGE_P MINT_CGE_I4
 #define MINT_CGE_UN_P MINT_CGE_UN_I4
 
-#define MINT_ADD_FP MINT_ADD_R8
-#define MINT_SUB_FP MINT_SUB_R8
-#define MINT_MUL_FP MINT_MUL_R8
-#define MINT_DIV_FP MINT_DIV_R8
-#define MINT_REM_FP MINT_REM_R8
+#define MINT_ADD_FP MINT_ADD_R4
+#define MINT_SUB_FP MINT_SUB_R4
+#define MINT_MUL_FP MINT_MUL_R4
+#define MINT_DIV_FP MINT_DIV_R4
+#define MINT_REM_FP MINT_REM_R4
 
-#define MINT_CNE_FP MINT_CNE_R8
-#define MINT_CEQ_FP MINT_CEQ_R8
-#define MINT_CGT_FP MINT_CGT_R8
-#define MINT_CGE_FP MINT_CGE_R8
-#define MINT_CLT_FP MINT_CLT_R8
-#define MINT_CLE_FP MINT_CLE_R8
+#define MINT_CNE_FP MINT_CNE_R4
+#define MINT_CEQ_FP MINT_CEQ_R4
+#define MINT_CGT_FP MINT_CGT_R4
+#define MINT_CGE_FP MINT_CGE_R4
+#define MINT_CLT_FP MINT_CLT_R4
+#define MINT_CLE_FP MINT_CLE_R4
 
 #endif
 
@@ -385,6 +386,12 @@ two_arg_branch(TransformData *td, int mint_op, int offset)
 	} else if (type1 == STACK_TYPE_I8 && type2 == STACK_TYPE_I4) {
 		ADD_CODE(td, MINT_CONV_I8_I4_SP);
 		td->in_offsets [td->ip - td->il_code]++;
+	} else if (type1 == STACK_TYPE_R4 && type2 == STACK_TYPE_R8) {
+		ADD_CODE (td, MINT_CONV_R8_R4);
+		td->in_offsets [td->ip - td->il_code]++;
+	} else if (type1 == STACK_TYPE_R8 && type2 == STACK_TYPE_R4) {
+		ADD_CODE (td, MINT_CONV_R8_R4_SP);
+		td->in_offsets [td->ip - td->il_code]++;
 	} else if (type1 != type2) {
 		g_warning("%s.%s: branch type mismatch %d %d", 
 			m_class_get_name (td->method->klass), td->method->name,
@@ -419,6 +426,15 @@ binary_arith_op(TransformData *td, int mint_op)
 		td->sp [-2].type = STACK_TYPE_I8;
 	}
 #endif
+	if (type1 == STACK_TYPE_R8 && type2 == STACK_TYPE_R4) {
+		ADD_CODE (td, MINT_CONV_R8_R4);
+		type2 = STACK_TYPE_R8;
+	}
+	if (type1 == STACK_TYPE_R4 && type2 == STACK_TYPE_R8) {
+		ADD_CODE (td, MINT_CONV_R8_R4_SP);
+		type1 = STACK_TYPE_R8;
+		td->sp [-2].type = STACK_TYPE_R8;
+	}
 	if (type1 == STACK_TYPE_MP)
 		type1 = STACK_TYPE_I;
 	if (type2 == STACK_TYPE_MP)
@@ -818,20 +834,6 @@ jit_call_supported (MonoMethod *method, MonoMethodSignature *sig)
 	return FALSE;
 }
 
-static inline gboolean
-type_size (MonoType *type)
-{
-	if (type->type == MONO_TYPE_I4 || type->type == MONO_TYPE_U4)
-		return 4;
-	else if (type->type == MONO_TYPE_I8 || type->type == MONO_TYPE_U8)
-		return 8;
-	else if (type->type == MONO_TYPE_R4 && !type->byref)
-		return 4;
-	else if (type->type == MONO_TYPE_R8 && !type->byref)
-		return 8;
-	return SIZEOF_VOID_P;
-}
-
 static int mono_class_get_magic_index (MonoClass *k)
 {
 	if (mono_class_is_magic_int (k))
@@ -863,6 +865,37 @@ interp_generate_mae_throw (TransformData *td, MonoMethod *method, MonoMethod *ta
 	td->sp -= 2;
 }
 
+/*
+ * These are additional locals that can be allocated as we transform the code.
+ * They are allocated past the method locals so they are accessed in the same
+ * way, with an offset relative to the frame->locals.
+ */
+static int
+create_interp_local (TransformData *td, MonoType *type)
+{
+	int align, size;
+	int offset = td->total_locals_size;
+
+	size = mono_type_size (type, &align);
+	offset = ALIGN_TO (offset, align);
+
+	td->total_locals_size = offset + size;
+
+	return offset;
+}
+
+static void
+dump_mint_code (TransformData *td)
+{
+	const guint16 *p = td->new_code;
+	while (p < td->new_ip) {
+		char *ins = mono_interp_dis_mintop (td->new_code, p);
+		g_print ("%s\n", ins);
+		g_free (ins);
+		p = mono_interp_dis_mintop_len (p);
+	}
+}
+
 static MonoMethodHeader*
 interp_method_get_header (MonoMethod* method, MonoError *error)
 {
@@ -876,6 +909,24 @@ interp_method_get_header (MonoMethod* method, MonoError *error)
 		return mono_method_get_header_internal (method, error);
 }
 
+/* stores top of stack as local and pushes address of it on stack */
+static void
+emit_store_value_as_local (TransformData *td, MonoType *src)
+{
+	int size = mini_magic_type_size (NULL, src);
+	int local_offset = create_interp_local (td, mini_native_type_replace_type (src));
+
+	store_local_general (td, local_offset, src);
+
+	size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
+	ADD_CODE (td, MINT_LDLOC_VT);
+	ADD_CODE (td, local_offset);
+	WRITE32 (td, &size);
+
+	PUSH_VT (td, size);
+	PUSH_TYPE (td, STACK_TYPE_VT, NULL);
+}
+
 /* Return TRUE if call transformation is finished */
 static gboolean
 interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoMethodSignature *csignature, gboolean readonly, int *op)
@@ -901,7 +952,7 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoMeth
 		if (!strcmp (".ctor", tm)) {
 			MonoType *arg = csignature->params [0];
 			/* depending on SIZEOF_VOID_P and the type of the value passed to the .ctor we either have to CONV it, or do nothing */
-			int arg_size = type_size (arg);
+			int arg_size = mini_magic_type_size (NULL, arg);
 
 			if (arg_size > SIZEOF_VOID_P) { // 8 -> 4
 				switch (type_index) {
@@ -909,7 +960,7 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoMeth
 					ADD_CODE (td, MINT_CONV_I4_I8);
 					break;
 				case 2:
-					// ADD_CODE (td, MINT_CONV_R8_R4);
+					ADD_CODE (td, MINT_CONV_R4_R8);
 					break;
 				}
 			}
@@ -920,7 +971,7 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoMeth
 					ADD_CODE (td, MINT_CONV_I8_I4);
 					break;
 				case 2:
-					ADD_CODE (td, MINT_CONV_R4_R8);
+					ADD_CODE (td, MINT_CONV_R8_R4);
 					break;
 				}
 			}
@@ -946,28 +997,64 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoMeth
 			td->ip += 5;
 			return TRUE;
 		} else if (!strcmp ("op_Implicit", tm ) || !strcmp ("op_Explicit", tm)) {
-			int arg_size = type_size (csignature->params [0]);
-			if (arg_size > SIZEOF_VOID_P) { // 8 -> 4
+			MonoType *src = csignature->params [0];
+			MonoType *dst = csignature->ret;
+			int src_size = mini_magic_type_size (NULL, src);
+			int dst_size = mini_magic_type_size (NULL, dst);
+
+			gboolean store_value_as_local = FALSE;
+
+			switch (type_index) {
+			case 0: case 1:
+				if (!mini_magic_is_int_type (src) || !mini_magic_is_int_type (dst)) {
+					if (mini_magic_is_int_type (src))
+						store_value_as_local = TRUE;
+					else
+						return FALSE;
+				}
+				break;
+			case 2:
+				if (!mini_magic_is_float_type (src) || !mini_magic_is_float_type (dst)) {
+					if (mini_magic_is_float_type (src))
+						store_value_as_local = TRUE;
+					else
+						return FALSE;
+				}
+				break;
+			}
+
+			if (store_value_as_local) {
+				emit_store_value_as_local (td, src);
+
+				/* emit call to managed conversion method */
+				return FALSE;
+			}
+
+#if SIZEOF_VOID_P == 4
+			if (src_size > dst_size) { // 8 -> 4
 				switch (type_index) {
 				case 0: case 1:
 					ADD_CODE (td, MINT_CONV_I4_I8);
 					break;
 				case 2:
-					// ADD_CODE (td, MINT_CONV_R4_R8);
+					ADD_CODE (td, MINT_CONV_R4_R8);
 					break;
 				}
 			}
+#endif
 
-			if (arg_size < SIZEOF_VOID_P) { // 4 -> 8
+#if SIZEOF_VOID_P == 8
+			if (src_size < dst_size) { // 4 -> 8
 				switch (type_index) {
 				case 0: case 1:
 					ADD_CODE (td, MINT_CONV_I8_I4);
 					break;
 				case 2:
-					ADD_CODE (td, MINT_CONV_R4_R8);
+					ADD_CODE (td, MINT_CONV_R8_R4);
 					break;
 				}
 			}
+#endif
 
 			SET_TYPE (td->sp - 1, stack_type [mt], magic_class);
 			td->ip += 5;
@@ -992,13 +1079,26 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoMeth
 			SET_TYPE (td->sp - 1, stack_type [mt], magic_class);
 			td->ip += 5;
 			return TRUE;
+		} else if (!strcmp ("CompareTo", tm) || !strcmp ("Equals", tm)) {
+			MonoType *arg = csignature->params [0];
+
+			/* on 'System.n*::{CompareTo,Equals} (System.n*)' variant we need to push managed
+			 * pointer instead of value */
+			if (arg->type == MONO_TYPE_VALUETYPE)
+				emit_store_value_as_local (td, arg);
+
+			/* emit call to managed conversion method */
+			return FALSE;
 		} else if (!strcmp (".cctor", tm)) {
 			/* white list */
 			return FALSE;
 		} else if (!strcmp ("Parse", tm)) {
 			/* white list */
 			return FALSE;
-		} else if (!strcmp ("IsNaN", tm)) {
+		} else if (!strcmp ("ToString", tm)) {
+			/* white list */
+			return FALSE;
+		} else if (!strcmp ("IsNaN", tm) || !strcmp ("IsInfinity", tm) || !strcmp ("IsNegativeInfinity", tm) || !strcmp ("IsPositiveInfinity", tm)) {
 			g_assert (type_index == 2); // nfloat only
 			/* white list */
 			return FALSE;
@@ -1703,25 +1803,6 @@ get_basic_blocks (TransformData *td)
 	}
 }
 
-/*
- * These are additional locals that can be allocated as we transform the code.
- * They are allocated past the method locals so they are accessed in the same
- * way, with an offset relative to the frame->locals.
- */
-static int
-create_interp_local (TransformData *td, MonoType *type)
-{
-	int align, size;
-	int offset = td->total_locals_size;
-
-	size = mono_type_size (type, &align);
-	offset = ALIGN_TO (offset, align);
-
-	td->total_locals_size = offset + size;
-
-	return offset;
-}
-
 static void
 interp_save_debug_info (InterpMethod *rtm, MonoMethodHeader *header, TransformData *td, GArray *line_numbers)
 {
@@ -2372,7 +2453,7 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsig
 			ADD_CODE(td, MINT_LDC_R4);
 			WRITE32(td, &val);
 			td->ip += 5;
-			PUSH_SIMPLE_TYPE(td, STACK_TYPE_R8);
+			PUSH_SIMPLE_TYPE(td, STACK_TYPE_R4);
 			break;
 		}
 		case CEE_LDC_R8: {
@@ -2675,7 +2756,7 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsig
 		case CEE_LDIND_R4:
 			CHECK_STACK (td, 1);
 			SIMPLE_OP (td, MINT_LDIND_R4_CHECK);
-			SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R8);
+			SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R4);
 			BARRIER_IF_VOLATILE (td);
 			break;
 		case CEE_LDIND_R8:
@@ -2802,6 +2883,9 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsig
 		case CEE_CONV_U1:
 			CHECK_STACK (td, 1);
 			switch (td->sp [-1].type) {
+			case STACK_TYPE_R4:
+				ADD_CODE (td, MINT_CONV_U1_R4);
+				break;
 			case STACK_TYPE_R8:
 				ADD_CODE(td, MINT_CONV_U1_R8);
 				break;
@@ -2820,6 +2904,9 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsig
 		case CEE_CONV_I1:
 			CHECK_STACK (td, 1);
 			switch (td->sp [-1].type) {
+			case STACK_TYPE_R4:
+				ADD_CODE(td, MINT_CONV_I1_R4);
+				break;
 			case STACK_TYPE_R8:
 				ADD_CODE(td, MINT_CONV_I1_R8);
 				break;
@@ -2838,6 +2925,9 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsig
 		case CEE_CONV_U2:
 			CHECK_STACK (td, 1);
 			switch (td->sp [-1].type) {
+			case STACK_TYPE_R4:
+				ADD_CODE(td, MINT_CONV_U2_R4);
+				break;
 			case STACK_TYPE_R8:
 				ADD_CODE(td, MINT_CONV_U2_R8);
 				break;
@@ -2856,6 +2946,9 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsig
 		case CEE_CONV_I2:
 			CHECK_STACK (td, 1);
 			switch (td->sp [-1].type) {
+			case STACK_TYPE_R4:
+				ADD_CODE(td, MINT_CONV_I2_R4);
+				break;
 			case STACK_TYPE_R8:
 				ADD_CODE(td, MINT_CONV_I2_R8);
 				break;
@@ -2933,6 +3026,9 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsig
 		case CEE_CONV_U4:
 			CHECK_STACK (td, 1);
 			switch (td->sp [-1].type) {
+			case STACK_TYPE_R4:
+				ADD_CODE(td, MINT_CONV_U4_R4);
+				break;
 			case STACK_TYPE_R8:
 				ADD_CODE(td, MINT_CONV_U4_R8);
 				break;
@@ -2955,6 +3051,9 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsig
 		case CEE_CONV_I4:
 			CHECK_STACK (td, 1);
 			switch (td->sp [-1].type) {
+			case STACK_TYPE_R4:
+				ADD_CODE (td, MINT_CONV_I4_R4);
+				break;
 			case STACK_TYPE_R8:
 				ADD_CODE(td, MINT_CONV_I4_R8);
 				break;
@@ -2977,6 +3076,9 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsig
 		case CEE_CONV_I8:
 			CHECK_STACK (td, 1);
 			switch (td->sp [-1].type) {
+			case STACK_TYPE_R4:
+				ADD_CODE(td, MINT_CONV_I8_R4);
+				break;
 			case STACK_TYPE_R8:
 				ADD_CODE(td, MINT_CONV_I8_R8);
 				break;
@@ -3008,11 +3110,14 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsig
 			case STACK_TYPE_I4:
 				ADD_CODE(td, MINT_CONV_R4_I4);
 				break;
+			case STACK_TYPE_R4:
+				/* no-op */
+				break;
 			default:
 				g_assert_not_reached ();
 			}
 			++td->ip;
-			SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R8);
+			SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R4);
 			break;
 		case CEE_CONV_R8:
 			CHECK_STACK (td, 1);
@@ -3023,6 +3128,9 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsig
 			case STACK_TYPE_I8:
 				ADD_CODE(td, MINT_CONV_R8_I8);
 				break;
+			case STACK_TYPE_R4:
+				ADD_CODE (td, MINT_CONV_R8_R4);
+				break;
 			case STACK_TYPE_R8:
 				break;
 			default:
@@ -3039,6 +3147,9 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsig
 				break;
 			case STACK_TYPE_I8:
 				break;
+			case STACK_TYPE_R4:
+				ADD_CODE (td, MINT_CONV_U8_R4);
+				break;
 			case STACK_TYPE_R8:
 				ADD_CODE(td, MINT_CONV_U8_R8);
 				break;
@@ -3154,6 +3265,12 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsig
 
 			td->sp -= csignature->param_count;
 			if (mono_class_is_magic_int (klass) || mono_class_is_magic_float (klass)) {
+#if SIZEOF_VOID_P == 8
+				if (mono_class_is_magic_int (klass) && td->sp [0].type == STACK_TYPE_I4)
+					ADD_CODE (td, MINT_CONV_I8_I4);
+				else if (mono_class_is_magic_float (klass) && td->sp [0].type == STACK_TYPE_R4)
+					ADD_CODE (td, MINT_CONV_R8_R4);
+#endif
 				ADD_CODE (td, MINT_NEWOBJ_MAGIC);
 				ADD_CODE (td, get_data_item_index (td, mono_interp_get_imethod (domain, m, error)));
 				goto_if_nok (error, exit);
@@ -3656,6 +3773,8 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsig
 					size = mono_class_value_size (klass, NULL);
 					size = ALIGN_TO (size, MINT_VT_ALIGNMENT);
 					td->vt_sp -= size;
+				} else if (td->sp [-1].type == STACK_TYPE_R8 && m_class_get_byval_arg (klass)->type == MONO_TYPE_R4) {
+					ADD_CODE (td, MINT_CONV_R4_R8);
 				}
 				ADD_CODE(td, MINT_BOX);
 				ADD_CODE(td, get_data_item_index (td, klass));
@@ -3793,7 +3912,7 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsig
 			ENSURE_I4 (td, 1);
 			SIMPLE_OP (td, MINT_LDELEM_R4);
 			--td->sp;
-			SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R8);
+			SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R4);
 			break;
 		case CEE_LDELEM_R8:
 			CHECK_STACK (td, 2);
@@ -3855,7 +3974,7 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsig
 					ENSURE_I4 (td, 1);
 					SIMPLE_OP (td, MINT_LDELEM_R4);
 					--td->sp;
-					SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R8);
+					SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_R4);
 					break;
 				case MINT_TYPE_R8:
 					ENSURE_I4 (td, 1);
@@ -4123,6 +4242,9 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsig
 		case CEE_CONV_OVF_I4_UN:
 			CHECK_STACK (td, 1);
 			switch (td->sp [-1].type) {
+			case STACK_TYPE_R4:
+				ADD_CODE(td, MINT_CONV_OVF_I4_R4);
+				break;
 			case STACK_TYPE_R8:
 				ADD_CODE(td, MINT_CONV_OVF_I4_R8);
 				break;
@@ -4149,6 +4271,9 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsig
 		case CEE_CONV_OVF_U4_UN:
 			CHECK_STACK (td, 1);
 			switch (td->sp [-1].type) {
+			case STACK_TYPE_R4:
+				ADD_CODE(td, MINT_CONV_OVF_U4_R4);
+				break;
 			case STACK_TYPE_R8:
 				ADD_CODE(td, MINT_CONV_OVF_U4_R8);
 				break;
@@ -4171,6 +4296,9 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsig
 		case CEE_CONV_OVF_I8:
 			CHECK_STACK (td, 1);
 			switch (td->sp [-1].type) {
+			case STACK_TYPE_R4:
+				ADD_CODE(td, MINT_CONV_OVF_I8_R4);
+				break;
 			case STACK_TYPE_R8:
 				ADD_CODE(td, MINT_CONV_OVF_I8_R8);
 				break;
@@ -4191,6 +4319,9 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsig
 		case CEE_CONV_OVF_U8:
 			CHECK_STACK (td, 1);
 			switch (td->sp [-1].type) {
+			case STACK_TYPE_R4:
+				ADD_CODE(td, MINT_CONV_OVF_U8_R4);
+				break;
 			case STACK_TYPE_R8:
 				ADD_CODE(td, MINT_CONV_OVF_U8_R8);
 				break;
@@ -4515,10 +4646,15 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsig
 				break;
 			case CEE_CEQ:
 				CHECK_STACK(td, 2);
-				if (td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_MP)
+				if (td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_MP) {
 					ADD_CODE(td, MINT_CEQ_I4 + STACK_TYPE_I - STACK_TYPE_I4);
-				else
+				} else {
+					if (td->sp [-1].type == STACK_TYPE_R4 && td->sp [-2].type == STACK_TYPE_R8)
+						ADD_CODE (td, MINT_CONV_R8_R4);
+					if (td->sp [-1].type == STACK_TYPE_R8 && td->sp [-2].type == STACK_TYPE_R4)
+						ADD_CODE (td, MINT_CONV_R8_R4_SP);
 					ADD_CODE(td, MINT_CEQ_I4 + td->sp [-1].type - STACK_TYPE_I4);
+				}
 				--td->sp;
 				SET_SIMPLE_TYPE(td->sp - 1, STACK_TYPE_I4);
 				++td->ip;
@@ -4789,16 +4925,11 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsig
 	}
 
 	if (td->verbose_level) {
-		const guint16 *p = td->new_code;
 		g_print ("Runtime method: %s %p, VT stack size: %d\n", mono_method_full_name (method, TRUE), rtm, td->max_vt_sp);
 		g_print ("Calculated stack size: %d, stated size: %d\n", td->max_stack_height, header->max_stack);
-		while (p < td->new_ip) {
-			char *ins = mono_interp_dis_mintop (td->new_code, p);
-			g_print ("%s\n", ins);
-			g_free (ins);
-			p = mono_interp_dis_mintop_len (p);
-		}
+		dump_mint_code (td);
 	}
+
 	/* Check if we use excessive stack space */
 	if (td->max_stack_height > header->max_stack * 3)
 		g_warning ("Excessive stack space usage for method %s, %d/%d", method->name, td->max_stack_height, header->max_stack);

+ 13 - 16
mono/mini/mini-native-types.c

@@ -133,14 +133,14 @@ static const MagicTypeInfo type_info[] = {
 };
 
 
-static inline gboolean
-type_size (MonoCompile *cfg, MonoType *type)
+gsize
+mini_magic_type_size (MonoCompile *cfg, MonoType *type)
 {
 	if (type->type == MONO_TYPE_I4 || type->type == MONO_TYPE_U4)
 		return 4;
 	else if (type->type == MONO_TYPE_I8 || type->type == MONO_TYPE_U8)
 		return 8;
-	else if (type->type == MONO_TYPE_R4 && !type->byref && cfg->r4fp)
+	else if (type->type == MONO_TYPE_R4 && !type->byref && (!cfg || cfg->r4fp))
 		return 4;
 	else if (type->type == MONO_TYPE_R8 && !type->byref)
 		return 8;
@@ -149,9 +149,6 @@ type_size (MonoCompile *cfg, MonoType *type)
 
 #ifndef DISABLE_JIT
 
-static gboolean is_int_type (MonoType *t);
-static gboolean is_float_type (MonoType *t);
-
 static MonoInst*
 emit_narrow (MonoCompile *cfg, const MagicTypeInfo *info, int sreg)
 {
@@ -202,16 +199,16 @@ emit_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi
 	}
 
 	if (!strcmp ("op_Implicit", name) || !strcmp ("op_Explicit", name)) {
-		int source_size = type_size (cfg, fsig->params [0]);
-		int dest_size = type_size (cfg, fsig->ret);
+		int source_size = mini_magic_type_size (cfg, fsig->params [0]);
+		int dest_size = mini_magic_type_size (cfg, fsig->ret);
 
 		switch (info->big_stack_type) {
 		case STACK_I8:
-			if (!is_int_type (fsig->params [0]) || !is_int_type (fsig->ret))
+			if (!mini_magic_is_int_type (fsig->params [0]) || !mini_magic_is_int_type (fsig->ret))
 				return NULL;
 			break;
 		case STACK_R8:
-			if (!is_float_type (fsig->params [0]) || !is_float_type (fsig->ret))
+			if (!mini_magic_is_float_type (fsig->params [0]) || !mini_magic_is_float_type (fsig->ret))
 				return NULL;
 			break;
 		default:
@@ -233,7 +230,7 @@ emit_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi
 	if (!strcmp (".ctor", name)) {
 		gboolean is_ldaddr = args [0]->opcode == OP_LDADDR;
 		int arg0 = args [1]->dreg;
-		int arg_size = type_size (cfg, fsig->params [0]);
+		int arg_size = mini_magic_type_size (cfg, fsig->params [0]);
 
 		if (arg_size > TARGET_SIZEOF_VOID_P) //8 -> 4
 			arg0 = emit_narrow (cfg, info, arg0)->dreg;
@@ -456,16 +453,16 @@ mono_class_is_magic_float (MonoClass *klass)
 	return FALSE;
 }
 
-static gboolean
-is_int_type (MonoType *t)
+gboolean
+mini_magic_is_int_type (MonoType *t)
 {
-	if (t->type != MONO_TYPE_I4 && t->type != MONO_TYPE_I8 && t->type != MONO_TYPE_U4 && t->type != MONO_TYPE_U8 && !mono_class_is_magic_int (mono_class_from_mono_type (t)))
+	if (t->type != MONO_TYPE_I && t->type != MONO_TYPE_I4 && t->type != MONO_TYPE_I8 && t->type != MONO_TYPE_U4 && t->type != MONO_TYPE_U8 && !mono_class_is_magic_int (mono_class_from_mono_type (t)))
 		return FALSE;
 	return TRUE;
 }
 
-static gboolean
-is_float_type (MonoType *t)
+gboolean
+mini_magic_is_float_type (MonoType *t)
 {
 	if (t->type != MONO_TYPE_R4 && t->type != MONO_TYPE_R8 && !mono_class_is_magic_float (mono_class_from_mono_type (t)))
 		return FALSE;

+ 3 - 0
mono/mini/mini.h

@@ -2755,6 +2755,9 @@ void        mono_simd_intrinsics_init (void);
 gboolean    mono_class_is_magic_int (MonoClass *klass);
 gboolean    mono_class_is_magic_float (MonoClass *klass);
 MonoInst*   mono_emit_native_types_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args);
+gsize       mini_magic_type_size (MonoCompile *cfg, MonoType *type);
+gboolean    mini_magic_is_int_type (MonoType *t);
+gboolean    mini_magic_is_float_type (MonoType *t);
 MonoType*   mini_native_type_replace_type (MonoType *type) MONO_LLVM_INTERNAL;
 
 MonoMethod*