2008-09-27 Mark Probst <mark.probst@gmail.com>
[mono.git] / mono / mini / mini-ppc.c
index a84f1edafe8cf5efaca6c8bfb21a8cf59457f5c2..bed880b6b605dd1541958e66109b97e640c957a6 100644 (file)
@@ -271,7 +271,7 @@ mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJit
        for (k = 0; k < param_count; k++) {
                
                if (csig->pinvoke)
-                       size = mono_type_native_stack_size (csig->params [k], &align);
+                       size = mono_type_native_stack_size (csig->params [k], (guint32*)&align);
                else
                        size = mini_type_stack_size (NULL, csig->params [k], &align);
 
@@ -577,11 +577,12 @@ mono_arch_flush_icache (guint8 *code, gint size)
 
        if (!cachelinesize) {
 #ifdef __APPLE__
-               int mib [3], len;
+               int mib [3];
+               size_t len;
                mib [0] = CTL_HW;
                mib [1] = HW_CACHELINE;
                len = sizeof (cachelinesize);
-               if (sysctl(mib, 2, &cachelinesize, &len, NULL, 0) == -1) {
+               if (sysctl(mib, 2, &cachelinesize, (size_t*)&len, NULL, 0) == -1) {
                        perror ("sysctl");
                        cachelinesize = 128;
                } else {
@@ -952,7 +953,7 @@ calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
                }
        }
 
-       if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos)) {
+       if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
                /* Prevent implicit arguments and sig_cookie from
                   being passed in registers */
                gr = PPC_LAST_ARG_REG + 1;
@@ -1015,6 +1016,34 @@ calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
        return cinfo;
 }
 
+static void
+allocate_tailcall_valuetype_addrs (MonoCompile *cfg)
+{
+#if !PPC_PASS_STRUCTS_BY_VALUE
+       MonoMethodSignature *sig = mono_method_signature (cfg->method);
+       int num_structs = 0;
+       int i;
+
+       if (!(cfg->flags & MONO_CFG_HAS_TAIL))
+               return;
+
+       for (i = 0; i < sig->param_count; ++i) {
+               MonoType *type = mono_type_get_underlying_type (sig->params [i]);
+               if (type->type == MONO_TYPE_VALUETYPE)
+                       num_structs++;
+       }
+
+       if (num_structs) {
+               cfg->tailcall_valuetype_addrs =
+                       mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * num_structs);
+               for (i = 0; i < num_structs; ++i) {
+                       cfg->tailcall_valuetype_addrs [i] =
+                               mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+                       cfg->tailcall_valuetype_addrs [i]->flags |= MONO_INST_INDIRECT;
+               }
+       }
+#endif
+}
 
 /*
  * Set var information according to the calling convention. ppc version.
@@ -1028,6 +1057,10 @@ mono_arch_allocate_vars (MonoCompile *m)
        MonoInst *inst;
        int i, offset, size, align, curinst;
        int frame_reg = ppc_sp;
+       gint32 *offsets;
+       guint32 locals_stack_size, locals_stack_align;
+
+       allocate_tailcall_valuetype_addrs (m);
 
        m->flags |= MONO_CFG_HAS_SPILLUP;
 
@@ -1149,27 +1182,24 @@ mono_arch_allocate_vars (MonoCompile *m)
                        m->sig_cookie += sizeof (gpointer);
        }
 
-       curinst = m->locals_start;
-       for (i = curinst; i < m->num_varinfo; ++i) {
-               inst = m->varinfo [i];
-               if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
-                       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)
-                       size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
-               else
-                       size = mono_type_size (inst->inst_vtype, &align);
-
-               offset += align - 1;
-               offset &= ~(align - 1);
-               inst->inst_offset = offset;
-               inst->opcode = OP_REGOFFSET;
-               inst->inst_basereg = frame_reg;
-               offset += size;
-               //g_print ("allocating local %d to %d\n", i, inst->inst_offset);
+       offsets = mono_allocate_stack_slots_full (m, FALSE, &locals_stack_size, &locals_stack_align);
+       if (locals_stack_align) {
+               offset += (locals_stack_align - 1);
+               offset &= ~(locals_stack_align - 1);
+       }
+       for (i = m->locals_start; i < m->num_varinfo; i++) {
+               if (offsets [i] != -1) {
+                       MonoInst *inst = m->varinfo [i];
+                       inst->opcode = OP_REGOFFSET;
+                       inst->inst_basereg = frame_reg;
+                       inst->inst_offset = offset + offsets [i];
+                       /*
+                       g_print ("allocating local %d (%s) to %d\n",
+                               i, mono_type_get_name (inst->inst_vtype), inst->inst_offset);
+                       */
+               }
        }
