Update to the latest version of the LLVM mono branch.
[mono.git] / mono / mini / mini-ppc.c
index 5176697ef9c6ac8c129266ff45eded40ef6f45c2..90240f63e5b6b31e228f6b16c0031290157b9057 100644 (file)
@@ -376,53 +376,6 @@ mono_ppc_is_direct_call_sequence (guint32 *code)
 #endif
 }
 
-gpointer
-mono_arch_get_vcall_slot (guint8 *code_ptr, mgreg_t *regs, int *displacement)
-{
-       char *o = NULL;
-       int reg, offset = 0;
-       guint32* code = (guint32*)code_ptr;
-       mgreg_t *r = (mgreg_t*)regs;
-
-       *displacement = 0;
-
-       /* This is the 'blrl' instruction */
-       --code;
-
-       /* Sanity check: instruction must be 'blrl' */
-       if (*code != 0x4e800021)
-               return NULL;
-
-       if (mono_ppc_is_direct_call_sequence (code))
-               return NULL;
-
-       /* FIXME: more sanity checks here */
-       /* OK, we're now at the 'blrl' instruction. Now walk backwards
-       till we get to a 'mtlr rA' */
-       for (; --code;) {
-               if((*code & 0x7c0803a6) == 0x7c0803a6) {
-                       gint16 soff;
-                       /* Here we are: we reached the 'mtlr rA'.
-                       Extract the register from the instruction */
-                       reg = (*code & 0x03e00000) >> 21;
-                       --code;
-                       /* ok, this is a lwz reg, offset (vtreg) 
-                        * it is emitted with:
-                        * ppc_emit32 (c, (32 << 26) | ((D) << 21) | ((a) << 16) | (guint16)(d))
-                        */
-                       soff = (*code & 0xffff);
-                       offset = soff;
-                       reg = (*code >> 16) & 0x1f;
-                       g_assert (reg != ppc_r1);
-                       /*g_print ("patching reg is %d\n", reg);*/
-                       o = (gpointer)(gsize)r [reg];
-                       break;
-               }
-       }
-       *displacement = offset;
-       return o;
-}
-
 #define MAX_ARCH_DELEGATE_PARAMS 7
 
 static gpointer
@@ -555,13 +508,10 @@ mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_targe
 }
 
 gpointer
-mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, mgreg_t *regs, guint8 *code)
+mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
 {
        mgreg_t *r = (mgreg_t*)regs;
 
-       /* FIXME: handle returning a struct */
-       if (MONO_TYPE_ISSTRUCT (sig->ret))
-               return (gpointer)(gsize)r [ppc_r4];
        return (gpointer)(gsize)r [ppc_r3];
 }
 
@@ -614,7 +564,16 @@ linux_find_auxv (int *count)
 void
 mono_arch_cpu_init (void)
 {
-#ifdef __APPLE__
+}
+
+/*
+ * Initialize architecture specific code.
+ */
+void
+mono_arch_init (void)
+{
+#if defined(MONO_CROSS_COMPILE)
+#elif defined(__APPLE__)
        int mib [3];
        size_t len;
        mib [0] = CTL_HW;
@@ -668,7 +627,6 @@ mono_arch_cpu_init (void)
 #elif defined(G_COMPILER_CODEWARRIOR)
        cachelinesize = 32;
        cachelineinc = 32;
-#elif defined(MONO_CROSS_COMPILE)
 #else
 //#error Need a way to get cache line size
 #endif
@@ -679,14 +637,6 @@ mono_arch_cpu_init (void)
 
        if (mono_cpu_count () > 1)
                cpu_hw_caps |= PPC_SMP_CAPABLE;
-}
-
-/*
- * Initialize architecture specific code.
- */
-void
-mono_arch_init (void)
-{
        InitializeCriticalSection (&mini_arch_mutex);
 
        ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
@@ -942,6 +892,8 @@ typedef struct {
        guint32 struct_ret;
        ArgInfo ret;
        ArgInfo sig_cookie;
+       gboolean vtype_retaddr;
+       int vret_arg_index;
        ArgInfo args [1];
 } CallInfo;
 
@@ -1009,9 +961,9 @@ has_only_a_r48_field (MonoClass *klass)
 #endif
 
 static CallInfo*
-calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
+calculate_sizes (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gboolean is_pinvoke)
 {
-       guint i, fr, gr;
+       guint i, fr, gr, pstart;
        int n = sig->hasthis + sig->param_count;
        MonoType *simpletype;
        guint32 stack_size = 0;
@@ -1022,17 +974,45 @@ calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
 
        /* FIXME: handle returning a struct */
        if (MONO_TYPE_ISSTRUCT (sig->ret)) {
-               add_general (&gr, &stack_size, &cinfo->ret, TRUE);
-               cinfo->struct_ret = PPC_FIRST_ARG_REG;
+               cinfo->vtype_retaddr = TRUE;
        }
 
+       pstart = 0;
        n = 0;
-       if (sig->hasthis) {
-               add_general (&gr, &stack_size, cinfo->args + n, TRUE);
-               n++;
+       /*
+        * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
+        * the first argument, allowing 'this' to be always passed in the first arg reg.
+        * Also do this if the first argument is a reference type, since virtual calls
+        * are sometimes made using calli without sig->hasthis set, like in the delegate
+        * invoke wrappers.
+        */
+       if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (gsctx, sig->params [0]))))) {
+               if (sig->hasthis) {
+                       add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
+                       n ++;
+               } else {
+                       add_general (&gr, &stack_size, &cinfo->args [sig->hasthis + 0], TRUE);
+                       pstart = 1;
+                       n ++;
+               }
+               add_general (&gr, &stack_size, &cinfo->ret, TRUE);
+               cinfo->struct_ret = cinfo->ret.reg;
+               cinfo->vret_arg_index = 1;
+       } else {
+               /* this */
+               if (sig->hasthis) {
+                       add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
+                       n ++;
+               }
+
+               if (cinfo->vtype_retaddr) {
+                       add_general (&gr, &stack_size, &cinfo->ret, TRUE);
+                       cinfo->struct_ret = cinfo->ret.reg;
+               }
        }
+
         DEBUG(printf("params: %d\n", sig->param_count));
-       for (i = 0; i < sig->param_count; ++i) {
+       for (i = pstart; i < sig->param_count; ++i) {
                if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
                         /* Prevent implicit arguments and sig_cookie from
                           being passed in registers */
@@ -1482,6 +1462,11 @@ mono_arch_allocate_vars (MonoCompile *m)
                        }
                        if (MONO_TYPE_ISSTRUCT (sig->params [i]) && size < sizeof (gpointer))
                                size = align = sizeof (gpointer);
+                       /* 
+                        * Use at least 4/8 byte alignment, since these might be passed in registers, and
+                        * they are saved using std in the prolog.
+                        */
+                       align = sizeof (gpointer);
                        offset += align - 1;
                        offset &= ~(align - 1);
                        inst->inst_offset = offset;
@@ -1504,7 +1489,7 @@ mono_arch_allocate_vars (MonoCompile *m)
        m->stack_offset = offset;
 
        if (sig->call_convention == MONO_CALL_VARARG) {
-               CallInfo *cinfo = calculate_sizes (m->method->signature, m->method->signature->pinvoke);
+               CallInfo *cinfo = calculate_sizes (m->generic_sharing_context, m->method->signature, m->method->signature->pinvoke);
 
                m->sig_cookie = cinfo->sig_cookie.offset;
 
@@ -1550,7 +1535,7 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
        sig = call->signature;
        n = sig->param_count + sig->hasthis;
        
-       cinfo = calculate_sizes (sig, sig->pinvoke);
+       cinfo = calculate_sizes (cfg->generic_sharing_context, sig, sig->pinvoke);
 
        for (i = 0; i < n; ++i) {
                ArgInfo *ainfo = cinfo->args + i;
@@ -1677,6 +1662,8 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
        g_free (cinfo);
 }
 
+#ifndef DISABLE_JIT
+
 void
 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
 {
@@ -1792,6 +1779,8 @@ mono_arch_is_inst_imm (gint64 imm)
        return TRUE;
 }
 
+#endif /* DISABLE_JIT */
+
 /*
  * Allow tracing to work with this interface (with an optional argument)
  */
@@ -3021,7 +3010,7 @@ emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
 
        pos = 0;
 
-       cinfo = calculate_sizes (sig, sig->pinvoke);
+       cinfo = calculate_sizes (cfg->generic_sharing_context, sig, sig->pinvoke);
 
        if (MONO_TYPE_ISSTRUCT (sig->ret)) {
                ArgInfo *ainfo = &cinfo->ret;
@@ -3161,7 +3150,7 @@ ins_native_length (MonoCompile *cfg, MonoInst *ins)
 
        call = (MonoCallInst*)ins;
        sig = mono_method_signature (cfg->method);
-       cinfo = calculate_sizes (sig, sig->pinvoke);
+       cinfo = calculate_sizes (cfg->generic_sharing_context, sig, sig->pinvoke);
 
        if (MONO_TYPE_ISSTRUCT (sig->ret))
                len += 4;
@@ -3562,7 +3551,22 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        }
                        break;
                case OP_BREAK:
-                       ppc_break (code);
+                       /*
+                        * gdb does not like encountering a trap in the debugged code. So 
+                        * instead of emitting a trap, we emit a call a C function and place a 
+                        * breakpoint there.
+                        */
+                       //ppc_break (code);
+                       ppc_mr (code, ppc_r3, ins->sreg1);
+                       mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
+                                            (gpointer)"mono_break");
+                       if ((FORCE_INDIR_CALL || cfg->method->dynamic) && !cfg->compile_aot) {
+                               ppc_load_func (code, ppc_r0, 0);
+                               ppc_mtlr (code, ppc_r0);
+                               ppc_blrl (code);
+                       } else {
+                               ppc_bl (code, 0);
+                       }
                        break;
                case OP_ADDCC:
                case OP_IADDCC:
@@ -3717,7 +3721,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                ppc_sldi (code, ppc_r0, ppc_r0, 32);
 #endif
                        ppc_compare (code, 0, ins->sreg1, ppc_r0);
-                       EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "ArithmeticException");
+                       EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
                        ppc_patch (divisor_is_m1, code);
                         /* XER format: SO, OV, CA, reserved [21 bits], count [8 bits]
                         */
@@ -4476,7 +4480,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");
                        break;
                case OP_JUMP_TABLE:
-                       mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
+                       mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_c1, ins->inst_p0);
 #ifdef __mono_ppc64__
                        ppc_load_sequence (code, ins->dreg, (guint64)0x0f0f0f0f0f0f0f0fLL);
 #else
@@ -4687,7 +4691,7 @@ mono_arch_register_lowlevel_calls (void)
 
 #ifndef DISABLE_JIT
 void
-mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
+mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
 {
        MonoJumpInfo *patch_info;
        gboolean compile_aot = !run_cctors;
@@ -4843,7 +4847,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                tracing = 1;
 
        sig = mono_method_signature (method);
-       cfg->code_size = MONO_PPC_32_64_CASE (260, 384) + sig->param_count * 20;
+       cfg->code_size = 512 + sig->param_count * 32;
        code = cfg->native_code = g_malloc (cfg->code_size);
 
        cfa_offset = 0;
@@ -4927,7 +4931,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
        /* load arguments allocated to register from the stack */
        pos = 0;
 
-       cinfo = calculate_sizes (sig, sig->pinvoke);
+       cinfo = calculate_sizes (cfg->generic_sharing_context, sig, sig->pinvoke);
 
        if (MONO_TYPE_ISSTRUCT (sig->ret)) {
                ArgInfo *ainfo = &cinfo->ret;
@@ -4973,7 +4977,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                                        } else {
                                                if (ppc_is_imm32 (inst->inst_offset)) {
                                                        ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
-                                                       ppc_stb (code, ainfo->reg, ppc_r11, inst->inst_offset);
+                                                       ppc_stb (code, ainfo->reg, inst->inst_offset, ppc_r11);
                                                } else {
                                                        ppc_load (code, ppc_r11, inst->inst_offset);
                                                        ppc_stbx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
@@ -4986,7 +4990,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                                        } else {
                                                if (ppc_is_imm32 (inst->inst_offset)) {
                                                        ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
-                                                       ppc_sth (code, ainfo->reg, ppc_r11, inst->inst_offset);
+                                                       ppc_sth (code, ainfo->reg, inst->inst_offset, ppc_r11);
                                                } else {
                                                        ppc_load (code, ppc_r11, inst->inst_offset);
                                                        ppc_sthx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
@@ -5000,7 +5004,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                                        } else {
                                                if (ppc_is_imm32 (inst->inst_offset)) {
                                                        ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
-                                                       ppc_stw (code, ainfo->reg, ppc_r11, inst->inst_offset);
+                                                       ppc_stw (code, ainfo->reg, inst->inst_offset, ppc_r11);
                                                } else {
                                                        ppc_load (code, ppc_r11, inst->inst_offset);
                                                        ppc_stwx (code, ainfo->reg, inst->inst_basereg, ppc_r11);
@@ -5034,7 +5038,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                                        } else {
                                                if (ppc_is_imm32 (inst->inst_offset)) {
                                                        ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
-                                                       ppc_stptr (code, ainfo->reg, ppc_r11, inst->inst_offset);
+                                                       ppc_stptr (code, ainfo->reg, inst->inst_offset, ppc_r11);
                                                } else {
                                                        ppc_load (code, ppc_r11, inst->inst_offset);
                                                        ppc_stptr_indexed (code, ainfo->reg, inst->inst_basereg, ppc_r11);
@@ -5054,7 +5058,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                                        } else {
                                                if (ppc_is_imm32 (inst->inst_offset)) {
                                                        ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
-                                                       ppc_stb (code, ppc_r0, ppc_r11, inst->inst_offset);
+                                                       ppc_stb (code, ppc_r0, inst->inst_offset, ppc_r11);
                                                } else {
                                                        ppc_load (code, ppc_r11, inst->inst_offset);
                                                        ppc_stbx (code, ppc_r0, inst->inst_basereg, ppc_r11);
@@ -5067,7 +5071,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                                        } else {
                                                if (ppc_is_imm32 (inst->inst_offset)) {
                                                        ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
-                                                       ppc_sth (code, ppc_r0, ppc_r11, inst->inst_offset);
+                                                       ppc_sth (code, ppc_r0, inst->inst_offset, ppc_r11);
                                                } else {
                                                        ppc_load (code, ppc_r11, inst->inst_offset);
                                                        ppc_sthx (code, ppc_r0, inst->inst_basereg, ppc_r11);
@@ -5081,7 +5085,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                                        } else {
                                                if (ppc_is_imm32 (inst->inst_offset)) {
                                                        ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
-                                                       ppc_stw (code, ppc_r0, ppc_r11, inst->inst_offset);
+                                                       ppc_stw (code, ppc_r0, inst->inst_offset, ppc_r11);
                                                } else {
                                                        ppc_load (code, ppc_r11, inst->inst_offset);
                                                        ppc_stwx (code, ppc_r0, inst->inst_basereg, ppc_r11);
@@ -5119,7 +5123,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                                        } else {
                                                if (ppc_is_imm32 (inst->inst_offset)) {
                                                        ppc_addis (code, ppc_r11, inst->inst_basereg, ppc_ha(inst->inst_offset));
-                                                       ppc_stptr (code, ppc_r0, ppc_r11, inst->inst_offset);
+                                                       ppc_stptr (code, ppc_r0, inst->inst_offset, ppc_r11);
                                                } else {
                                                        ppc_load (code, ppc_r11, inst->inst_offset);
                                                        ppc_stptr_indexed (code, ppc_r0, inst->inst_basereg, ppc_r11);
@@ -5441,6 +5445,8 @@ exception_id_by_name (const char *name)
                return MONO_EXC_NULL_REF;
        if (strcmp (name, "ArrayTypeMismatchException") == 0)
                return MONO_EXC_ARRAY_TYPE_MISMATCH;
+       if (strcmp (name, "ArgumentException") == 0)
+               return MONO_EXC_ARGUMENT;
        g_error ("Unknown intrinsic exception %s\n", name);
        return 0;
 }
@@ -5917,6 +5923,16 @@ mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
        return (MonoVTable*)(gsize) r [MONO_ARCH_RGCTX_REG];
 }
 
+GSList*
+mono_arch_get_cie_program (void)
+{
+       GSList *l = NULL;
+
+       mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, ppc_r1, 0);
+
+       return l;
+}
+
 MonoInst*
 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
 {