Change the way we do soft float to a fallback mechanism.
authorAlex Rønne Petersen <alexrp@xamarin.com>
Tue, 9 Jul 2013 16:56:38 +0000 (18:56 +0200)
committerAlex Rønne Petersen <alexrp@xamarin.com>
Tue, 9 Jul 2013 17:27:57 +0000 (19:27 +0200)
MONO_ARCH_SOFT_FLOAT previously meant that a back end was using
soft float unconditionally. It's now MONO_ARCH_SOFT_FLOAT_FALLBACK
and actually indicates whether the back end has a soft float
fallback compiled in - not necessarily that it's used.

A new port function has been added:

    gboolean mono_arch_is_soft_float (void) MONO_INTERNAL;

This function is what actually tells Mini whether the back end is
going to use soft float. If MONO_ARCH_SOFT_FLOAT_FALLBACK is not
defined, it must return FALSE. Otherwise, it should return TRUE or
FALSE depending on whether the back end determines that the hardware
supports floating point. Once mono_arch_init () has been called,
the value returned from this function must be constant for the rest
of the VM's lifetime.

For example, on ARM, we now try to detect VFP via /proc/self/auxv
or /proc/cpuinfo and, if found, return FALSE from the function. This
only applies to Linux and Android as iOS always has VFP.

It's important to note that if the runtime is built with the 'softfp'
or 'hard' ABIs, the soft float fallback is not compiled in, as the
runtime is assumed to only be executed on VFP-capable systems.

Finally, the ARM feature detection code has been moved from the
mono_arch_cpu_optimizations () function to mono_arch_init () so that
FPU detection/initialization is done in one place.

16 files changed:
mono/mini/decompose.c
mono/mini/ir-emit.h
mono/mini/jit-icalls.c
mono/mini/method-to-ir.c
mono/mini/mini-amd64.c
mono/mini/mini-arm.c
mono/mini/mini-arm.h
mono/mini/mini-ia64.c
mono/mini/mini-llvm.c
mono/mini/mini-mips.c
mono/mini/mini-ppc.c
mono/mini/mini-s390x.c
mono/mini/mini-sparc.c
mono/mini/mini-x86.c
mono/mini/mini.c
mono/mini/mini.h

index c15502818fbd048bd473e1c25b3f31d497bb8688..2beeb9e59d57475fa500935d05262777fd834b91 100644 (file)
@@ -1483,7 +1483,7 @@ typedef union {
        double vald;
 } DVal;
 
-#ifdef MONO_ARCH_SOFT_FLOAT
+#ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
 
 /**
  * mono_decompose_soft_float:
index b90c5a536a9cd0d2a38b8e590c81233b23ce8a8e..75f582a3bf59846850130072c988124006423111 100644 (file)
@@ -44,13 +44,13 @@ alloc_lreg (MonoCompile *cfg)
 static inline guint32
 alloc_freg (MonoCompile *cfg)
 {
-#ifdef MONO_ARCH_SOFT_FLOAT
-       /* Allocate an lvreg so float ops can be decomposed into long ops */
-       return alloc_lreg (cfg);
-#else
-       /* Allocate these from the same pool as the int regs */
-       return cfg->next_vreg ++;
-#endif
+       if (mono_arch_is_soft_float ()) {
+               /* Allocate an lvreg so float ops can be decomposed into long ops */
+               return alloc_lreg (cfg);
+       } else {
+               /* Allocate these from the same pool as the int regs */
+               return cfg->next_vreg ++;
+       }
 }
 
 static inline guint32
@@ -314,11 +314,7 @@ alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
         if ((dest)->opcode == OP_VMOVE) (dest)->klass = mono_class_from_mono_type ((vartype)); \
        } while (0)
 
-#ifdef MONO_ARCH_SOFT_FLOAT
-#define DECOMPOSE_INTO_REGPAIR(stack_type) ((stack_type) == STACK_I8 || (stack_type) == STACK_R8)
-#else
-#define DECOMPOSE_INTO_REGPAIR(stack_type) ((stack_type) == STACK_I8)
-#endif
+#define DECOMPOSE_INTO_REGPAIR(stack_type) (mono_arch_is_soft_float () ? ((stack_type) == STACK_I8 || (stack_type) == STACK_R8) : ((stack_type) == STACK_I8))
 
 static inline void
 handle_gsharedvt_ldaddr (MonoCompile *cfg)
@@ -468,7 +464,7 @@ handle_gsharedvt_ldaddr (MonoCompile *cfg)
 
 #define EMIT_NEW_VARLOADA(cfg,dest,var,vartype) do { NEW_VARLOADA ((cfg), (dest), (var), (vartype)); MONO_ADD_INS ((cfg)->cbb, (dest)); } while (0)
 
-#ifdef MONO_ARCH_SOFT_FLOAT
+#ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
 
 /*
  * Since the IL stack (and our vregs) contain double values, we have to do a conversion
@@ -476,33 +472,61 @@ handle_gsharedvt_ldaddr (MonoCompile *cfg)
  */
 
 #define EMIT_NEW_VARLOAD_SFLOAT(cfg,dest,var,vartype) do { \
