2007-04-25 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini-ppc.c
index c5d4f92f46f468de0bd672d1fbb8eb455b2e0819..159b77bbc663ac1a9fe0c41ef2bc8c7d418e399e 100644 (file)
@@ -21,6 +21,8 @@
 #include <sys/sysctl.h>
 #endif
 
+#define FORCE_INDIR_CALL 1
+
 enum {
        TLS_MODE_DETECT,
        TLS_MODE_FAILED,
@@ -410,7 +412,7 @@ enum {
 
 typedef struct {
        gint32  offset;
-       guint16 vtsize; /* in param area */
+       guint32 vtsize; /* in param area */
        guint8  reg;
        guint8  regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
        guint8  size    : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
@@ -620,6 +622,7 @@ calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
 #else
                        add_general (&gr, &stack_size, cinfo->args + n, TRUE);
                        cinfo->args [n].regtype = RegTypeStructByAddr;
+                       cinfo->args [n].vtsize = size;
 #endif
                        n++;
                        break;
@@ -649,6 +652,7 @@ calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
 #else
                        add_general (&gr, &stack_size, cinfo->args + n, TRUE);
                        cinfo->args [n].regtype = RegTypeStructByAddr;
+                       cinfo->args [n].vtsize = size;
 #endif
                        n++;
                        break;
@@ -996,9 +1000,17 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call,
                                if (arg->type == STACK_I8)
                                        call->used_iregs |= 1 << (ainfo->reg + 1);
                        } else if (ainfo->regtype == RegTypeStructByAddr) {
-                               /* FIXME: where si the data allocated? */
-                               arg->backend.reg3 = ainfo->reg;
-                               call->used_iregs |= 1 << ainfo->reg;
+                               if (ainfo->offset) {
+                                       MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
+                                       arg->opcode = OP_OUTARG_MEMBASE;
+                                       ai->reg = ainfo->reg;
+                                       ai->size = sizeof (gpointer);
+                                       ai->offset = ainfo->offset;
+                                       arg->backend.data = ai;
+                               } else {
+                                       arg->backend.reg3 = ainfo->reg;
+                                       call->used_iregs |= 1 << ainfo->reg;
+                               }
                        } else if (ainfo->regtype == RegTypeStructByVal) {
                                int cur_reg;
                                MonoPPCArgInfo *ai = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoPPCArgInfo));
@@ -1358,15 +1370,8 @@ peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
                                        ins->inst_basereg == last_ins->inst_destbasereg &&
                                        ins->inst_offset == last_ins->inst_offset) {
-                               if (ins->dreg == last_ins->sreg1) {
-                                       last_ins->next = ins->next;                             
-                                       ins = ins->next;                                
-                                       continue;
-                               } else {
-                                       //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
-                                       ins->opcode = OP_MOVE;
-                                       ins->sreg1 = last_ins->sreg1;
-                               }
+                               ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? CEE_CONV_I1 : CEE_CONV_U1;
+                               ins->sreg1 = last_ins->sreg1;                           
                        }
                        break;
                case OP_LOADU2_MEMBASE:
@@ -1374,15 +1379,8 @@ peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
                                        ins->inst_basereg == last_ins->inst_destbasereg &&
                                        ins->inst_offset == last_ins->inst_offset) {
-                               if (ins->dreg == last_ins->sreg1) {
-                                       last_ins->next = ins->next;                             
-                                       ins = ins->next;                                
-                                       continue;
-                               } else {
-                                       //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
-                                       ins->opcode = OP_MOVE;
-                                       ins->sreg1 = last_ins->sreg1;
-                               }
+                               ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? CEE_CONV_I2 : CEE_CONV_U2;
+                               ins->sreg1 = last_ins->sreg1;                           
                        }
                        break;
                case CEE_CONV_I4:
@@ -1462,8 +1460,6 @@ branch_b1_table [] = {
        PPC_BR_LT 
 };
 
-static const char*const * ins_spec = ppcg4;
-
 static void
 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
 {
@@ -1567,8 +1563,8 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
        int imm;
 
        /* setup the virtual reg allocator */
-       if (bb->max_ireg > cfg->rs->next_vireg)
-               cfg->rs->next_vireg = bb->max_ireg;
+       if (bb->max_vreg > cfg->rs->next_vreg)
+               cfg->rs->next_vreg = bb->max_vreg;
 
        ins = bb->code;
        while (ins) {
@@ -1700,7 +1696,7 @@ loop_start:
                ins = ins->next;
        }
        bb->last_ins = last_ins;
-       bb->max_ireg = cfg->rs->next_vireg;
+       bb->max_vreg = cfg->rs->next_vreg;
        
 }
 
@@ -1946,10 +1942,10 @@ ppc_patch (guchar *code, guchar *target)
                return;
        }
 
-       if (prim == 15 || ins == 0x4e800021) {
+       if (prim == 15 || ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
                guint32 *seq;
-               /* the trampoline code will try to patch the blrl */
-               if (ins == 0x4e800021) {
+               /* the trampoline code will try to patch the blrl, blr, bcctr */
+               if (ins == 0x4e800021 || ins == 0x4e800020 || ins == 0x4e800420) {
                        code -= 12;
                }
                /* this is the lis/ori/mtlr/blrl sequence */
@@ -1957,7 +1953,7 @@ ppc_patch (guchar *code, guchar *target)
                g_assert ((seq [0] >> 26) == 15);
                g_assert ((seq [1] >> 26) == 24);
                g_assert ((seq [2] >> 26) == 31);
-               g_assert (seq [3] == 0x4e800021);
+               g_assert (seq [3] == 0x4e800021 || seq [3] == 0x4e800020 || seq [3] == 0x4e800420);
                /* FIXME: make this thread safe */
                ppc_lis (code, ppc_r0, (guint32)(target) >> 16);
                ppc_ori (code, ppc_r0, ppc_r0, (guint32)(target) & 0xffff);
@@ -2004,7 +2000,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
        while (ins) {
                offset = code - cfg->native_code;
 
-               max_len = ((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN];
+               max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
 
                if (offset > (cfg->code_size - max_len - 16)) {
                        cfg->code_size *= 2;
@@ -2355,7 +2351,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (!(ins->inst_imm & 0xffff0000)) {
                                ppc_ori (code, ins->sreg1, ins->dreg, ins->inst_imm);
                        } else if (!(ins->inst_imm & 0xffff)) {
-                               ppc_oris (code, ins->sreg1, ins->dreg, ((guint32)(ins->inst_imm) >> 16));
+                               ppc_oris (code, ins->dreg, ins->sreg1, ((guint32)(ins->inst_imm) >> 16));
                        } else {
                                g_assert_not_reached ();
                        }
@@ -2525,7 +2521,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
                        else
                                mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
-                       if (cfg->method->dynamic) {
+                       if (FORCE_INDIR_CALL || cfg->method->dynamic) {
                                ppc_lis (code, ppc_r0, 0);
                                ppc_ori (code, ppc_r0, ppc_r0, 0);
                                ppc_mtlr (code, ppc_r0);
@@ -2594,7 +2590,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        ppc_mr (code, ppc_r3, ins->sreg1);
                        mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
                                             (gpointer)"mono_arch_throw_exception");
-                       if (cfg->method->dynamic) {
+                       if (FORCE_INDIR_CALL || cfg->method->dynamic) {
                                ppc_lis (code, ppc_r0, 0);
                                ppc_ori (code, ppc_r0, ppc_r0, 0);
                                ppc_mtlr (code, ppc_r0);
@@ -2609,7 +2605,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        ppc_mr (code, ppc_r3, ins->sreg1);
                        mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
                                             (gpointer)"mono_arch_rethrow_exception");
-                       if (cfg->method->dynamic) {
+                       if (FORCE_INDIR_CALL || cfg->method->dynamic) {
                                ppc_lis (code, ppc_r0, 0);
                                ppc_ori (code, ppc_r0, ppc_r0, 0);
                                ppc_mtlr (code, ppc_r0);
@@ -2888,7 +2884,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        g_assert_not_reached ();
                        break;
                case OP_FCOMPARE:
-                       ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
+                       ppc_fcmpu (code, 0, ins->sreg1, ins->sreg2);
                        break;
                case OP_FCEQ:
                        ppc_fcmpo (code, 0, ins->sreg1, ins->sreg2);
@@ -2929,6 +2925,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
                        break;
                case OP_FBLT:
+                       ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
                        EMIT_COND_BRANCH (ins, CEE_BLT - CEE_BEQ);
                        break;
                case OP_FBLT_UN:
@@ -2936,6 +2933,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        EMIT_COND_BRANCH (ins, CEE_BLT_UN - CEE_BEQ);
                        break;
                case OP_FBGT:
+                       ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
                        EMIT_COND_BRANCH (ins, CEE_BGT - CEE_BEQ);
                        break;
                case OP_FBGT_UN:
@@ -2943,12 +2941,14 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        EMIT_COND_BRANCH (ins, CEE_BGT_UN - CEE_BEQ);
                        break;
                case OP_FBGE:
+                       ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
                        EMIT_COND_BRANCH (ins, CEE_BGE - CEE_BEQ);
                        break;
                case OP_FBGE_UN:
                        EMIT_COND_BRANCH (ins, CEE_BGE_UN - CEE_BEQ);
                        break;
                case OP_FBLE:
+                       ppc_bc (code, PPC_BR_TRUE, PPC_BR_SO, 2);
                        EMIT_COND_BRANCH (ins, CEE_BLE - CEE_BEQ);
                        break;
                case OP_FBLE_UN:
@@ -3163,7 +3163,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                        max_offset += 6; 
 
                while (ins) {
-                       max_offset += ((guint8 *)ins_spec [ins->opcode])[MONO_INST_LEN];
+                       max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
                        ins = ins->next;
                }
        }
@@ -3322,9 +3322,17 @@ register.  Should this case include linux/ppc?
                                        code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, doffset, ppc_r11, ainfo->offset + soffset);
                                }
                        } else if (ainfo->regtype == RegTypeStructByAddr) {
+                               /* if it was originally a RegTypeBase */
+                               if (ainfo->offset) {
+                                       /* load the previous stack pointer in r11 */
+                                       ppc_lwz (code, ppc_r11, 0, ppc_sp);
+                                       ppc_lwz (code, ppc_r11, ainfo->offset, ppc_r11);
+                               } else {
+                                       ppc_mr (code, ppc_r11, ainfo->reg);
+                               }
                                g_assert (ppc_is_imm16 (inst->inst_offset));
-                               /* FIXME: handle overrun! with struct sizes not multiple of 4 */
-                               code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
+                               code = emit_memcpy (code, ainfo->vtsize, inst->inst_basereg, inst->inst_offset, ppc_r11, 0);
+                               /*g_print ("copy in %s: %d bytes from %d to offset: %d\n", method->name, ainfo->vtsize, ainfo->reg, inst->inst_offset);*/
                        } else
                                g_assert_not_reached ();
                }
@@ -3334,7 +3342,14 @@ register.  Should this case include linux/ppc?
        if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
                ppc_load (code, ppc_r3, cfg->domain);
                mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
-               ppc_bl (code, 0);
+               if (FORCE_INDIR_CALL || cfg->method->dynamic) {
+                       ppc_lis (code, ppc_r0, 0);
+                       ppc_ori (code, ppc_r0, ppc_r0, 0);
+                       ppc_mtlr (code, ppc_r0);
+                       ppc_blrl (code);
+               } else {
+                       ppc_bl (code, 0);
+               }
        }
 
        if (method->save_lmf) {
@@ -3345,7 +3360,7 @@ register.  Should this case include linux/ppc?
                } else {
                        mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
                                     (gpointer)"mono_get_lmf_addr");
-                       if (cfg->method->dynamic) {
+                       if (FORCE_INDIR_CALL || cfg->method->dynamic) {
                                ppc_lis (code, ppc_r0, 0);
                                ppc_ori (code, ppc_r0, ppc_r0, 0);
                                ppc_mtlr (code, ppc_r0);
@@ -3534,7 +3549,7 @@ mono_arch_emit_exceptions (MonoCompile *cfg)
                if (patch_info->type == MONO_PATCH_INFO_EXC) {
                        i = exception_id_by_name (patch_info->data.target);
                        if (!exc_throw_found [i]) {
-                               max_epilog_size += 12;
+                               max_epilog_size += 24;
                                exc_throw_found [i] = TRUE;
                        }
                } else if (patch_info->type == MONO_PATCH_INFO_BB_OVF)
@@ -3543,7 +3558,7 @@ mono_arch_emit_exceptions (MonoCompile *cfg)
                        MonoOvfJump *ovfj = patch_info->data.target;
                        i = exception_id_by_name (ovfj->data.exception);
                        if (!exc_throw_found [i]) {
-                               max_epilog_size += 12;
+                               max_epilog_size += 24;
                                exc_throw_found [i] = TRUE;
                        }
                        max_epilog_size += 8;
@@ -3612,7 +3627,14 @@ mono_arch_emit_exceptions (MonoCompile *cfg)
                        patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
                        patch_info->data.name = "mono_arch_throw_exception_by_name";
                        patch_info->ip.i = code - cfg->native_code;
-                       ppc_b (code, 0);
+                       if (FORCE_INDIR_CALL || cfg->method->dynamic) {
+                               ppc_lis (code, ppc_r0, 0);
+                               ppc_ori (code, ppc_r0, ppc_r0, 0);
+                               ppc_mtctr (code, ppc_r0);
+                               ppc_bcctr (code, PPC_BR_ALWAYS, 0);
+                       } else {
+                               ppc_b (code, 0);
+                       }
                        break;
                }
                default: