New tests.
[mono.git] / mono / mini / mini-arm.c
index 40949a3355fc5f1f55f94086b4c614d1eb0c68dd..0a72637f062ad53b5efd0e90572c5925241fab7c 100644 (file)
@@ -136,6 +136,8 @@ mono_arch_fregname (int reg)
        return "unknown";
 }
 
+#ifndef DISABLE_JIT
+
 static guint8*
 emit_big_add (guint8 *code, int dreg, int sreg, int imm)
 {
@@ -247,6 +249,8 @@ emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
        return code;
 }
 
+#endif /* #ifndef DISABLE_JIT */
+
 /*
  * mono_arch_get_argument_info:
  * @csig:  a method signature
@@ -549,6 +553,14 @@ guint32
 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
 {
        guint32 opts = 0;
+       const char *cpu_arch = getenv ("MONO_CPU_ARCH");
+       if (cpu_arch != NULL) {
+               thumb_supported = strstr (cpu_arch, "thumb") != NULL;
+               if (strncmp (cpu_arch, "armv", 4) == 0) {
+                       v5_supported = cpu_arch [4] >= '5';
+                       v7_supported = cpu_arch [4] >= '7';
+               }
+       } else {
 #if __APPLE__
        thumb_supported = TRUE;
        v5_supported = TRUE;
@@ -580,12 +592,15 @@ mono_arch_cpu_optimizazions (guint32 *exclude_mask)
                /*printf ("features: v5: %d, thumb: %d\n", v5_supported, thumb_supported);*/
        }
 #endif
+       }
 
        /* no arm-specific optimizations yet */
        *exclude_mask = 0;
        return opts;
 }
 
+#ifndef DISABLE_JIT
+
 static gboolean
 is_regsize_var (MonoType *t) {
        if (t->byref)
@@ -685,6 +700,8 @@ mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
        return 2;
 }
 
+#endif /* #ifndef DISABLE_JIT */
+
 #ifndef __GNUC_PREREQ
 #define __GNUC_PREREQ(maj, min) (0)
 #endif
@@ -902,7 +919,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
                        n++;
                        break;
                case MONO_TYPE_GENERICINST:
-                       if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
+                       if (!mono_type_generic_inst_is_valuetype (simpletype)) {
                                cinfo->args [n].size = sizeof (gpointer);
                                add_general (&gr, &stack_size, cinfo->args + n, TRUE);
                                n++;
@@ -1015,7 +1032,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
                        cinfo->ret.storage = RegTypeFP;*/
                        break;
                case MONO_TYPE_GENERICINST:
-                       if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
+                       if (!mono_type_generic_inst_is_valuetype (simpletype)) {
                                cinfo->ret.storage = RegTypeGeneral;
                                cinfo->ret.reg = ARMREG_R0;
                                break;
@@ -1041,6 +1058,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
        return cinfo;
 }
 
+#ifndef DISABLE_JIT
 
 /*
  * Set var information according to the calling convention. arm version.
@@ -1051,10 +1069,11 @@ mono_arch_allocate_vars (MonoCompile *cfg)
 {
        MonoMethodSignature *sig;
        MonoMethodHeader *header;
-       MonoInst *inst;
+       MonoInst *ins;
        int i, offset, size, align, curinst;
        int frame_reg = ARMREG_FP;
        CallInfo *cinfo;
+       guint32 ualign;
 
        sig = mono_method_signature (cfg->method);
 
@@ -1069,7 +1088,7 @@ mono_arch_allocate_vars (MonoCompile *cfg)
        if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
                cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
 
-       header = mono_method_get_header (cfg->method);
+       header = cfg->header;
 
        /* 
         * We use the frame register also for any method that has
@@ -1133,12 +1152,12 @@ mono_arch_allocate_vars (MonoCompile *cfg)
                        offset &= ~(sizeof (gpointer) - 1);
                        cfg->ret->inst_offset = - offset;
                } else {
-                       inst = cfg->vret_addr;
+                       ins = cfg->vret_addr;
                        offset += sizeof(gpointer) - 1;
                        offset &= ~(sizeof(gpointer) - 1);
-                       inst->inst_offset = offset;
-                       inst->opcode = OP_REGOFFSET;
-                       inst->inst_basereg = frame_reg;
+                       ins->inst_offset = offset;
+                       ins->opcode = OP_REGOFFSET;
+                       ins->inst_basereg = frame_reg;
                        if (G_UNLIKELY (cfg->verbose_level > 1)) {
                                printf ("vret_addr =");
                                mono_print_ins (cfg->vret_addr);
@@ -1147,21 +1166,46 @@ mono_arch_allocate_vars (MonoCompile *cfg)
                offset += sizeof(gpointer);
        }
 
+       /* Allocate these first so they have a small offset, OP_SEQ_POINT depends on this */
+       if (cfg->arch.seq_point_info_var) {
+               MonoInst *ins;
+
+               ins = cfg->arch.seq_point_info_var;
+
+               size = 4;
+               align = 4;
+               offset += align - 1;
+               offset &= ~(align - 1);
+               ins->opcode = OP_REGOFFSET;
+               ins->inst_basereg = frame_reg;
+               ins->inst_offset = offset;
+               offset += size;
+
+               ins = cfg->arch.ss_trigger_page_var;
+               size = 4;
+               align = 4;
+               offset += align - 1;
+               offset &= ~(align - 1);
+               ins->opcode = OP_REGOFFSET;
+               ins->inst_basereg = frame_reg;
+               ins->inst_offset = offset;
+               offset += size;
+       }
+
        curinst = cfg->locals_start;
        for (i = curinst; i < cfg->num_varinfo; ++i) {
-               inst = cfg->varinfo [i];
-               if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
+               ins = cfg->varinfo [i];
+               if ((ins->flags & MONO_INST_IS_DEAD) || ins->opcode == OP_REGVAR || ins->opcode == OP_REGOFFSET)
                        continue;
 
                /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
                * pinvoke wrappers when they call functions returning structure */
-               if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF) {
-                       guint32 ualign;
-                       size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &ualign);
+               if (ins->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (ins->inst_vtype) && ins->inst_vtype->type != MONO_TYPE_TYPEDBYREF) {
+                       size = mono_class_native_size (mono_class_from_mono_type (ins->inst_vtype), &ualign);
                        align = ualign;
                }
                else
-                       size = mono_type_size (inst->inst_vtype, &align);
+                       size = mono_type_size (ins->inst_vtype, &align);
 
                /* FIXME: if a structure is misaligned, our memcpy doesn't work,
                 * since it loads/stores misaligned words, which don't do the right thing.
@@ -1170,22 +1214,22 @@ mono_arch_allocate_vars (MonoCompile *cfg)
                        align = 4;
                offset += align - 1;
                offset &= ~(align - 1);
-               inst->inst_offset = offset;
-               inst->opcode = OP_REGOFFSET;
-               inst->inst_basereg = frame_reg;
+               ins->opcode = OP_REGOFFSET;
+               ins->inst_offset = offset;
+               ins->inst_basereg = frame_reg;
                offset += size;
                //g_print ("allocating local %d to %d\n", i, inst->inst_offset);
        }
 
        curinst = 0;
        if (sig->hasthis) {
-               inst = cfg->args [curinst];
-               if (inst->opcode != OP_REGVAR) {
-                       inst->opcode = OP_REGOFFSET;
-                       inst->inst_basereg = frame_reg;
+               ins = cfg->args [curinst];
+               if (ins->opcode != OP_REGVAR) {
+                       ins->opcode = OP_REGOFFSET;
+                       ins->inst_basereg = frame_reg;
                        offset += sizeof (gpointer) - 1;
                        offset &= ~(sizeof (gpointer) - 1);
-                       inst->inst_offset = offset;
+                       ins->inst_offset = offset;
                        offset += sizeof (gpointer);
                }
                curinst++;
@@ -1203,12 +1247,13 @@ mono_arch_allocate_vars (MonoCompile *cfg)
        }                       
 
        for (i = 0; i < sig->param_count; ++i) {
-               inst = cfg->args [curinst];
+               ins = cfg->args [curinst];
 
-               if (inst->opcode != OP_REGVAR) {
-                       inst->opcode = OP_REGOFFSET;
-                       inst->inst_basereg = frame_reg;
-                       size = mini_type_stack_size_full (NULL, sig->params [i], NULL, sig->pinvoke);
+               if (ins->opcode != OP_REGVAR) {
+                       ins->opcode = OP_REGOFFSET;
+                       ins->inst_basereg = frame_reg;
+                       size = mini_type_stack_size_full (NULL, sig->params [i], &ualign, sig->pinvoke);
+                       align = ualign;
                        /* FIXME: if a structure is misaligned, our memcpy doesn't work,
                         * since it loads/stores misaligned words, which don't do the right thing.
                         */
@@ -1219,7 +1264,7 @@ mono_arch_allocate_vars (MonoCompile *cfg)
                                align = 4;
                        offset += align - 1;
                        offset &= ~(align - 1);
-                       inst->inst_offset = offset;
+                       ins->inst_offset = offset;
                        offset += size;
                }
                curinst++;