-               if (COMPILE_SOFT_FLOAT ((cfg)) && !(vartype)->byref && (vartype)->type == MONO_TYPE_R4) { \
-             MonoInst *iargs [1]; \
-             EMIT_NEW_VARLOADA (cfg, iargs [0], (var), (vartype)); \
-             (dest) = mono_emit_jit_icall (cfg, mono_fload_r4, iargs); \
-        } else { \
-             EMIT_NEW_VARLOAD ((cfg), (dest), (var), (vartype)); \
-        } \
-    } while (0)
+               if (!COMPILE_LLVM ((cfg)) && !(vartype)->byref && (vartype)->type == MONO_TYPE_R4) { \
+                       MonoInst *iargs [1]; \
+                       EMIT_NEW_VARLOADA (cfg, iargs [0], (var), (vartype)); \
+                       (dest) = mono_emit_jit_icall (cfg, mono_fload_r4, iargs); \
+               } else { \
+                       EMIT_NEW_VARLOAD ((cfg), (dest), (var), (vartype)); \
+               } \
+       } while (0)
 
 #define EMIT_NEW_VARSTORE_SFLOAT(cfg,dest,var,vartype,inst) do {       \
                if (COMPILE_SOFT_FLOAT ((cfg)) && !(vartype)->byref && (vartype)->type == MONO_TYPE_R4) { \
-             MonoInst *iargs [2]; \
-             iargs [0] = (inst); \
-             EMIT_NEW_VARLOADA (cfg, iargs [1], (var), (vartype)); \
-             mono_emit_jit_icall (cfg, mono_fstore_r4, iargs); \
-        } else { \
-             EMIT_NEW_VARSTORE ((cfg), (dest), (var), (vartype), (inst)); \
-        } \
-    } while (0)
+                       MonoInst *iargs [2]; \
+                       iargs [0] = (inst); \
+                       EMIT_NEW_VARLOADA (cfg, iargs [1], (var), (vartype)); \
+                       mono_emit_jit_icall (cfg, mono_fstore_r4, iargs); \
+               } else { \
+                       EMIT_NEW_VARSTORE ((cfg), (dest), (var), (vartype), (inst)); \
+               } \
+       } while (0)
 
-#define EMIT_NEW_ARGLOAD(cfg,dest,num) EMIT_NEW_VARLOAD_SFLOAT ((cfg), (dest), cfg->args [(num)], cfg->arg_types [(num)])
+#define EMIT_NEW_ARGLOAD(cfg,dest,num) do {    \
+               if (mono_arch_is_soft_float ()) {       \
+                       EMIT_NEW_VARLOAD_SFLOAT ((cfg), (dest), cfg->args [(num)], cfg->arg_types [(num)]);     \
+               } else {        \
+                       NEW_ARGLOAD ((cfg), (dest), (num));     \
+                       MONO_ADD_INS ((cfg)->cbb, (dest));      \
+               }       \
+       } while (0)
 
-#define EMIT_NEW_LOCLOAD(cfg,dest,num) EMIT_NEW_VARLOAD_SFLOAT ((cfg), (dest), cfg->locals [(num)], header->locals [(num)])
+#define EMIT_NEW_LOCLOAD(cfg,dest,num) do {    \
+               if (mono_arch_is_soft_float ()) {       \
+                       EMIT_NEW_VARLOAD_SFLOAT ((cfg), (dest), cfg->locals [(num)], header->locals [(num)]);   \
+               } else {        \
+                       NEW_LOCLOAD ((cfg), (dest), (num));     \
+                       MONO_ADD_INS ((cfg)->cbb, (dest));      \
+               }       \
+       } while (0)
 
-#define EMIT_NEW_LOCSTORE(cfg,dest,num,inst) EMIT_NEW_VARSTORE_SFLOAT ((cfg), (dest), (cfg)->locals [(num)], (cfg)->locals [(num)]->inst_vtype, (inst))
+#define EMIT_NEW_LOCSTORE(cfg,dest,num,inst) do {      \
+               if (mono_arch_is_soft_float ()) {       \
+                       EMIT_NEW_VARSTORE_SFLOAT ((cfg), (dest), (cfg)->locals [(num)], (cfg)->locals [(num)]->inst_vtype, (inst));     \
+               } else {        \
+                       NEW_LOCSTORE ((cfg), (dest), (num), (inst));    \
+                       MONO_ADD_INS ((cfg)->cbb, (dest));      \
+               }       \
+       } while (0)
 
-#define EMIT_NEW_ARGSTORE(cfg,dest,num,inst) EMIT_NEW_VARSTORE_SFLOAT ((cfg), (dest), cfg->args [(num)], cfg->arg_types [(num)], (inst))
+#define EMIT_NEW_ARGSTORE(cfg,dest,num,inst) do {      \
+               if (mono_arch_is_soft_float ()) {       \
+                       EMIT_NEW_VARSTORE_SFLOAT ((cfg), (dest), cfg->args [(num)], cfg->arg_types [(num)], (inst));    \
+               } else {        \
+                       NEW_ARGSTORE ((cfg), (dest), (num), (inst));    \
+                       MONO_ADD_INS ((cfg)->cbb, (dest));      \
+               }       \
+       } while (0)
 
 #else
 
index 78db84f7fd30d03c011f17c5c2a892dd2a1c044b..8822b8026e78b85c0b2d83210734b35bd216e0e9 100644 (file)
@@ -429,7 +429,7 @@ mono_imul_ovf_un (guint32 a, guint32 b)
 }
 #endif
 
-#if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
+#if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
 double
 mono_fdiv (double a, double b)
 {
@@ -439,7 +439,7 @@ mono_fdiv (double a, double b)
 }
 #endif
 
-#ifdef MONO_ARCH_SOFT_FLOAT
+#ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
 
 double
 mono_fsub (double a, double b)
@@ -915,7 +915,7 @@ mono_fconv_ovf_u8 (double v)
  * 
  * To work around this issue we test for value boundaries instead. 
  */
-#if defined(__arm__) && MONO_ARCH_SOFT_FLOAT 
+#if defined(__arm__) && defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
        if (isnan (v) || !(v >= -0.5 && v <= ULLONG_MAX+0.5)) {
                mono_raise_exception (mono_get_exception_overflow ());
        }
