Merge pull request #2820 from kumpera/license-change-rebased
[mono.git] / mono / mini / mini-arm.c
index a71aa353c19e450658b146d1ed6d3357a1a1a6df..86d4e123919cb97908c28153de6b512f1bc5d644 100644 (file)
@@ -8,6 +8,7 @@
  * (C) 2003 Ximian, Inc.
  * Copyright 2003-2011 Novell, Inc (http://www.novell.com)
  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 #include "mini.h"
 #include <string.h>
@@ -903,7 +904,7 @@ mono_arch_init (void)
        mono_aot_register_jit_icall ("mono_arm_throw_exception", mono_arm_throw_exception);
        mono_aot_register_jit_icall ("mono_arm_throw_exception_by_token", mono_arm_throw_exception_by_token);
        mono_aot_register_jit_icall ("mono_arm_resume_unwind", mono_arm_resume_unwind);
-#if defined(ENABLE_GSHAREDVT)
+#if defined(MONO_ARCH_GSHAREDVT_SUPPORTED)
        mono_aot_register_jit_icall ("mono_arm_start_gsharedvt_call", mono_arm_start_gsharedvt_call);
 #endif
        mono_aot_register_jit_icall ("mono_arm_unaligned_stack", mono_arm_unaligned_stack);
@@ -1159,50 +1160,6 @@ mono_arch_flush_icache (guint8 *code, gint size)
 #endif
 }
 
-typedef enum {
-       RegTypeNone,
-       /* Passed/returned in an ireg */
-       RegTypeGeneral,
-       /* Passed/returned in a pair of iregs */
-       RegTypeIRegPair,
-       /* Passed on the stack */
-       RegTypeBase,
-       /* First word in r3, second word on the stack */
-       RegTypeBaseGen,
-       /* FP value passed in either an ireg or a vfp reg */
-       RegTypeFP,
-       RegTypeStructByVal,
-       RegTypeStructByAddr,
-       /* gsharedvt argument passed by addr in greg */
-       RegTypeGSharedVtInReg,
-       /* gsharedvt argument passed by addr on stack */
-       RegTypeGSharedVtOnStack,
-       RegTypeHFA
-} ArgStorage;
-
-typedef struct {
-       gint32  offset;
-       guint16 vtsize; /* in param area */
-       /* RegTypeHFA */
-       int esize;
-       /* RegTypeHFA */
-       int nregs;
-       guint8  reg;
-       ArgStorage  storage;
-       gint32  struct_size;
-       guint8  size    : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
-} ArgInfo;
-
-typedef struct {
-       int nargs;
-       guint32 stack_usage;
-       /* The index of the vret arg in the argument list for RegTypeStructByAddr */
-       int vret_arg_index;
-       ArgInfo ret;
-       ArgInfo sig_cookie;
-       ArgInfo args [1];
-} CallInfo;
-
 #define DEBUG(a)
 
 static void inline
@@ -2353,13 +2310,13 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
                        if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
                                MONO_INST_NEW (cfg, ins, OP_MOVE);
                                ins->dreg = mono_alloc_ireg (cfg);
-                               ins->sreg1 = in->dreg + 1;
+                               ins->sreg1 = MONO_LVREG_LS (in->dreg);
                                MONO_ADD_INS (cfg->cbb, ins);
                                mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
 
                                MONO_INST_NEW (cfg, ins, OP_MOVE);
                                ins->dreg = mono_alloc_ireg (cfg);
-                               ins->sreg1 = in->dreg + 2;
+                               ins->sreg1 = MONO_LVREG_MS (in->dreg);
                                MONO_ADD_INS (cfg->cbb, ins);
                                mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
                        } else if (!t->byref && ((t->type == MONO_TYPE_R8) || (t->type == MONO_TYPE_R4))) {
@@ -2375,6 +2332,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
                                        } else {
                                                int creg;
 
+                                               cfg->param_area = MAX (cfg->param_area, 8);
                                                MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ARMREG_SP, (cfg->param_area - 8), in->dreg);
                                                creg = mono_alloc_ireg (cfg);
                                                MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, creg, ARMREG_SP, (cfg->param_area - 8));
@@ -2396,6 +2354,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
                                        } else {
                                                int creg;
 
+                                               cfg->param_area = MAX (cfg->param_area, 8);
                                                MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ARMREG_SP, (cfg->param_area - 8), in->dreg);
                                                creg = mono_alloc_ireg (cfg);
                                                MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, creg, ARMREG_SP, (cfg->param_area - 8));
@@ -2456,10 +2415,10 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
                        break;
                case RegTypeBaseGen:
                        if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
-                               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, ainfo->offset, (G_BYTE_ORDER == G_BIG_ENDIAN) ? in->dreg + 1 : in->dreg + 2);
+                               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, ainfo->offset, (G_BYTE_ORDER == G_BIG_ENDIAN) ? MONO_LVREG_LS (in->dreg) : MONO_LVREG_MS (in->dreg));
                                MONO_INST_NEW (cfg, ins, OP_MOVE);
                                ins->dreg = mono_alloc_ireg (cfg);
-                               ins->sreg1 = G_BYTE_ORDER == G_BIG_ENDIAN ? in->dreg + 2 : in->dreg + 1;
+                               ins->sreg1 = G_BYTE_ORDER == G_BIG_ENDIAN ? MONO_LVREG_MS (in->dreg) : MONO_LVREG_LS (in->dreg);
                                MONO_ADD_INS (cfg->cbb, ins);
                                mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ARMREG_R3, FALSE);
                        } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
@@ -2467,6 +2426,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
 
                                /* This should work for soft-float as well */
 
+                               cfg->param_area = MAX (cfg->param_area, 8);
                                MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ARMREG_SP, (cfg->param_area - 8), in->dreg);
                                creg = mono_alloc_ireg (cfg);
                                mono_call_inst_add_outarg_reg (cfg, call, creg, ARMREG_R3, FALSE);
@@ -2657,8 +2617,8 @@ mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
                                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;
+                               ins->sreg1 = MONO_LVREG_LS (val->dreg);
+                               ins->sreg2 = MONO_LVREG_MS (val->dreg);
                                MONO_ADD_INS (cfg->cbb, ins);
                        }
                        return;
@@ -3463,11 +3423,14 @@ loop_start:
                case OP_IOR_IMM:
                case OP_IXOR_IMM:
                        if ((imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount)) < 0) {
+                               int opcode2 = mono_op_imm_to_op (ins->opcode);
                                ADD_NEW_INS (cfg, temp, OP_ICONST);
                                temp->inst_c0 = ins->inst_imm;
                                temp->dreg = mono_alloc_ireg (cfg);
                                ins->sreg2 = temp->dreg;
-                               ins->opcode = mono_op_imm_to_op (ins->opcode);
+                               if (opcode2 == -1)
+                                       g_error ("mono_op_imm_to_op failed for %s\n", mono_inst_name (ins->opcode));
+                               ins->opcode = opcode2;
                        }
                        if (ins->opcode == OP_SBB || ins->opcode == OP_ISBB || ins->opcode == OP_SUBCC)
                                goto loop_start;
@@ -3507,13 +3470,17 @@ loop_start:
                case OP_IDIV_IMM:
                case OP_IDIV_UN_IMM:
                case OP_IREM_IMM:
-               case OP_IREM_UN_IMM:
+               case OP_IREM_UN_IMM: {
+                       int opcode2 = mono_op_imm_to_op (ins->opcode);
                        ADD_NEW_INS (cfg, temp, OP_ICONST);
                        temp->inst_c0 = ins->inst_imm;
                        temp->dreg = mono_alloc_ireg (cfg);
                        ins->sreg2 = temp->dreg;
-                       ins->opcode = mono_op_imm_to_op (ins->opcode);
+                       if (opcode2 == -1)
+                               g_error ("mono_op_imm_to_op failed for %s\n", mono_inst_name (ins->opcode));
+                       ins->opcode = opcode2;
                        break;
+               }
                case OP_LOCALLOC_IMM:
                        ADD_NEW_INS (cfg, temp, OP_ICONST);
                        temp->inst_c0 = ins->inst_imm;