@@ -1301,6 +1346,55 @@ emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
        MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, cinfo->sig_cookie.offset, sig_arg->dreg);
 }
 
+#ifdef ENABLE_LLVM
+LLVMCallInfo*
+mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig)
+{
+       int i, n;
+       CallInfo *cinfo;
+       ArgInfo *ainfo;
+       LLVMCallInfo *linfo;
+
+       n = sig->param_count + sig->hasthis;
+
+       cinfo = get_call_info (cfg->mempool, sig, sig->pinvoke);
+
+       linfo = mono_mempool_alloc0 (cfg->mempool, sizeof (LLVMCallInfo) + (sizeof (LLVMArgInfo) * n));
+
+       /*
+        * LLVM always uses the native ABI while we use our own ABI, the
+        * only difference is the handling of vtypes:
+        * - we only pass/receive them in registers in some cases, and only 
+        *   in 1 or 2 integer registers.
+        */
+       if (cinfo->ret.storage != RegTypeGeneral && cinfo->ret.storage != RegTypeNone && cinfo->ret.storage != RegTypeFP && cinfo->ret.storage != RegTypeIRegPair) {
+               cfg->exception_message = g_strdup ("unknown ret conv");
+               cfg->disable_llvm = TRUE;
+               return linfo;
+       }
+
+       for (i = 0; i < n; ++i) {
+               ainfo = cinfo->args + i;
+
+               linfo->args [i].storage = LLVMArgNone;
+
+               switch (ainfo->storage) {
+               case RegTypeGeneral:
+               case RegTypeIRegPair:
+               case RegTypeBase:
+                       linfo->args [i].storage = LLVMArgInIReg;
+                       break;
+               default:
+                       cfg->exception_message = g_strdup_printf ("ainfo->storage (%d)", ainfo->storage);
+                       cfg->disable_llvm = TRUE;
+                       break;
+               }
+       }
+
+       return linfo;
+}
+#endif
+
 void
 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
 {
@@ -1539,10 +1633,14 @@ mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
                if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
                        MonoInst *ins;
 
-                       MONO_INST_NEW (cfg, ins, OP_SETLRET);
-                       ins->sreg1 = val->dreg + 1;
-                       ins->sreg2 = val->dreg + 2;
-                       MONO_ADD_INS (cfg->cbb, ins);
+                       if (COMPILE_LLVM (cfg)) {
+                               MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
+                       } else {
+                               MONO_INST_NEW (cfg, ins, OP_SETLRET);
+                               ins->sreg1 = val->dreg + 1;
+                               ins->sreg2 = val->dreg + 2;
+                               MONO_ADD_INS (cfg->cbb, ins);
+                       }
                        return;
                }
 #ifdef MONO_ARCH_SOFT_FLOAT
@@ -1582,6 +1680,8 @@ mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
        MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
 }
 
+#endif /* #ifndef DISABLE_JIT */
+
 gboolean 
 mono_arch_is_inst_imm (gint64 imm)
 {
@@ -1890,6 +1990,8 @@ mono_arch_finish_dyn_call (MonoDynCallInfo *info, guint8 *buf)
        }
 }
 
+#ifndef DISABLE_JIT
+
 /*
  * Allow tracing to work with this interface (with an optional argument)
  */
@@ -2439,8 +2541,13 @@ loop_start:
                        gboolean swap = FALSE;
                        int reg;
 
+                       if (!ins->next) {
+                               /* Optimized away */
+                               NULLIFY_INS (ins);
+                               break;
+                       }
+
                        /* Some fp compares require swapped operands */
-                       g_assert (ins->next);
                        switch (ins->next->opcode) {
                        case OP_FBGT:
                                ins->next->opcode = OP_FBLT;
@@ -2521,6 +2628,8 @@ emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size,
        return code;
 }
 
+#endif /* #ifndef DISABLE_JIT */
+
 typedef struct {
        guchar *code;
        const guchar *target;
@@ -2847,6 +2956,14 @@ mono_arm_emit_load_imm (guint8 *code, int dreg, guint32 val)
        return code;
 }
 
+gboolean
+mono_arm_thumb_supported (void)
+{
+       return thumb_supported;
+}
+
+#ifndef DISABLE_JIT
+
 /*
  * emit_load_volatile_arguments:
  *
@@ -2966,8 +3083,6 @@ emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
        return code;
 }
 
-#ifndef DISABLE_JIT
-
 void
 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 {
@@ -3179,7 +3294,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_NOT_NULL:
                        break;
                case OP_SEQ_POINT: {
-                       int i, il_offset;
+                       int i;
                        MonoInst *info_var = cfg->arch.seq_point_info_var;
                        MonoInst *ss_trigger_page_var = cfg->arch.ss_trigger_page_var;
                        MonoInst *var;
@@ -3221,12 +3336,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                ARM_LDR_IMM (code, dreg, dreg, 0);
                        }
 
-                       il_offset = ins->inst_imm;
-
-                       if (!cfg->seq_points)
-                               cfg->seq_points = g_ptr_array_new ();
-                       g_ptr_array_add (cfg->seq_points, GUINT_TO_POINTER (il_offset));
-                       g_ptr_array_add (cfg->seq_points, GUINT_TO_POINTER (code - cfg->native_code));
+                       mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
 
                        if (cfg->compile_aot) {
                                guint32 offset = code - cfg->native_code;
@@ -3707,6 +3817,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_CALL_HANDLER: 
                        mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
                        ARM_BL (code, 0);
+                       mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
                        break;
                case OP_LABEL:
                        ins->inst_c0 = code - cfg->native_code;
@@ -4255,9 +4366,11 @@ mono_arch_register_lowlevel_calls (void)
        mono_register_jit_icall (mono_arm_throw_exception, "mono_arm_throw_exception", mono_create_icall_signature ("void"), TRUE);
        mono_register_jit_icall (mono_arm_throw_exception_by_token, "mono_arm_throw_exception_by_token", mono_create_icall_signature ("void"), TRUE);
 
+#ifndef MONO_CROSS_COMPILE
 #ifdef HAVE_AEABI_READ_TP
        mono_register_jit_icall (__aeabi_read_tp, "__aeabi_read_tp", mono_create_icall_signature ("void"), TRUE);
 #endif
+#endif
 }
 
 #define patch_lis_ori(ip,val) do {\
@@ -4344,6 +4457,8 @@ mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, Mono
        }
 }
 
+#ifndef DISABLE_JIT
+
 /*
  * Stack frame layout:
  * 
@@ -4934,6 +5049,8 @@ mono_arch_emit_exceptions (MonoCompile *cfg)
 
 }
 
+#endif /* #ifndef DISABLE_JIT */
+
 static gboolean tls_offset_inited = FALSE;
 
 void
@@ -4985,6 +5102,8 @@ mono_arch_flush_register_windows (void)
 
 #ifdef MONO_ARCH_HAVE_IMT
 
+#ifndef DISABLE_JIT
+
 void
 mono_arch_emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt_arg)
 {
@@ -5028,6 +5147,8 @@ mono_arch_emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt
        }
 }
 
+#endif /* DISABLE_JIT */
+
 MonoMethod*
 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
 {
@@ -5045,12 +5166,6 @@ mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
                return (MonoMethod*) code_ptr [1];
 }
 
-MonoObject*
-mono_arch_find_this_argument (mgreg_t *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
-{
-       return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), regs, NULL);
-}
-
 MonoVTable*
 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
 {