index 461a5fe54c5353e553cc85d28365f5df509dee48..d65d117e7ebb3aa9c999c5af3e2eff550d446769 100644 (file)
@@ -2337,7 +2337,7 @@ mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig,
                                         MonoInst **args, int calli, int virtual, int tail, int rgctx, int unbox_trampoline)
 {
        MonoCallInst *call;
-#ifdef MONO_ARCH_SOFT_FLOAT
+#ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
        int i;
 #endif
 
@@ -2384,7 +2384,7 @@ mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig,
        } else if (!MONO_TYPE_IS_VOID (sig->ret))
                call->inst.dreg = alloc_dreg (cfg, call->inst.type);
 
-#ifdef MONO_ARCH_SOFT_FLOAT
+#ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
        if (COMPILE_SOFT_FLOAT (cfg)) {
                /* 
                 * If the call has a float argument, we would need to do an r8->r4 conversion using 
@@ -4399,7 +4399,7 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
 {
        MonoMethodHeaderSummary header;
        MonoVTable *vtable;
-#ifdef MONO_ARCH_SOFT_FLOAT
+#ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
        MonoMethodSignature *sig = mono_method_signature (method);
        int i;
 #endif
@@ -4490,13 +4490,15 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
        if (mono_security_method_has_declsec (method))
                return FALSE;
 
-#ifdef MONO_ARCH_SOFT_FLOAT
-       /* FIXME: */
-       if (sig->ret && sig->ret->type == MONO_TYPE_R4)
-               return FALSE;
-       for (i = 0; i < sig->param_count; ++i)
-               if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
+#ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
+       if (mono_arch_is_soft_float ()) {
+               /* FIXME: */
+               if (sig->ret && sig->ret->type == MONO_TYPE_R4)
                        return FALSE;
+               for (i = 0; i < sig->param_count; ++i)
+                       if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
+                               return FALSE;
+       }
 #endif
 
        return TRUE;
@@ -8297,7 +8299,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                        ins->klass = mono_class_from_mono_type (ret_type);
                                                }
                                        } else {
-#ifdef MONO_ARCH_SOFT_FLOAT
+#ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
                                                if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
                                                        MonoInst *iargs [1];
                                                        MonoInst *conv;
@@ -12408,10 +12410,13 @@ mono_handle_global_vregs (MonoCompile *cfg)
 #if SIZEOF_REGISTER == 8
                case STACK_I8:
 #endif
-#if !defined(TARGET_X86) && !defined(MONO_ARCH_SOFT_FLOAT)
+#if !defined(TARGET_X86)
                /* Enabling this screws up the fp stack on x86 */
                case STACK_R8:
 #endif
+                       if (mono_arch_is_soft_float ())
+                               break;
+
                        /* Arguments are implicitly global */
                        /* Putting R4 vars into registers doesn't work currently */
                        /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
index eb60841a81f5c9daf065e66511d20aa94dd7df17..1d22be833dd2d11928b88daa282d6a60ce26cd85 100644 (file)
@@ -1386,6 +1386,12 @@ mono_arch_cpu_enumerate_simd_versions (void)
        return sse_opts;        
 }
 
+gboolean
+mono_arch_is_soft_float (void)
+{
+       return FALSE;
+}
+
 #ifndef DISABLE_JIT
 
 GList *
index 00953df72456985a5c8b3ef412ff08cc964c291b..bfcc41e35ab7e4abef4dc395c3dbd185c680d003 100644 (file)
 #error "ARM_FPU_NONE is defined while one of ARM_FPU_VFP/ARM_FPU_VFP_HARD is defined"
 #endif
 
+#define IS_VFP (!mono_arch_is_soft_float ())
+#define IS_SOFT_FLOAT (mono_arch_is_soft_float ())
+
 #if defined(__ARM_EABI__) && defined(__linux__) && !defined(PLATFORM_ANDROID) && !defined(__native_client__)
 #define HAVE_AEABI_READ_TP 1
 #endif
 
-#ifdef ARM_FPU_VFP_HARD
-#define ARM_FPU_VFP 1
-#endif
-
-#ifdef ARM_FPU_VFP
-#define IS_VFP 1
-#else
-#define IS_VFP 0
-#endif
-
-#ifdef MONO_ARCH_SOFT_FLOAT
-#define IS_SOFT_FLOAT 1
-#else
-#define IS_SOFT_FLOAT 0
-#endif
-
 #ifdef __native_client_codegen__
 const guint kNaClAlignment = kNaClAlignmentARM;
 const guint kNaClAlignmentMask = kNaClAlignmentMaskARM;