+       offset += locals_stack_size;
 
        curinst = 0;
        if (sig->hasthis) {
@@ -1193,7 +1223,7 @@ mono_arch_allocate_vars (MonoCompile *m)
                        inst->opcode = OP_REGOFFSET;
                        inst->inst_basereg = frame_reg;
                        if (sig->pinvoke) {
-                               size = mono_type_native_stack_size (sig->params [i], &align);
+                               size = mono_type_native_stack_size (sig->params [i], (guint32*)&align);
                                inst->backend.is_pinvoke = 1;
                        } else {
                                size = mono_type_size (sig->params [i], &align);
@@ -1376,7 +1406,7 @@ emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
 {
        int sig_reg = mono_alloc_ireg (cfg);
 
-       MONO_EMIT_NEW_ICONST (cfg, sig_reg, call->signature);
+       MONO_EMIT_NEW_ICONST (cfg, sig_reg, (guint32)call->signature);
        MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG,
                        ppc_r1, cinfo->sig_cookie.offset, sig_reg);
 }
@@ -1474,12 +1504,18 @@ mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
 
                                cfg->flags |= MONO_CFG_HAS_FPOUT;
                        } else {
-                               MONO_INST_NEW (cfg, ins, OP_FMOVE);
-                               ins->dreg = mono_alloc_freg (cfg);
-                               ins->sreg1 = in->dreg;
-                               MONO_ADD_INS (cfg->cbb, ins);
+                               int dreg = mono_alloc_freg (cfg);
 
-                               mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, TRUE);
+                               if (ainfo->size == 4) {
+                                       MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, dreg, in->dreg);
+                               } else {
+                                       MONO_INST_NEW (cfg, ins, OP_FMOVE);
+                                       ins->dreg = dreg;
+                                       ins->sreg1 = in->dreg;
+                                       MONO_ADD_INS (cfg->cbb, ins);
+                               }
+
+                               mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg, TRUE);
                                cfg->flags |= MONO_CFG_HAS_FPOUT;
                        }
                } else {
@@ -1518,16 +1554,18 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
        int ovf_size = ainfo->vtsize;
        int doffset = ainfo->offset;
        int i, soffset, dreg;
-       int size = 0;
 
        if (ainfo->regtype == RegTypeStructByVal) {
+               guint32 size = 0;
                soffset = 0;
-               /*
-                 Darwin needs some special handling for 1 and 2 byte arguments
-               */
 #ifdef __APPLE__
+               /*
+                * Darwin pinvokes needs some special handling for 1
+                * and 2 byte arguments
+                */
                g_assert (ins->klass);
-               size =  mono_class_native_size (ins->klass, NULL);
+               if (call->signature->pinvoke)
+                       size =  mono_class_native_size (ins->klass, NULL);
                if (size == 2 || size == 1) {
                        int tmpr = mono_alloc_ireg (cfg);
                        if (size == 1)
@@ -1655,7 +1693,7 @@ mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean ena
                cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
                code = cfg->native_code + offset;
        }
-handle_enum:
+
        switch (rtype) {
        case MONO_TYPE_VOID:
                /* special case string .ctor icall */
@@ -1983,6 +2021,8 @@ mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
                MONO_EMIT_NEW_LOAD_R8 (cfg, adj_reg, (gpointer)&adjust_val);
                MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADR8_MEMBASE, tmp_reg, ppc_sp, -8);
                MONO_EMIT_NEW_BIALU (cfg, OP_FSUB, ins->dreg, tmp_reg, adj_reg);
+               if (ins->opcode == OP_ICONV_TO_R4)
+                       MONO_EMIT_NEW_UNALU (cfg, OP_FCONV_TO_R4, ins->dreg, ins->dreg);
                ins->opcode = OP_NOP;
                break;
        }
@@ -2368,48 +2408,6 @@ emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size,
        return code;
 }
 
