2009-05-14 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini-ppc.c
index 4fbba1a4b80f803708fb6a53bfeb50ad24e4d585..557523944959e79c1ebe451b17bc36d923f4cbd6 100644 (file)
@@ -373,17 +373,6 @@ mono_arch_get_vcall_slot (guint8 *code_ptr, gpointer *regs, int *displacement)
        return o;
 }
 
-gpointer*
-mono_arch_get_vcall_slot_addr (guint8 *code, gpointer *regs)
-{
-       gpointer vt;
-       int displacement;
-       vt = mono_arch_get_vcall_slot (code, regs, &displacement);
-       if (!vt)
-               return NULL;
-       return (gpointer*)((char*)vt + displacement);
-}
-
 #define MAX_ARCH_DELEGATE_PARAMS 7
 
 gpointer
@@ -2085,6 +2074,48 @@ mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
        }
 }
 
+void
+mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *ins)
+{
+       switch (ins->opcode) {
+       case OP_LADD_OVF:
+               /* ADC sets the condition code */
+               MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
+               MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
+               NULLIFY_INS (ins);
+               break;
+       case OP_LADD_OVF_UN:
+               /* ADC sets the condition code */
+               MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
+               MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
+               NULLIFY_INS (ins);
+               break;
+       case OP_LSUB_OVF:
+               /* SBB sets the condition code */
+               MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
+               MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
+               NULLIFY_INS (ins);
+               break;
+       case OP_LSUB_OVF_UN:
+               /* SBB sets the condition code */
+               MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
+               MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
+               NULLIFY_INS (ins);
+               break;
+       case OP_LNEG:
+               /* This is the old version from inssel-long32.brg */
+               MONO_EMIT_NEW_UNALU (cfg, OP_INOT, ins->dreg + 1, ins->sreg1 + 1);
+               MONO_EMIT_NEW_UNALU (cfg, OP_INOT, ins->dreg + 2, ins->sreg1 + 2);
+               /* ADC sets the condition codes */
+               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, ins->dreg + 1, ins->dreg + 1, 1);
+               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, ins->dreg + 2, ins->dreg + 2, 0);
+               NULLIFY_INS (ins);
+               break;
+       default:
+               break;
+       }
+}
+
 /* 
  * the branch_b0_table should maintain the order of these
  * opcodes.
@@ -2603,12 +2634,12 @@ handle_thunk (int absolute, guchar *code, const guchar *target) {
        pdata.found = 0;
 
        mono_domain_lock (domain);
-       mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
+       mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
 
        if (!pdata.found) {
                /* this uses the first available slot */
                pdata.found = 2;
-               mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
+               mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
        }
        mono_domain_unlock (domain);
 
@@ -3185,12 +3216,12 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        ppc_load_reg_indexed (code, ins->dreg, ins->sreg2, ins->inst_basereg);
                        break;
                case OP_LOADI4_MEMINDEX:
-               case OP_LOADU4_MEMINDEX:
-                       ppc_lwzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
 #ifdef __mono_ppc64__
-                       if (ins->opcode == OP_LOADI4_MEMINDEX)
-                               ppc_extsb (code, ins->dreg, ins->dreg);
+                       ppc_lwax (code, ins->dreg, ins->sreg2, ins->inst_basereg);
+                       break;
 #endif
+               case OP_LOADU4_MEMINDEX:
+                       ppc_lwzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
                        break;
                case OP_LOADU2_MEMINDEX:
                        ppc_lhzx (code, ins->dreg, ins->sreg2, ins->inst_basereg);
@@ -4218,6 +4249,39 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        break;
                }
 #endif
+               case OP_ATOMIC_CAS_I4:
+               CASE_PPC64 (OP_ATOMIC_CAS_I8) {
+                       int location = ins->sreg1;
+                       int value = ins->sreg2;
+                       int comparand = ins->sreg3;
+                       guint8 *start, *not_equal, *lost_reservation;
+
+                       start = code;
+                       if (ins->opcode == OP_ATOMIC_CAS_I4)
+                               ppc_lwarx (code, ppc_r0, 0, location);
+#ifdef __mono_ppc64__
+                       else
+                               ppc_ldarx (code, ppc_r0, 0, location);
+#endif
+                       ppc_cmp (code, 0, ins->opcode == OP_ATOMIC_CAS_I4 ? 0 : 1, ppc_r0, comparand);
+
+                       not_equal = code;
+                       ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
+                       if (ins->opcode == OP_ATOMIC_CAS_I4)
+                               ppc_stwcxd (code, value, 0, location);
+#ifdef __mono_ppc64__
+                       else
+                               ppc_stdcxd (code, value, 0, location);
+#endif
+
+                       lost_reservation = code;
+                       ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
+                       ppc_patch (lost_reservation, start);
+
+                       ppc_patch (not_equal, code);
+                       ppc_mr (code, ins->dreg, ppc_r0);
+                       break;
+               }
 
                default:
                        g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
@@ -4995,6 +5059,8 @@ mono_arch_emit_exceptions (MonoCompile *cfg)
                        break;
                }
                case MONO_PATCH_INFO_EXC: {
+                       MonoClass *exc_class;
+
                        unsigned char *ip = patch_info->ip.i + cfg->native_code;
                        i = exception_id_by_name (patch_info->data.target);
                        if (exc_throw_pos [i]) {
@@ -5004,19 +5070,24 @@ mono_arch_emit_exceptions (MonoCompile *cfg)
                        } else {
                                exc_throw_pos [i] = code;
                        }
+
+                       exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
+                       g_assert (exc_class);
+
                        ppc_patch (ip, code);
                        /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
-                       ppc_load (code, ppc_r3, patch_info->data.target);
-                       /* we got here from a conditional call, so the calling ip is set in lr already */
+                       ppc_load (code, ppc_r3, exc_class->type_token);
+                       /* we got here from a conditional call, so the calling ip is set in lr */
+                       ppc_mflr (code, ppc_r4);
                        patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
-                       patch_info->data.name = "mono_arch_throw_exception_by_name";
+                       patch_info->data.name = "mono_arch_throw_corlib_exception";
                        patch_info->ip.i = code - cfg->native_code;
                        if (FORCE_INDIR_CALL || cfg->method->dynamic) {
                                ppc_load_func (code, ppc_r0, 0);
                                ppc_mtctr (code, ppc_r0);
                                ppc_bcctr (code, PPC_BR_ALWAYS, 0);
                        } else {
-                               ppc_b (code, 0);
+                               ppc_bl (code, 0);
                        }
                        break;
                }
@@ -5238,13 +5309,15 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
                        if (item->check_target_idx) {
                                if (!item->compare_done)
                                        item->chunk_size += CMP_SIZE;
-                               if (fail_tramp)
+                               if (item->has_target_code)
                                        item->chunk_size += BR_SIZE + JUMP_IMM32_SIZE;
                                else
                                        item->chunk_size += LOADSTORE_SIZE + BR_SIZE + JUMP_IMM_SIZE;
                        } else {
                                if (fail_tramp) {
                                        item->chunk_size += CMP_SIZE + BR_SIZE + JUMP_IMM32_SIZE * 2;
+                                       if (!item->has_target_code)
+                                               item->chunk_size += LOADSTORE_SIZE;
                                } else {
                                        item->chunk_size += LOADSTORE_SIZE + JUMP_IMM_SIZE;
 #if ENABLE_WRONG_METHOD_CHECK
@@ -5263,7 +5336,7 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
        } else {
                /* the initial load of the vtable address */
                size += PPC_LOAD_SEQUENCE_LENGTH + LOADSTORE_SIZE;
-               code = mono_code_manager_reserve (domain->code_mp, size);
+               code = mono_domain_code_reserve (domain, size);
        }
        start = code;
        if (!fail_tramp) {
@@ -5289,7 +5362,7 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
                                }
                                item->jmp_code = code;
                                ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
-                               if (fail_tramp) {
+                               if (item->has_target_code) {
                                        ppc_load (code, ppc_r0, item->value.target_code);
                                } else {
                                        ppc_load_reg (code, ppc_r0, (sizeof (gpointer) * item->value.vtable_slot), ppc_r11);
@@ -5303,7 +5376,13 @@ mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckI
                                        ppc_compare_log (code, 0, MONO_ARCH_IMT_REG, ppc_r0);
                                        item->jmp_code = code;
                                        ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
-                                       ppc_load (code, ppc_r0, item->value.target_code);
+                                       if (item->has_target_code) {
+                                               ppc_load (code, ppc_r0, item->value.target_code);
+                                       } else {
+                                               g_assert (vtable);
+                                               ppc_load (code, ppc_r0, & (vtable->vtable [item->value.vtable_slot]));
+                                               ppc_load_reg_indexed (code, ppc_r0, 0, ppc_r0);
+                                       }
                                        ppc_mtctr (code, ppc_r0);
                                        ppc_bcctr (code, PPC_BR_ALWAYS, 0);
                                        ppc_patch (item->jmp_code, code);