@@ -3690,8 +3657,8 @@ mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *long_ins)
 
        if (long_ins->opcode == OP_LNEG) {
                ins = long_ins;
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSBS_IMM, ins->dreg + 1, ins->sreg1 + 1, 0);
-               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSC_IMM, ins->dreg + 2, ins->sreg1 + 2, 0);
+               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSBS_IMM, MONO_LVREG_LS (ins->dreg), MONO_LVREG_LS (ins->sreg1), 0);
+               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSC_IMM, MONO_LVREG_MS (ins->dreg), MONO_LVREG_MS (ins->sreg1), 0);
                NULLIFY_INS (ins);
        }
 }
@@ -5102,13 +5069,17 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 
                        if (IS_HARD_FLOAT)
                                code = emit_float_args (cfg, call, code, &max_len, &offset);
-                       if (!arm_is_imm12 (ins->inst_offset))
+                       if (!arm_is_imm12 (ins->inst_offset)) {
+                               /* sreg1 might be IP */
+                               ARM_MOV_REG_REG (code, ARMREG_LR, ins->sreg1);
                                code = mono_arm_emit_load_imm (code, ARMREG_IP, ins->inst_offset);
-                       ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
-                       if (!arm_is_imm12 (ins->inst_offset))
-                               ARM_LDR_REG_REG (code, ARMREG_PC, ins->sreg1, ARMREG_IP);
-                       else
+                               ARM_ADD_REG_REG (code, ARMREG_IP, ARMREG_IP, ARMREG_LR);
+                               ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
+                               ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, 0);
+                       } else {
+                               ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
                                ARM_LDR_IMM (code, ARMREG_PC, ins->sreg1, ins->inst_offset);
+                       }
                        ins->flags |= MONO_INST_GC_CALLSITE;
                        ins->backend.pc_offset = code - cfg->native_code;
                        code = emit_move_return_value (cfg, ins, code);
@@ -5788,10 +5759,10 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
 #endif
                                ARM_CMPD (code, vfp_scratch2, vfp_scratch1);
                                ARM_FMSTAT (code);
-                               EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_GT, "ArithmeticException");
+                               EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_GT, "OverflowException");
                                ARM_CMPD (code, ins->sreg1, ins->sreg1);
                                ARM_FMSTAT (code);
-                               EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_VS, "ArithmeticException");
+                               EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_VS, "OverflowException");
                                ARM_CPYD (code, ins->dreg, ins->sreg1);
 
                                code = mono_arm_emit_vfp_scratch_restore (cfg, code, vfp_scratch1);
@@ -6561,7 +6532,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                code = mono_arm_load_jumptable_entry_addr (code, jte, ARMREG_LR);
 #else
                ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
-               ARM_B (code, 2);
+               ARM_B (code, 1);
                *(gpointer*)code = &single_step_tramp;
                code += 4;
                *(gpointer*)code = breakpoint_tramp;
@@ -6791,8 +6762,7 @@ mono_arch_emit_exceptions (MonoCompile *cfg)
                        }
                        arm_patch (ip, code);
 
-                       exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
-                       g_assert (exc_class);
+                       exc_class = mono_class_load_from_name (mono_defaults.corlib, "System", patch_info->data.name);
 
                        ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_LR);
 #ifdef USE_JUMP_TABLES
@@ -6814,7 +6784,7 @@ mono_arch_emit_exceptions (MonoCompile *cfg)
                        patch_info->ip.i = code - cfg->native_code;
                        ARM_BL (code, 0);
                        cfg->thunk_area += THUNK_SIZE;
-                       *(guint32*)(gpointer)code = exc_class->type_token;
+                       *(guint32*)(gpointer)code = exc_class->type_token - MONO_TOKEN_TYPE_DEF;
                        code += 4;
 #endif
                        break;
@@ -7651,8 +7621,8 @@ mono_arch_opcode_supported (int opcode)
        }
 }
 
-#if defined(ENABLE_GSHAREDVT)
-
-#include "../../../mono-extensions/mono/mini/mini-arm-gsharedvt.c"
-
-#endif /* !MONOTOUCH */
+CallInfo*
+mono_arch_get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
+{
+       return get_call_info (mp, sig);
+}