double vald;
} DVal;
-#ifdef MONO_ARCH_SOFT_FLOAT
+#ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
/**
* mono_decompose_soft_float:
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
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)
#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
*/
#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
}
#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)
{
}
#endif
-#ifdef MONO_ARCH_SOFT_FLOAT
+#ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
double
mono_fsub (double a, double b)
*
* 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 ());
}
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
} 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
{
MonoMethodHeaderSummary header;
MonoVTable *vtable;
-#ifdef MONO_ARCH_SOFT_FLOAT
+#ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
MonoMethodSignature *sig = mono_method_signature (method);
int i;
#endif
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;
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;
#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 */
return sse_opts;
}
+gboolean
+mono_arch_is_soft_float (void)
+{
+ return FALSE;
+}
+
#ifndef DISABLE_JIT
GList *
#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;
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) {
#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';
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;
}
/*
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)
break;
/* floating point opcodes */
-#if defined(ARM_FPU_VFP)
-
case OP_R8CONST:
if (cfg->compile_aot) {
ARM_FLDD (code, ins->dreg, ARMREG_PC, 0);
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;
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;
case OP_FNEG:
ARM_NEGD (code, ins->dreg, ins->sreg1);
break;
-#endif
case OP_FREM:
/* emulated */
g_assert_not_reached ();
#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
#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
return 0;
}
+gboolean
+mono_arch_is_soft_float (void)
+{
+ return FALSE;
+}
+
/*
* This function test for all SIMD functions supported.
*
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, "");
return opts;
}
+gboolean
+mono_arch_is_soft_float (void)
+{
+ return FALSE;
+}
+
/*
* This function test for all SIMD functions supported.
*
return opts;
}
+gboolean
+mono_arch_is_soft_float (void)
+{
+ return FALSE;
+}
+
/*
* This function test for all SIMD functions supported.
*
return opts;
}
+gboolean
+mono_arch_is_soft_float (void)
+{
+ return FALSE;
+}
+
/*========================= End of Function ========================*/
/*------------------------------------------------------------------*/
mono_arch_cpu_optimizations(&dummy);
}
+gboolean
+mono_arch_is_soft_float (void)
+{
+ return FALSE;
+}
+
/*
* Initialize architecture specific code.
*/
#endif
}
+gboolean
+mono_arch_is_soft_float (void)
+{
+ return FALSE;
+}
+
/*
* This function test for all SSE functions supported.
*
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
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);
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);
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))
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);
#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
#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
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