@@ -785,6 +772,8 @@ create_function_wrapper (gpointer function)
 void
 mono_arch_init (void)
 {
+       const char *cpu_arch;
+
        InitializeCriticalSection (&mini_arch_mutex);
 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
        if (mini_get_debug_options ()->soft_breakpoints) {
@@ -808,31 +797,14 @@ mono_arch_init (void)
 
 #if defined(ARM_FPU_VFP_HARD)
        arm_fpu = MONO_ARM_FPU_VFP_HARD;
-#elif defined(ARM_FPU_VFP)
-       arm_fpu = MONO_ARM_FPU_VFP;
 #else
-       arm_fpu = MONO_ARM_FPU_NONE;
+       /* NOTE: This may be set to MONO_ARM_FPU_NONE below
+                in case we decide to fall back to soft float. */
+       arm_fpu = MONO_ARM_FPU_VFP;
 #endif
-}
-
-/*
- * Cleanup architecture specific code.
- */
-void
-mono_arch_cleanup (void)
-{
-}
-
-/*
- * This function returns the optimizations supported on this cpu.
- */
-guint32
-mono_arch_cpu_optimizations (guint32 *exclude_mask)
-{
-       guint32 opts = 0;
 
        /* Format: armv(5|6|7[s])[-thumb[2]] */
-       const char *cpu_arch = getenv ("MONO_CPU_ARCH");
+       cpu_arch = getenv ("MONO_CPU_ARCH");
        if (cpu_arch != NULL) {
                if (strncmp (cpu_arch, "armv", 4) == 0) {
                        v5_supported = cpu_arch [4] >= '5';
@@ -844,100 +816,134 @@ mono_arch_cpu_optimizations (guint32 *exclude_mask)
                thumb2_supported = strstr (cpu_arch, "thumb2") != NULL;
        } else {
 #if __APPLE__
-       thumb_supported = TRUE;
-       v5_supported = TRUE;
-       darwin = TRUE;
-       iphone_abi = TRUE;
+               thumb_supported = TRUE;
+               v5_supported = TRUE;
+               darwin = TRUE;
+               iphone_abi = TRUE;
 #elif defined(PLATFORM_ANDROID)
-       /* Android is awesome and doesn't make most of /proc (including
-        * /proc/self/auxv) available to regular processes. So we use
-        * /proc/cpuinfo instead.... */
-       char buf [512];
-       char *line;
-       FILE *file = fopen ("/proc/cpuinfo", "r");
-       if (file) {
-               while ((line = fgets (buf, 512, file))) {
-                       if (strncmp (line, "Processor", 9) == 0) {
-                               char *ver = strstr (line, "(v");
-                               if (ver) {
-                                       if (ver [2] >= '5')
-                                               v5_supported = TRUE;
-                                       if (ver [2] >= '6')
-                                               v6_supported = TRUE;
-                                       if (ver [2] >= '7')
-                                               v7_supported = TRUE;
-                                       /* TODO: Find a way to detect v7s. */
+               /* Android is awesome and doesn't make most of /proc (including
+                * /proc/self/auxv) available to regular processes. So we use
+                * /proc/cpuinfo instead.... */
+               char buf [512];
+               char *line;
+
+               FILE *file = fopen ("/proc/cpuinfo", "r");
+
+               gboolean vfp_found = FALSE;
+
+               if (file) {
+                       while ((line = fgets (buf, 512, file))) {
+                               if (strncmp (line, "Processor", 9) == 0) {
+                                       char *ver = strstr (line, "(v");
+                                       if (ver) {
+                                               if (ver [2] >= '5')
+                                                       v5_supported = TRUE;
+                                               if (ver [2] >= '6')
+                                                       v6_supported = TRUE;
+                                               if (ver [2] >= '7')
+                                                       v7_supported = TRUE;
+                                               /* TODO: Find a way to detect v7s. */
+                                       }
+                                       continue;
                                }
-                               continue;
-                       }
-                       if (strncmp (line, "Features", 8) == 0) {
-                               /* TODO: Find a way to detect Thumb 2. */
-                               char *th = strstr (line, "thumb");
-                               if (th) {
-                                       thumb_supported = TRUE;
-                                       if (v5_supported)
-                                               break;
+                               if (strncmp (line, "Features", 8) == 0) {
+                                       /* TODO: Find a way to detect Thumb 2. */
+                                       char *th = strstr (line, "thumb");
+                                       if (th) {
+                                               thumb_supported = TRUE;
+                                               if (v5_supported)
+                                                       break;
+                                       }
+                                       th = strstr (line, "vfp");
+                                       if (th) {
+                                               vfp_found = TRUE;
+                                       }
+                                       continue;
                                }
-                               continue;
                        }
+
+                       fclose (file);
+                       /*printf ("features: v5: %d, thumb: %d\n", v5_supported, thumb_supported);*/
                }
 
-               fclose (file);
-               /*printf ("features: v5: %d, thumb: %d\n", v5_supported, thumb_supported);*/
-       }
+               if (!vfp_found && arm_fpu != MONO_ARM_FPU_VFP_HARD)
+                       arm_fpu = MONO_ARM_FPU_NONE;
 #else
-       /* This solution is neat because it uses the dynamic linker
-        * instead of the kernel. Thus, it works in QEMU chroots. */
-       unsigned long int hwcap;
-       unsigned long int platform;
-
-       if ((hwcap = getauxval(AT_HWCAP))) {
-               /* We use hardcoded values to avoid depending on a
-                * specific version of the hwcap.h header. */
-
-               /* HWCAP_ARM_THUMB */
-               if ((hwcap & 4) != 0)
-                       /* TODO: Find a way to detect Thumb 2. */
-                       thumb_supported = TRUE;
-       }
+               /* This solution is neat because it uses the dynamic linker
+                * instead of the kernel. Thus, it works in QEMU chroots. */
+               unsigned long int hwcap;
+               unsigned long int platform;
+
+               gboolean vfp_found = FALSE;
+
+               if ((hwcap = getauxval(AT_HWCAP))) {
+                       /* We use hardcoded values to avoid depending on a
+                        * specific version of the hwcap.h header. */
 
-       if ((platform = getauxval(AT_PLATFORM))) {
-               /* Actually a pointer to the platform string. */
-               const char *str = (const char *) platform;
+                       /* HWCAP_ARM_THUMB */
+                       if ((hwcap & 4) != 0)
+                               /* TODO: Find a way to detect Thumb 2. */
+                               thumb_supported = TRUE;
 
-               /* Possible CPU name values (from kernel sources):
-                *
-                * - v4
-                * - v5
-                * - v5t
-                * - v6
-                * - v7
-                *
-                * Value is suffixed with the endianness ('b' or 'l').
-                * We only support little endian anyway.
-               */
+                       if ((hwcap & 64) != 0)
+                               vfp_found = TRUE;
+               }
 
-               if (str [1] >= '5')
-                       v5_supported = TRUE;
+               if ((platform = getauxval(AT_PLATFORM))) {
+                       /* Actually a pointer to the platform string. */
+                       const char *str = (const char *) platform;
+
+                       /* Possible CPU name values (from kernel sources):
+                        *
+                        * - v4
+                        * - v5
+                        * - v5t
+                        * - v6
+                        * - v7
+                        *
+                        * Value is suffixed with the endianness ('b' or 'l').
+                        * We only support little endian anyway.
+                        */
 
-               if (str [1] >= '6')
-                       v6_supported = TRUE;
+                       if (str [1] >= '5')
+                               v5_supported = TRUE;
 
-               if (str [1] >= '7')
-                       v7_supported = TRUE;
+                       if (str [1] >= '6')
+                               v6_supported = TRUE;
 
-               /* TODO: Find a way to detect v7s. */
-       }
+                       if (str [1] >= '7')
+                               v7_supported = TRUE;
+
+                       /* TODO: Find a way to detect v7s. */
+               }
+
+               /*printf ("hwcap = %i, platform = %s\n", (int) hwcap, (const char *) platform);
+               printf ("thumb = %i, thumb2 = %i, v5 = %i, v6 = %i, v7 = %i, v7s = %i\n",
+                       thumb_supported, thumb2_supported, v5_supported, v6_supported, v7_supported, v7s_supported);*/
 
-       /*printf ("hwcap = %i, platform = %s\n", (int) hwcap, (const char *) platform);
-       printf ("thumb = %i, thumb2 = %i, v5 = %i, v6 = %i, v7 = %i, v7s = %i\n",
-               thumb_supported, thumb2_supported, v5_supported, v6_supported, v7_supported, v7s_supported);*/
+               if (!vfp_found && arm_fpu != MONO_ARM_FPU_VFP_HARD)
+                       arm_fpu = MONO_ARM_FPU_NONE;
 #endif
        }
+}
+
+/*
+ * Cleanup architecture specific code.
+ */
+void
+mono_arch_cleanup (void)
+{
+}
 
+/*
+ * This function returns the optimizations supported on this cpu.
+ */
+guint32
+mono_arch_cpu_optimizations (guint32 *exclude_mask)
+{
        /* no arm-specific optimizations yet */
        *exclude_mask = 0;
-       return opts;
+       return 0;
 }
 
 /*
@@ -973,6 +979,16 @@ mono_arch_opcode_needs_emulation (MonoCompile *cfg, int opcode)
        return TRUE;
 }
 
+gboolean
+mono_arch_is_soft_float (void)
+{
+#ifndef MONO_ARCH_SOFT_FLOAT_FALLBACK
+       return FALSE;
+#else
+       return arm_fpu == MONO_ARM_FPU_NONE;
+#endif
+}
+
 static gboolean
 is_regsize_var (MonoGenericSharingContext *gsctx, MonoType *t) {
        if (t->byref)
@@ -4780,8 +4796,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        break;
 
                /* floating point opcodes */
-#if defined(ARM_FPU_VFP)
-
                case OP_R8CONST:
                        if (cfg->compile_aot) {
                                ARM_FLDD (code, ins->dreg, ARMREG_PC, 0);
@@ -4863,9 +4877,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                ARM_FMRRD (code, ARMREG_R0, ARMREG_R1, ins->sreg1);
                        }
                        break;
-
-#endif
-
                case OP_FCONV_TO_I1:
                        code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
                        break;
@@ -4927,7 +4938,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
                        break;
                }
-#if defined(ARM_FPU_VFP)
                case OP_FADD:
                        ARM_VFP_ADDD (code, ins->dreg, ins->sreg1, ins->sreg2);
                        break;
@@ -4943,7 +4953,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_FNEG:
                        ARM_NEGD (code, ins->dreg, ins->sreg1);
                        break;
-#endif
                case OP_FREM:
                        /* emulated */
                        g_assert_not_reached ();
index 86859aaf37b1e3252ec964d53460d308610afd40..913dafc5e0d7480dcd205ad9dd931b965cd5058d 100644 (file)
@@ -15,8 +15,8 @@
 #define kNaClLengthOfCallImm 4
 #endif
 
-#if defined(ARM_FPU_NONE) || (defined(__ARM_EABI__) && !defined(ARM_FPU_VFP) && !defined(ARM_FPU_VFP_HARD))
-#define MONO_ARCH_SOFT_FLOAT 1
+#if defined(ARM_FPU_NONE)
+#define MONO_ARCH_SOFT_FLOAT_FALLBACK 1
 #endif
 
 #ifdef ARM_FPU_VFP_HARD
@@ -36,9 +36,9 @@
 #if defined(ARM_FPU_VFP)
 #define ARM_FP_MODEL "vfp"
 #elif defined(ARM_FPU_NONE)
-#define ARM_FP_MODEL "soft-float"
+#define ARM_FP_MODEL "vfp+fallback"
 #elif defined(ARM_FPU_VFP_HARD)
-#define ARM_FP_MODEL "vfp(hardfp-abi)"
+#define ARM_FP_MODEL "vfp+hard"
 #else
 #error "At least one of ARM_FPU_NONE, ARM_FPU_VFP or ARM_FPU_VFP_HARD must be defined."
 #endif
 #define MONO_ARCH_CALLEE_REGS ((1<<ARMREG_R0) | (1<<ARMREG_R1) | (1<<ARMREG_R2) | (1<<ARMREG_R3) | (1<<ARMREG_IP))
 #define MONO_ARCH_CALLEE_SAVED_REGS ((1<<ARMREG_V1) | (1<<ARMREG_V2) | (1<<ARMREG_V3) | (1<<ARMREG_V4) | (1<<ARMREG_V5) | (1<<ARMREG_V6) | (1<<ARMREG_V7))
 
-#if defined(ARM_FPU_VFP) || defined(ARM_FPU_VFP_HARD)
 /* Every double precision vfp register, d0/d1 is reserved for a scratch reg */
 #define MONO_ARCH_CALLEE_FREGS 0x55555550
-#else
-#define MONO_ARCH_CALLEE_FREGS 0xf
-#endif
 #define MONO_ARCH_CALLEE_SAVED_FREGS 0
 
 #define MONO_ARCH_USE_FPSTACK FALSE
 
 #define MONO_ARCH_INST_SREG2_MASK(ins) (0)
 
-#ifdef MONO_ARCH_SOFT_FLOAT
-#define MONO_ARCH_INST_FIXED_REG(desc) (((desc) == 'l' || (desc == 'f') || (desc == 'g')) ? ARM_LSW_REG: (((desc) == 'a') ? ARMREG_R0 : -1))
-#define MONO_ARCH_INST_IS_REGPAIR(desc) ((desc) == 'l' || (desc) == 'L' || (desc) == 'f' || (desc) == 'g')
-#define MONO_ARCH_INST_IS_FLOAT(desc) (FALSE)
-#else
-#define MONO_ARCH_INST_FIXED_REG(desc) (((desc) == 'l')? ARM_LSW_REG: (((desc) == 'a') ? ARMREG_R0 : -1))
-#define MONO_ARCH_INST_IS_REGPAIR(desc) (desc == 'l' || desc == 'L')
-#define MONO_ARCH_INST_IS_FLOAT(desc) ((desc == 'f') || (desc == 'g'))
-#endif
-#define MONO_ARCH_INST_REGPAIR_REG2(desc,hreg1) (desc == 'l'  || (desc == 'f') || (desc == 'g')? ARM_MSW_REG : -1)
+#define MONO_ARCH_INST_FIXED_REG(desc) \
+       (mono_arch_is_soft_float () ? \
+       ((desc) == 'l' || (desc) == 'f' || (desc) == 'g' ? ARM_LSW_REG : (desc) == 'a' ? ARMREG_R0 : -1) : \
+       ((desc) == 'l' ? ARM_LSW_REG : (desc) == 'a' ? ARMREG_R0 : -1))
+
+#define MONO_ARCH_INST_IS_REGPAIR(desc) \
+       (mono_arch_is_soft_float () ? \
+       ((desc) == 'l' || (desc) == 'L' || (desc) == 'f' || (desc) == 'g') : \
+       ((desc) == 'l' || (desc) == 'L'))
+
+#define MONO_ARCH_INST_IS_FLOAT(desc) \
+       (mono_arch_is_soft_float () ? \
+       (FALSE) : \
+       ((desc) == 'f' || (desc) == 'g'))
+
+#define MONO_ARCH_INST_REGPAIR_REG2(desc,hreg1) ((desc) == 'l' || (desc) == 'f' || (desc) == 'g' ? ARM_MSW_REG : -1)
 
 #define MONO_ARCH_FRAME_ALIGNMENT 8
 
index c45305e2668a99e960a45797daec97f6011df4a3..3ab6a7ffc72171cc46d63d3b90f136bd6fad0954 100644 (file)
@@ -610,6 +610,12 @@ mono_arch_cpu_optimizations (guint32 *exclude_mask)
        return 0;
 }
 
+gboolean
+mono_arch_is_soft_float (void)
+{
+        return FALSE;
+}
+
 /*
  * This function test for all SIMD functions supported.
  *
index dcfaf366102cdb815e0d2d98c0c519c4d7bac3fe..3474e0d7bbc0c7a4950b1d438da9b59021d215bd 100644 (file)
@@ -934,12 +934,12 @@ convert_full (EmitContext *ctx, LLVMValueRef v, LLVMTypeRef dtype, gboolean is_u
                if (LLVMGetTypeKind (stype) == LLVMPointerTypeKind)
                        return LLVMBuildPtrToInt (ctx->builder, v, dtype, "");
 
-#ifdef MONO_ARCH_SOFT_FLOAT
-               if (stype == LLVMInt32Type () && dtype == LLVMFloatType ())
-                       return LLVMBuildBitCast (ctx->builder, v, dtype, "");
-               if (stype == LLVMInt32Type () && dtype == LLVMDoubleType ())
-                       return LLVMBuildBitCast (ctx->builder, LLVMBuildZExt (ctx->builder, v, LLVMInt64Type (), ""), dtype, "");
-#endif
+               if (mono_arch_is_soft_float ()) {
+                       if (stype == LLVMInt32Type () && dtype == LLVMFloatType ())
+                               return LLVMBuildBitCast (ctx->builder, v, dtype, "");
+                       if (stype == LLVMInt32Type () && dtype == LLVMDoubleType ())
+                               return LLVMBuildBitCast (ctx->builder, LLVMBuildZExt (ctx->builder, v, LLVMInt64Type (), ""), dtype, "");
+               }
 
                if (LLVMGetTypeKind (stype) == LLVMVectorTypeKind && LLVMGetTypeKind (dtype) == LLVMVectorTypeKind)
                        return LLVMBuildBitCast (ctx->builder, v, dtype, "");
index a72be2f15bdbe1477fc9d7281eb10ae7a4502ba4..3bb87f964df510f5406b9960dc756d1570bcade3 100644 (file)
@@ -726,6 +726,12 @@ mono_arch_cpu_optimizations (guint32 *exclude_mask)
        return opts;
 }
 
+gboolean
+mono_arch_is_soft_float (void)
+{
+       return FALSE;
+}
+
 /*
  * This function test for all SIMD functions supported.
  *
index 13ea174f78debb8dae960233da586852e66e5b94..5453a22dcd65a9cd4c07588063eeeda7486d1adc 100644 (file)
@@ -668,6 +668,12 @@ mono_arch_cpu_optimizations (guint32 *exclude_mask)
        return opts;
 }
 
+gboolean
+mono_arch_is_soft_float (void)
+{
+       return FALSE;
+}
+
 /*
  * This function test for all SIMD functions supported.
  *
index 43677fc3ec9af85edfff546a6ef25c921c73a99e..56d95a8894708dd67561980dd5fe910e82bdfd63 100644 (file)
@@ -1382,6 +1382,12 @@ mono_arch_cpu_optimizations (guint32 *exclude_mask)
        return opts;
 }
 
+gboolean
+mono_arch_is_soft_float (void)
+{
+       return FALSE;
+}
+
 /*========================= End of Function ========================*/
 
 /*------------------------------------------------------------------*/
index 2300f39c74ae25372174e6f9ef049cb6f7a1051b..79d9890b4207edd3c0cb8269d2af598ca71dd733 100644 (file)
@@ -207,6 +207,12 @@ mono_arch_cpu_init (void)
        mono_arch_cpu_optimizations(&dummy);
 }
 
+gboolean
+mono_arch_is_soft_float (void)
+{
+       return FALSE;
+}
+
 /*
  * Initialize architecture specific code.
  */
index 141cc6b4f13a64bd48b305d8ce673c8bf62167df..11f12c03efffb1ea8fc2448ac7d2f0906f6501cd 100644 (file)
@@ -916,6 +916,12 @@ mono_arch_cpu_optimizations (guint32 *exclude_mask)
 #endif
 }
 
+gboolean
+mono_arch_is_soft_float (void)
+{
+       return FALSE;
+}
+
 /*
  * This function test for all SSE functions supported.
  *
index e0576bd1fbde14b9690c95a53feb13e07e2e9d7e..68cd2c3033c6f00d8d8e188f2c5be6247e61c15a 100644 (file)
@@ -1202,11 +1202,11 @@ mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode,
                set_vreg_to_inst (cfg, vreg, inst);
 
 #if SIZEOF_REGISTER == 4
-#ifdef MONO_ARCH_SOFT_FLOAT
-       regpair = mono_type_is_long (type) || mono_type_is_float (type);
-#else
-       regpair = mono_type_is_long (type);
-#endif
+       if (mono_arch_is_soft_float ()) {
+               regpair = mono_type_is_long (type) || mono_type_is_float (type);
+       } else {
+               regpair = mono_type_is_long (type);
+       }
 #else
        regpair = FALSE;
 #endif
@@ -1227,12 +1227,10 @@ mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode,
                        printf ("  Create LVAR R%d (R%d, R%d)\n", inst->dreg, inst->dreg + 1, inst->dreg + 2);
                }
 
-#ifdef MONO_ARCH_SOFT_FLOAT
-               if (cfg->opt & MONO_OPT_SSA) {
+               if (mono_arch_is_soft_float () && cfg->opt & MONO_OPT_SSA) {
                        if (mono_type_is_float (type))
                                inst->flags = MONO_INST_VOLATILE;
                }
-#endif
 
                /* Allocate a dummy MonoInst for the first vreg */
                MONO_INST_NEW (cfg, tree, OP_LOCAL);
@@ -1272,10 +1270,8 @@ mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
 
        if (mono_type_is_long (type))
                dreg = mono_alloc_dreg (cfg, STACK_I8);
-#ifdef MONO_ARCH_SOFT_FLOAT
-       else if (mono_type_is_float (type))
+       else if (mono_arch_is_soft_float () && mono_type_is_float (type))
                dreg = mono_alloc_dreg (cfg, STACK_R8);
-#endif
        else
                /* All the others are unified */
                dreg = mono_alloc_preg (cfg);
@@ -5261,8 +5257,8 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                return cfg;
        }
 
-#ifdef MONO_ARCH_SOFT_FLOAT
-       if (!COMPILE_LLVM (cfg))
+#ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
+       if (COMPILE_SOFT_FLOAT (cfg))
                mono_decompose_soft_float (cfg);
 #endif
        if (!COMPILE_LLVM (cfg))
@@ -7124,8 +7120,20 @@ mini_init (const char *filename, const char *runtime_version)
        register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, "mono_imul_ovf_un", FALSE);
 #endif
 
