// mono_icall_sig_ptr_ptr
// mono_icall_sig_uint16_double
// mono_icall_sig_uint32_double
+// mono_icall_sig_uint32_float
// mono_icall_sig_uint8_double
// mono_icall_sig_ulong_double
// mono_icall_sig_ulong_float
ICALL_SIG (2, (ptr, ptr)) \
ICALL_SIG (2, (uint16, double)) \
ICALL_SIG (2, (uint32, double)) \
+ICALL_SIG (2, (uint32, float)) \
ICALL_SIG (2, (uint8, double)) \
ICALL_SIG (2, (ulong, double)) \
ICALL_SIG (2, (ulong, float)) \
MONO_JIT_ICALL (__emul_rconv_to_ovf_i8) \
MONO_JIT_ICALL (__emul_rconv_to_ovf_u8) \
MONO_JIT_ICALL (__emul_rconv_to_ovf_u8_un) \
+MONO_JIT_ICALL (__emul_rconv_to_u4) \
MONO_JIT_ICALL (__emul_rconv_to_u8) \
MONO_JIT_ICALL (__emul_rrem) \
MONO_JIT_ICALL (cominterop_get_ccw) \
#include "mini.h"
/* Version number of the AOT file format */
-#define MONO_AOT_FILE_VERSION 168
+#define MONO_AOT_FILE_VERSION 169
#define MONO_AOT_TRAMP_PAGE_SIZE 16384
sbyte sb = (sbyte)a;
if (sb != 2)
return 6;
- /* MS.NET special cases these */
+ return 0;
+ }
+
+ public static int test_0_fconv_u8 () {
double d = Double.NaN;
- ui = (uint)d;
+ ulong ui;
+ ui = (ulong)d;
if (ui != 0)
- return 7;
+ return 1;
d = Double.PositiveInfinity;
+ ui = (ulong)d;
+ /* x64: 0, ARM64: ulong.MaxValue (verified against CoreCLR) */
+ if (ui != 0 && ui != ulong.MaxValue)
+ return 2;
+ d = Double.NegativeInfinity;
+ ui = (ulong)d;
+ /* x64: long.MaxValue + 1 (inconsistent with conversion to u4 but matches CLR) */
+ if (ui != 0 && ui != (ulong)long.MaxValue + 1)
+ return 3;
+ return 0;
+ }
+
+ public static int test_0_fconv_u4 () {
+ double d = Double.NaN;
+ uint ui;
ui = (uint)d;
if (ui != 0)
- return 8;
+ return 1;
+ d = Double.PositiveInfinity;
+ ui = (uint)d;
+ /* x64: 0, ARM64: uint.MaxValue (verified against CoreCLR) */
+ if (ui != 0 && ui != uint.MaxValue)
+ return 2;
d = Double.NegativeInfinity;
ui = (uint)d;
if (ui != 0)
- return 9;
- /* FIXME: This fails with llvm and with gcc -O2 on osx/linux */
- /*
- d = Double.MaxValue;
- i = (int)d;
- if (i != -2147483648)
- return 10;
- */
+ return 3;
+ return 0;
+ }
+
+ public static int test_0_rconv_u8 () {
+ float d = float.NaN;
+ ulong ui;
+ ui = (ulong)d;
+ if (ui != 0)
+ return 1;
+ d = float.PositiveInfinity;
+ ui = (ulong)d;
+ /* x64: 0, ARM64: ulong.MaxValue (verified against CoreCLR) */
+ if (ui != 0 && ui != ulong.MaxValue)
+ return 2;
+ d = float.NegativeInfinity;
+ ui = (ulong)d;
+ /* x64: long.MaxValue + 1 (inconsistent with conversion to u4 but matches CLR) */
+ if (ui != 0 && ui != (ulong)long.MaxValue + 1)
+ return 3;
+ return 0;
+ }
+ public static int test_0_rconv_u4 () {
+ float d = float.NaN;
+ uint ui;
+ ui = (uint)d;
+ if (ui != 0)
+ return 1;
+ d = float.PositiveInfinity;
+ ui = (uint)d;
+ /* x64: 0, ARM64: uint.MaxValue (verified against CoreCLR) */
+ if (ui != 0 && ui != uint.MaxValue)
+ return 2;
+ d = float.NegativeInfinity;
+ ui = (uint)d;
+ if (ui != 0)
+ return 3;
return 0;
}
++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;
+#ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
+ sp [-1].data.i = mono_rconv_u4 (sp [-1].data.f_r4);
+#else
+ sp [-1].data.i = (guint32) sp [-1].data.f_r4;
+#endif
++ip;
MINT_IN_BREAK;
MINT_IN_CASE(MINT_CONV_U4_R8)
- /* needed on arm64 */
- if (mono_isinf (sp [-1].data.f))
- sp [-1].data.i = 0;
- /* needed by wasm */
- else if (isnan (sp [-1].data.f))
- sp [-1].data.i = 0;
- else
- sp [-1].data.i = (guint32)sp [-1].data.f;
+#ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
+ sp [-1].data.i = mono_fconv_u4_2 (sp [-1].data.f);
+#else
+ sp [-1].data.i = (guint32) sp [-1].data.f;
+#endif
++ip;
MINT_IN_BREAK;
MINT_IN_CASE(MINT_CONV_I8_I4)
++ip;
MINT_IN_BREAK;
MINT_IN_CASE(MINT_CONV_U8_R4)
+#ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
+ sp [-1].data.l = mono_rconv_u8 (sp [-1].data.f_r4);
+#else
sp [-1].data.l = (guint64) sp [-1].data.f_r4;
+#endif
++ip;
MINT_IN_BREAK;
MINT_IN_CASE(MINT_CONV_U8_R8)
+#ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
+ sp [-1].data.l = mono_fconv_u8_2 (sp [-1].data.f);
+#else
sp [-1].data.l = (guint64)sp [-1].data.f;
+#endif
++ip;
MINT_IN_BREAK;
MINT_IN_CASE(MINT_CPOBJ) {
guint64
mono_fconv_u8 (double v)
{
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
+ const double two63 = 2147483648.0 * 4294967296.0;
+ if (v < two63) {
+ return (gint64)v;
+ } else {
+ return (gint64)(v - two63) + ((guint64)1 << 63);
+ }
+#else
+ if (mono_isinf (v) || mono_isnan (v))
+ return 0;
return (guint64)v;
+#endif
}
+#ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
guint64
mono_fconv_u8_2 (double v)
{
guint64
mono_rconv_u8 (float v)
{
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
+ const float two63 = 2147483648.0 * 4294967296.0;
+ if (v < two63) {
+ return (gint64)v;
+ } else {
+ return (gint64)(v - two63) + ((guint64)1 << 63);
+ }
+#else
+ if (mono_isinf (v) || mono_isnan (v))
+ return 0;
return (guint64)v;
+#endif
}
+#endif
#ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
gint64
return (guint32)v;
}
+#ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
guint32
mono_fconv_u4_2 (double v)
{
return mono_fconv_u4 (v);
}
+gint32
+mono_rconv_u4 (float v)
+{
+ if (mono_isinf (v) || mono_isnan (v))
+ return 0;
+ return (gint32)v;
+}
+#endif
+
gint64
mono_fconv_ovf_i8 (double v)
{
G_EXTERN_C guint32 mono_fconv_u4 (double v);
G_EXTERN_C guint32 mono_fconv_u4_2 (double v);
+G_EXTERN_C gint32 mono_rconv_u4 (float v);
+
G_EXTERN_C gint64 mono_fconv_ovf_i8 (double v);
G_EXTERN_C guint64 mono_fconv_ovf_u8 (double v);
static unsigned char*
emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
{
- if (size == 8)
+ // Use 8 as register size to get Nan/Inf conversion to uint result truncated to 0
+ if (size == 8 || (!is_signed && size == 4))
amd64_sse_cvttsd2si_reg_reg (code, dreg, sreg);
else
amd64_sse_cvttsd2si_reg_reg_size (code, dreg, sreg, 4);
amd64_sse_cvtss2si_reg_reg_size (code, ins->dreg, ins->sreg1, 4);
break;
case OP_RCONV_TO_U4:
- amd64_sse_cvtss2si_reg_reg_size (code, ins->dreg, ins->sreg1, 4);
+ // Use 8 as register size to get Nan/Inf conversion result truncated to 0
+ amd64_sse_cvtss2si_reg_reg (code, ins->dreg, ins->sreg1);
break;
case OP_RCONV_TO_I8:
case OP_RCONV_TO_I:
#define MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
#define MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
-#define MONO_ARCH_EMULATE_CONV_R8_UN 1
+#define MONO_ARCH_EMULATE_CONV_R8_UN 1
+#define MONO_ARCH_EMULATE_FCONV_TO_U8 1
+// The Windows x64 FullAOT+LLVM fails to pass the basic-float tests without this.
+#ifdef TARGET_WIN32
+#define MONO_ARCH_EMULATE_FCONV_TO_U4 1
+#endif
#define MONO_ARCH_EMULATE_FREM 1
#define MONO_ARCH_HAVE_IS_INT_OVERFLOW 1
#define MONO_ARCH_HAVE_INVALIDATE_METHOD 1
} MonoCompileArch;
#define MONO_ARCH_EMULATE_FCONV_TO_I8 1
+#define MONO_ARCH_EMULATE_FCONV_TO_U8 1
#define MONO_ARCH_EMULATE_LCONV_TO_R8 1
#define MONO_ARCH_EMULATE_LCONV_TO_R4 1
#define MONO_ARCH_EMULATE_LCONV_TO_R8_UN 1
case OP_RCONV_TO_I2:
case OP_RCONV_TO_U2:
return LLVMInt16Type ();
+ case OP_FCONV_TO_U4:
case OP_RCONV_TO_U4:
return LLVMInt32Type ();
+ case OP_FCONV_TO_U8:
+ case OP_RCONV_TO_U8:
+ return LLVMInt64Type ();
case OP_FCONV_TO_I:
case OP_FCONV_TO_U:
return TARGET_SIZEOF_VOID_P == 8 ? LLVMInt64Type () : LLVMInt32Type ();
case OP_RCONV_TO_U2:
values [ins->dreg] = LLVMBuildZExt (builder, LLVMBuildFPToUI (builder, lhs, LLVMInt16Type (), dname), LLVMInt32Type (), "");
break;
+ case OP_FCONV_TO_U4:
case OP_RCONV_TO_U4:
values [ins->dreg] = LLVMBuildFPToUI (builder, lhs, LLVMInt32Type (), dname);
break;
+ case OP_FCONV_TO_U8:
+ case OP_RCONV_TO_U8:
+ values [ins->dreg] = LLVMBuildFPToUI (builder, lhs, LLVMInt64Type (), dname);
+ break;
case OP_FCONV_TO_I8:
case OP_RCONV_TO_I8:
values [ins->dreg] = LLVMBuildFPToSI (builder, lhs, LLVMInt64Type (), dname);
#define MONO_ARCH_EMULATE_FREM 1
#endif
+#define MONO_ARCH_EMULATE_FCONV_TO_U8 1
+
/*
* mips backend misses some instructions that enable emitting of optimal
* code on other targets and, additionally, the register allocator gets
#define MONO_ARCH_EMULATE_LCONV_TO_R4 1
#endif
+#define MONO_ARCH_EMULATE_FCONV_TO_U8 1
#define MONO_ARCH_EMULATE_LCONV_TO_R8_UN 1
#define MONO_ARCH_EMULATE_FREM 1
#define MONO_ARCH_GC_MAPS_SUPPORTED 1
#endif
#define MONO_ARCH_EMULATE_CONV_R8_UN (1)
+#define MONO_ARCH_EMULATE_FCONV_TO_U8 (1)
+#define MONO_ARCH_EMULATE_FCONV_TO_U4 (1)
#define MONO_ARCH_EMULATE_FCONV_TO_I8 (1)
#define MONO_ARCH_EMULATE_LCONV_TO_R8 (1)
#define MONO_ARCH_EMULATE_LCONV_TO_R4 (1)
register_opcode_emulation (OP_FDIV, __emul_fdiv, mono_icall_sig_double_double_double, mono_fdiv, FALSE);
#endif
+#ifdef MONO_ARCH_EMULATE_FCONV_TO_U8
register_opcode_emulation (OP_FCONV_TO_U8, __emul_fconv_to_u8, mono_icall_sig_ulong_double, mono_fconv_u8_2, FALSE);
register_opcode_emulation (OP_RCONV_TO_U8, __emul_rconv_to_u8, mono_icall_sig_ulong_float, mono_rconv_u8, FALSE);
+#endif
+#ifdef MONO_ARCH_EMULATE_FCONV_TO_U4
register_opcode_emulation (OP_FCONV_TO_U4, __emul_fconv_to_u4, mono_icall_sig_uint32_double, mono_fconv_u4_2, FALSE);
+ register_opcode_emulation (OP_RCONV_TO_U4, __emul_rconv_to_u4, mono_icall_sig_uint32_float, mono_rconv_u4, FALSE);
+#endif
register_opcode_emulation (OP_FCONV_TO_OVF_I8, __emul_fconv_to_ovf_i8, mono_icall_sig_long_double, mono_fconv_ovf_i8, FALSE);
register_opcode_emulation (OP_FCONV_TO_OVF_U8, __emul_fconv_to_ovf_u8, mono_icall_sig_ulong_double, mono_fconv_ovf_u8, FALSE);
register_opcode_emulation (OP_FCONV_TO_OVF_U8_UN, __emul_fconv_to_ovf_u8_un, mono_icall_sig_ulong_double, mono_fconv_ovf_u8_un, FALSE);
/*#define MONO_ARCH_SIGSEGV_ON_ALTSTACK*/
#endif
+#define MONO_ARCH_EMULATE_FCONV_TO_U8 1
#define MONO_ARCH_EMULATE_FCONV_TO_I8 1
#define MONO_ARCH_EMULATE_LCONV_TO_R8 1
#define MONO_ARCH_EMULATE_LCONV_TO_R4 1
#define MONO_ARCH_NEED_DIV_CHECK 1
#define MONO_ARCH_EMULATE_FREM 1
+#define MONO_ARCH_EMULATE_FCONV_TO_U8 1
+#define MONO_ARCH_EMULATE_FCONV_TO_U4 1
#define MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS 1
#define MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS 1
#define MONO_ARCH_FLOAT32_SUPPORTED 1
/* Enables OP_LSHL, OP_LSHL_IMM, OP_LSHR, OP_LSHR_IMM, OP_LSHR_UN, OP_LSHR_UN_IMM */
#define MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
+#define MONO_ARCH_EMULATE_FCONV_TO_U8 1
+#define MONO_ARCH_EMULATE_FCONV_TO_U4 1
+
#define MONO_ARCH_NEED_DIV_CHECK 1
#define MONO_ARCH_HAVE_IS_INT_OVERFLOW 1
#define MONO_ARCH_HAVE_INVALIDATE_METHOD 1
-nomethod System.Linq.Expressions.Tests.ArrayIndexTests.NonZeroBasedOneDimensionalArrayIndex
-nomethod System.Linq.Expressions.Tests.ArrayIndexTests.NonZeroBasedOneDimensionalArrayIndexMethod
-# Expected Float to uint to be 2147483648 but got 0... https://github.com/mono/mono/issues/14931
--nomethod System.Linq.Expressions.Tests.ConvertTests.ConvertFloatToUIntTest
--nomethod System.Linq.Expressions.Tests.ConvertTests.ConvertNullableFloatToUIntTest
--nomethod System.Linq.Expressions.Tests.ConvertTests.ConvertNullableFloatToNullableUIntTest
--nomethod System.Linq.Expressions.Tests.ConvertTests.ConvertFloatToNullableUIntTest
--noclass System.Linq.Expressions.Tests.LambdaTests
--noclass System.Linq.Expressions.Tests.LambdaDivideNullableTests
--nomethod System.Linq.Expressions.Tests.BinaryCoalesceTests.VerifyIL_NullableIntCoalesceToNullableInt
-
# OOM Exception. Weird
# https://github.com/mono/mono/issues/14933
-nomethod System.Linq.Expressions.Tests.ArrayBoundsTests.SingleNegativeBoundErrorMessage