-static unsigned char*
-mono_emit_stack_alloc (guchar *code, MonoInst* tree)
-{
-#if 0
-       int sreg = tree->sreg1;
-       x86_alu_reg_reg (code, X86_SUB, X86_ESP, tree->sreg1);
-       if (tree->flags & MONO_INST_INIT) {
-               int offset = 0;
-               if (tree->dreg != X86_EAX && sreg != X86_EAX) {
-                       x86_push_reg (code, X86_EAX);
-                       offset += 4;
-               }
-               if (tree->dreg != X86_ECX && sreg != X86_ECX) {
-                       x86_push_reg (code, X86_ECX);
-                       offset += 4;
-               }
-               if (tree->dreg != X86_EDI && sreg != X86_EDI) {
-                       x86_push_reg (code, X86_EDI);
-                       offset += 4;
-               }
-               
-               x86_shift_reg_imm (code, X86_SHR, sreg, 2);
-               if (sreg != X86_ECX)
-                       x86_mov_reg_reg (code, X86_ECX, sreg, 4);
-               x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
-                               
-               x86_lea_membase (code, X86_EDI, X86_ESP, offset);
-               x86_cld (code);
-               x86_prefix (code, X86_REP_PREFIX);
-               x86_stosl (code);
-               
-               if (tree->dreg != X86_EDI && sreg != X86_EDI)
-                       x86_pop_reg (code, X86_EDI);
-               if (tree->dreg != X86_ECX && sreg != X86_ECX)
-                       x86_pop_reg (code, X86_ECX);
-               if (tree->dreg != X86_EAX && sreg != X86_EAX)
-                       x86_pop_reg (code, X86_EAX);
-       }
-#endif
-       return code;
-}
-
 typedef struct {
        guchar *code;
        const guchar *target;
@@ -2631,6 +2629,7 @@ emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
        MonoInst *inst;
        CallInfo *cinfo;
        guint32 i, pos;
+       int struct_index = 0;
 
        /* FIXME: Generate intermediate code instead */
 
@@ -2643,8 +2642,10 @@ emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
        cinfo = calculate_sizes (sig, sig->pinvoke);
 
        if (MONO_TYPE_ISSTRUCT (sig->ret)) {
-           /* FIXME: */
-           NOT_IMPLEMENTED;
+               ArgInfo *ainfo = &cinfo->ret;
+               inst = cfg->vret_addr;
+               g_assert (ppc_is_imm16 (inst->inst_offset));
+               ppc_lwz (code, ainfo->reg, inst->inst_offset, inst->inst_basereg);
        }
        for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
                ArgInfo *ainfo = cinfo->args + i;
@@ -2682,11 +2683,45 @@ emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
                        break;
 
                case RegTypeBase:
-               case RegTypeStructByVal:
-               case RegTypeStructByAddr:
                        /* FIXME: */
                        NOT_IMPLEMENTED;
 
+               case RegTypeStructByVal: {
+                       guint32 size = 0;
+
+                       /* FIXME: */
+                       if (ainfo->vtsize)
+                               NOT_IMPLEMENTED;
+#ifdef __APPLE__
+                       /*
+                        * Darwin pinvokes needs some special handling
+                        * for 1 and 2 byte arguments
+                        */
+                       if (method->signature->pinvoke)
+                               size = mono_class_native_size (inst->klass, NULL);
+                       if (size == 1 || size == 2) {
+                               /* FIXME: */
+                               NOT_IMPLEMENTED;
+                       } else
+#endif
+                               for (i = 0; i < ainfo->size; ++i) {
+                                       ppc_lwz (code, ainfo->reg  + i,
+                                               inst->inst_offset + i * sizeof (gpointer), inst->inst_basereg);
+                               }
+                       break;
+               }
+
+               case RegTypeStructByAddr: {
+                       MonoInst *addr = cfg->tailcall_valuetype_addrs [struct_index];
+
+                       g_assert (ppc_is_imm16 (addr->inst_offset));
+                       g_assert (!ainfo->offset);
+                       ppc_lwz (code, ainfo->reg, addr->inst_offset, addr->inst_basereg);
+
+                       struct_index++;
+                       break;
+               }
+
                default:
                        g_assert_not_reached ();
                }
@@ -2743,6 +2778,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                mono_debug_record_line_number (cfg, ins, offset);
 
                switch (ins->opcode) {
+               case OP_RELAXED_NOP:
                case OP_NOP:
                case OP_DUMMY_USE:
                case OP_DUMMY_STORE:
@@ -3833,6 +3869,7 @@ mono_arch_emit_prolog (MonoCompile *cfg)
        CallInfo *cinfo;
        int tracing = 0;
        int lmf_offset = 0;
+       int tailcall_struct_index;
 
        if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
                tracing = 1;
@@ -3929,6 +3966,8 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                        ppc_stwx (code, ainfo->reg, ppc_r11, inst->inst_basereg);
                }
        }
+
+       tailcall_struct_index = 0;
        for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
                ArgInfo *ainfo = cinfo->args + i;
                inst = cfg->args [pos];
@@ -4044,19 +4083,22 @@ mono_arch_emit_prolog (MonoCompile *cfg)
                                g_assert (ppc_is_imm16 (inst->inst_offset));
                                g_assert (ppc_is_imm16 (inst->inst_offset + ainfo->size * sizeof (gpointer)));
                                /* FIXME: what if there is no class? */
-                               if (mono_class_from_mono_type (inst->inst_vtype))
+                               if (sig->pinvoke && mono_class_from_mono_type (inst->inst_vtype))
                                        size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
                                for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
-/*
-Darwin handles 1 and 2 byte structs specially by loading h/b into the arg
-register.  Should this case include linux/ppc?
-*/
 #if __APPLE__
+                                       /*
+                                        * Darwin handles 1 and 2 byte
+                                        * structs specially by
+                                        * loading h/b into the arg
+                                        * register.  Only done for
+                                        * pinvokes.
+                                        */
                                        if (size == 2)
                                                ppc_sth (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
                                        else if (size == 1)
                                                ppc_stb (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
-                                       else 
+                                       else
 #endif
                                                ppc_stw (code, ainfo->reg + cur_reg, doffset, inst->inst_basereg);
                                        soffset += sizeof (gpointer);
@@ -4084,6 +4126,16 @@ register.  Should this case include linux/ppc?
                                } else {
                                        ppc_mr (code, ppc_r11, ainfo->reg);
                                }
+
+                               if (cfg->tailcall_valuetype_addrs) {
+                                       MonoInst *addr = cfg->tailcall_valuetype_addrs [tailcall_struct_index];
+
+                                       g_assert (ppc_is_imm16 (addr->inst_offset));
+                                       ppc_stw (code, ppc_r11, addr->inst_offset, addr->inst_basereg);
+
+                                       tailcall_struct_index++;
+                               }
+
                                g_assert (ppc_is_imm16 (inst->inst_offset));
                                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);*/
@@ -4161,7 +4213,6 @@ register.  Should this case include linux/ppc?
 void
 mono_arch_emit_epilog (MonoCompile *cfg)
 {
-       MonoJumpInfo *patch_info;
        MonoMethod *method = cfg->method;
        int pos, i;
        int max_epilog_size = 16 + 20*4;