-#if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
-       register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, "mono_fdiv", FALSE);
+#if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
+
+#ifdef MONO_ARCH_EMULATE_MUL_DIV
+#define EMUL_MUL_DIV 1
+#else
+#define EMUL_MUL_DIV 0
+#endif
+
+       if (EMUL_MUL_DIV || mono_arch_is_soft_float ()) {
+               register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, "mono_fdiv", FALSE);
+       }
+
+#undef EMUL_MUL_DIV
+
 #endif
 
        register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, "mono_fconv_u8", FALSE);
@@ -7156,44 +7164,47 @@ mini_init (const char *filename, const char *runtime_version)
 #endif
 #endif
 
-#ifdef MONO_ARCH_SOFT_FLOAT
-       register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, "mono_fsub", FALSE);
-       register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, "mono_fadd", FALSE);
-       register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, "mono_fmul", FALSE);
-       register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, "mono_fneg", FALSE);
-       register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, "mono_conv_to_r8", FALSE);
-       register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, "mono_conv_to_r4", FALSE);
-       register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, "mono_fconv_r4", FALSE);
-       register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, "mono_fconv_i1", FALSE);
-       register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, "mono_fconv_i2", FALSE);
-       register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
-       register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, "mono_fconv_u1", FALSE);
-       register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, "mono_fconv_u2", FALSE);
+#ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
+       if (mono_arch_is_soft_float ()) {
+               register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, "mono_fsub", FALSE);
+               register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, "mono_fadd", FALSE);
+               register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, "mono_fmul", FALSE);
+               register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, "mono_fneg", FALSE);
+               register_opcode_emulation (OP_ICONV_TO_R8, "__emul_iconv_to_r8", "double int32", mono_conv_to_r8, "mono_conv_to_r8", FALSE);
+               register_opcode_emulation (OP_ICONV_TO_R4, "__emul_iconv_to_r4", "double int32", mono_conv_to_r4, "mono_conv_to_r4", FALSE);
+               register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, "mono_fconv_r4", FALSE);
+               register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, "mono_fconv_i1", FALSE);
+               register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, "mono_fconv_i2", FALSE);
+               register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
+               register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, "mono_fconv_u1", FALSE);
+               register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, "mono_fconv_u2", FALSE);
+
 #if SIZEOF_VOID_P == 4
-       register_opcode_emulation (OP_FCONV_TO_I, "__emul_fconv_to_i", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
-#endif
-
-       register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, "mono_fcmp_eq", FALSE);
-       register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, "mono_fcmp_lt", FALSE);
-       register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, "mono_fcmp_gt", FALSE);
-       register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, "mono_fcmp_le", FALSE);
-       register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, "mono_fcmp_ge", FALSE);
-       register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, "mono_fcmp_ne_un", FALSE);
-       register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, "mono_fcmp_lt_un", FALSE);
-       register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, "mono_fcmp_gt_un", FALSE);
-       register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, "mono_fcmp_le_un", FALSE);
-       register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, "mono_fcmp_ge_un", FALSE);
-
-       register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, "mono_fceq", FALSE);
-       register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, "mono_fcgt", FALSE);
-       register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, "mono_fcgt_un", FALSE);
-       register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, "mono_fclt", FALSE);
-       register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, "mono_fclt_un", FALSE);
-
-       register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
-       register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
-       register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
-       register_icall (mono_isfinite, "mono_isfinite", "uint32 double", FALSE);
+               register_opcode_emulation (OP_FCONV_TO_I, "__emul_fconv_to_i", "int32 double", mono_fconv_i4, "mono_fconv_i4", FALSE);
+#endif
+
+               register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, "mono_fcmp_eq", FALSE);
+               register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, "mono_fcmp_lt", FALSE);
+               register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, "mono_fcmp_gt", FALSE);
+               register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, "mono_fcmp_le", FALSE);
+               register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, "mono_fcmp_ge", FALSE);
+               register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, "mono_fcmp_ne_un", FALSE);
+               register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, "mono_fcmp_lt_un", FALSE);
+               register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, "mono_fcmp_gt_un", FALSE);
+               register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, "mono_fcmp_le_un", FALSE);
+               register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, "mono_fcmp_ge_un", FALSE);
+
+               register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, "mono_fceq", FALSE);
+               register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, "mono_fcgt", FALSE);
+               register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, "mono_fcgt_un", FALSE);
+               register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, "mono_fclt", FALSE);
+               register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, "mono_fclt_un", FALSE);
+
+               register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
+               register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
+               register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
+               register_icall (mono_isfinite, "mono_isfinite", "uint32 double", FALSE);
+       }
 #endif
 
 #ifdef COMPRESSED_INTERFACE_BITMAP
index 3e028ada899eaf049b2dbda1de027dd6d3354e2a..68b2e9868a1ee05054d193564dcd6cf466012417 100644 (file)
 #define LLVM_ENABLED FALSE
 #endif
 
-#ifdef MONO_ARCH_SOFT_FLOAT
-#define COMPILE_SOFT_FLOAT(cfg) (!COMPILE_LLVM ((cfg)))
+#ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
+#define COMPILE_SOFT_FLOAT(cfg) (!COMPILE_LLVM ((cfg)) && mono_arch_is_soft_float ())
 #else
-#define COMPILE_SOFT_FLOAT(cfg) 0
+#define COMPILE_SOFT_FLOAT(cfg) (0)
 #endif
 
 #ifdef ENABLE_LLVM
@@ -2261,6 +2261,7 @@ gboolean  mono_arch_gsharedvt_sig_supported     (MonoMethodSignature *sig) MONO_
 gpointer  mono_arch_get_gsharedvt_trampoline    (MonoTrampInfo **info, gboolean aot) MONO_INTERNAL;
 gpointer  mono_arch_get_gsharedvt_call_info     (gpointer addr, MonoMethodSignature *normal_sig, MonoMethodSignature *gsharedvt_sig, MonoGenericSharingContext *gsctx, gboolean gsharedvt_in, gint32 vcall_offset, gboolean calli) MONO_INTERNAL;
 gboolean  mono_arch_opcode_needs_emulation      (MonoCompile *cfg, int opcode) MONO_INTERNAL;
+gboolean  mono_arch_is_soft_float               (void) MONO_INTERNAL;
 
 /* Soft Debug support */
 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED