New test.
[mono.git] / mono / mini / mini-ia64.c
index 9adc39ff41251813853d74523fbd84280d23f9fa..4d67083dc11b09f640149cec68072701143b0716 100644 (file)
@@ -59,6 +59,7 @@ static const char*const * ins_spec = ia64_desc;
 #define GP_SCRATCH_REG 31
 #define GP_SCRATCH_REG2 30
 #define FP_SCRATCH_REG 32
+#define FP_SCRATCH_REG2 33
 
 #define LOOP_ALIGNMENT 8
 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
@@ -984,14 +985,14 @@ add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, MonoInst *arg, ArgStorage
                arg->opcode = OP_OUTARG_REG;
                arg->inst_left = tree;
                arg->inst_right = (MonoInst*)call;
-               arg->unused = reg;
+               arg->backend.reg3 = reg;
                call->used_iregs |= 1 << reg;
                break;
        case ArgInFloatReg:
                arg->opcode = OP_OUTARG_FREG;
                arg->inst_left = tree;
                arg->inst_right = (MonoInst*)call;
-               arg->unused = reg;
+               arg->backend.reg3 = reg;
                call->used_fregs |= 1 << reg;
                break;
        default:
@@ -999,12 +1000,47 @@ add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, MonoInst *arg, ArgStorage
        }
 }
 
+static void
+emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
+{
+       MonoInst *arg;
+       MonoMethodSignature *tmp_sig;
+       MonoInst *sig_arg;
+
+       /* FIXME: Add support for signature tokens to AOT */
+       cfg->disable_aot = TRUE;
+
+       g_assert (cinfo->sig_cookie.storage == ArgOnStack);
+
+       /*
+        * mono_ArgIterator_Setup assumes the signature cookie is 
+        * passed first and all the arguments which were before it are
+        * passed on the stack after the signature. So compensate by 
+        * passing a different signature.
+        */
+       tmp_sig = mono_metadata_signature_dup (call->signature);
+       tmp_sig->param_count -= call->signature->sentinelpos;
+       tmp_sig->sentinelpos = 0;
+       memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
+
+       MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
+       sig_arg->inst_p0 = tmp_sig;
+
+       MONO_INST_NEW (cfg, arg, OP_OUTARG);
+       arg->inst_left = sig_arg;
+       arg->inst_imm = 16 + cinfo->sig_cookie.offset;
+       arg->type = STACK_PTR;
+
+       /* prepend, so they get reversed */
+       arg->next = call->out_args;
+       call->out_args = arg;
+}
+
 /* 
  * take the arguments and generate the arch-specific
  * instructions to properly call the function in call.
  * This includes pushing, moving arguments to the right register
  * etc.
- * Issue: who does the spilling if needed, and when?
  */
 MonoCallInst*
 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual)
@@ -1034,37 +1070,8 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call,
                ainfo = cinfo->args + i;
 
                if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
-                       MonoMethodSignature *tmp_sig;
-
                        /* Emit the signature cookie just before the implicit arguments */
-                       MonoInst *sig_arg;
-                       /* FIXME: Add support for signature tokens to AOT */
-                       cfg->disable_aot = TRUE;
-
-                       g_assert (cinfo->sig_cookie.storage == ArgOnStack);
-
-                       /*
-                        * mono_ArgIterator_Setup assumes the signature cookie is 
-                        * passed first and all the arguments which were before it are
-                        * passed on the stack after the signature. So compensate by 
-                        * passing a different signature.
-                        */
-                       tmp_sig = mono_metadata_signature_dup (call->signature);
-                       tmp_sig->param_count -= call->signature->sentinelpos;
-                       tmp_sig->sentinelpos = 0;
-                       memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
-
-                       MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
-                       sig_arg->inst_p0 = tmp_sig;
-
-                       MONO_INST_NEW (cfg, arg, OP_OUTARG);
-                       arg->inst_left = sig_arg;
-                       arg->inst_imm = 16 + cinfo->sig_cookie.offset;
-                       arg->type = STACK_PTR;
-
-                       /* prepend, so they get reversed */
-                       arg->next = call->out_args;
-                       call->out_args = arg;
+                       emit_sig_cookie (cfg, call, cinfo);
                }
 
                if (is_virtual && i == 0) {
@@ -1111,32 +1118,32 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call,
 
                                if (ainfo->storage == ArgAggregate) {
                                        MonoInst *vtaddr, *load, *load2, *offset_ins, *set_reg;
-                                       int slot;
+                                       int slot, j;
 
                                        vtaddr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
 
                                        /* 
                                         * Part of the structure is passed in registers.
                                         */
-                                       for (i = 0; i < ainfo->nregs; ++i) {
+                                       for (j = 0; j < ainfo->nregs; ++j) {
                                                int offset, load_op, dest_reg, arg_storage;
 
-                                               slot = ainfo->reg + i;
+                                               slot = ainfo->reg + j;
                                                
                                                if (ainfo->atype == AggregateSingleHFA) {
                                                        load_op = CEE_LDIND_R4;
-                                                       offset = i * 4;
-                                                       dest_reg = ainfo->reg + i;
+                                                       offset = j * 4;
+                                                       dest_reg = ainfo->reg + j;
                                                        arg_storage = ArgInFloatReg;
                                                } else if (ainfo->atype == AggregateDoubleHFA) {
                                                        load_op = CEE_LDIND_R8;
-                                                       offset = i * 8;
-                                                       dest_reg = ainfo->reg + i;
+                                                       offset = j * 8;
+                                                       dest_reg = ainfo->reg + j;
                                                        arg_storage = ArgInFloatReg;
                                                } else {
                                                        load_op = CEE_LDIND_I;
-                                                       offset = i * 8;
-                                                       dest_reg = cfg->arch.reg_out0 + ainfo->reg + i;
+                                                       offset = j * 8;
+                                                       dest_reg = cfg->arch.reg_out0 + ainfo->reg + j;
                                                        arg_storage = ArgInIReg;
                                                }
 
@@ -1152,7 +1159,7 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call,
                                                MONO_INST_NEW (cfg, load, load_op);
                                                load->inst_left = load2;
 
-                                               if (i == 0)
+                                               if (j == 0)
                                                        set_reg = arg;
                                                else
                                                        MONO_INST_NEW (cfg, set_reg, OP_OUTARG_REG);
@@ -1166,16 +1173,16 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call,
                                        /* 
                                         * Part of the structure is passed on the stack.
                                         */
-                                       for (i = ainfo->nregs; i < ainfo->nslots; ++i) {
+                                       for (j = ainfo->nregs; j < ainfo->nslots; ++j) {
                                                MonoInst *outarg;
 
-                                               slot = ainfo->reg + i;
+                                               slot = ainfo->reg + j;
 
                                                MONO_INST_NEW (cfg, load, CEE_LDIND_I);
                                                load->ssa_op = MONO_SSA_LOAD;
                                                load->inst_i0 = (cfg)->varinfo [vtaddr->inst_c0];
 
-                                               NEW_ICONST (cfg, offset_ins, (i * sizeof (gpointer)));
+                                               NEW_ICONST (cfg, offset_ins, (j * sizeof (gpointer)));
                                                MONO_INST_NEW (cfg, load2, CEE_ADD);
                                                load2->inst_left = load;
                                                load2->inst_right = offset_ins;
@@ -1183,7 +1190,7 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call,
                                                MONO_INST_NEW (cfg, load, CEE_LDIND_I);
                                                load->inst_left = load2;
 
-                                               if (i == 0)
+                                               if (j == 0)
                                                        outarg = arg;
                                                else
                                                        MONO_INST_NEW (cfg, outarg, OP_OUTARG);
@@ -1241,6 +1248,11 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call,
                }
        }
 
+       /* Handle the case where there are no implicit arguments */
+       if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos)) {
+               emit_sig_cookie (cfg, call, cinfo);
+       }
+
        call->stack_usage = cinfo->stack_usage;
        cfg->param_area = MAX (cfg->param_area, call->stack_usage);
        cfg->arch.n_out_regs = MAX (cfg->arch.n_out_regs, cinfo->reg_usage);
@@ -1514,7 +1526,9 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_STOREI8_MEMBASE_IMM:
                case OP_STORE_MEMBASE_IMM:
                        /* There are no store_membase instructions on ia64 */
-                       if (ia64_is_imm14 (ins->inst_offset)) {
+                       if (ins->inst_offset == 0) {
+                               temp2 = NULL;
+                       } else if (ia64_is_imm14 (ins->inst_offset)) {
                                NEW_INS (cfg, temp2, OP_ADD_IMM);
                                temp2->sreg1 = ins->inst_destbasereg;
                                temp2->inst_imm = ins->inst_offset;
@@ -1558,7 +1572,8 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
                        }
 
                        ins->inst_offset = 0;
-                       ins->inst_destbasereg = temp2->dreg;
+                       if (temp2)
+                               ins->inst_destbasereg = temp2->dreg;
                        break;
                case OP_STOREI1_MEMBASE_REG:
                case OP_STOREI2_MEMBASE_REG:
@@ -1600,37 +1615,17 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_LOAD_MEMBASE:
                case OP_LOADR4_MEMBASE:
                case OP_LOADR8_MEMBASE:
-                       /* There are no load_membase instructions on ia64 */
-                       if (ins->inst_offset == 0) {
-                               break;
-                       }
-                       else if (ia64_is_imm14 (ins->inst_offset)) {
-                               NEW_INS (cfg, temp2, OP_ADD_IMM);
-                               temp2->sreg1 = ins->inst_basereg;
-                               temp2->inst_imm = ins->inst_offset;
-                               temp2->dreg = mono_regstate_next_int (cfg->rs);
-                       }
-                       else {
-                               NEW_INS (cfg, temp, OP_I8CONST);
-                               temp->inst_c0 = ins->inst_offset;
-                               temp->dreg = mono_regstate_next_int (cfg->rs);
-                               NEW_INS (cfg, temp2, CEE_ADD);
-                               temp2->sreg1 = ins->inst_basereg;
-                               temp2->sreg2 = temp->dreg;
-                               temp2->dreg = mono_regstate_next_int (cfg->rs);
-                       }
-
-                       ins->inst_offset = 0;
-                       ins->inst_basereg = temp2->dreg;
-                       break;
-               case OP_IA64_FETCHADD4_IMM:
-               case OP_IA64_FETCHADD8_IMM:
                case OP_ATOMIC_EXCHANGE_I4:
                case OP_ATOMIC_EXCHANGE_I8:
                case OP_ATOMIC_ADD_NEW_I4:
                case OP_ATOMIC_ADD_NEW_I8:
+               case OP_ATOMIC_ADD_IMM_NEW_I4:
+               case OP_ATOMIC_ADD_IMM_NEW_I8:
                        /* There are no membase instructions on ia64 */
-                       if (ia64_is_imm14 (ins->inst_offset)) {
+                       if (ins->inst_offset == 0) {
+                               break;
+                       }
+                       else if (ia64_is_imm14 (ins->inst_offset)) {
                                NEW_INS (cfg, temp2, OP_ADD_IMM);
                                temp2->sreg1 = ins->inst_basereg;
                                temp2->inst_imm = ins->inst_offset;
@@ -1645,6 +1640,7 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
                                temp2->sreg2 = temp->dreg;
                                temp2->dreg = mono_regstate_next_int (cfg->rs);
                        }
+
                        ins->inst_offset = 0;
                        ins->inst_basereg = temp2->dreg;
                        break;
@@ -2509,6 +2505,13 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_LSHR_UN_IMM:
                        ia64_shr_u_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
                        break;
+               case CEE_MUL:
+                       /* Based on gcc code */
+                       ia64_setf_sig (code, FP_SCRATCH_REG, ins->sreg1);
+                       ia64_setf_sig (code, FP_SCRATCH_REG2, ins->sreg2);
+                       ia64_xmpy_l (code, FP_SCRATCH_REG, FP_SCRATCH_REG, FP_SCRATCH_REG2);
+                       ia64_getf_sig (code, ins->dreg, FP_SCRATCH_REG);
+                       break;
 
                case OP_STOREI1_MEMBASE_REG:
                        ia64_st1_hint (code, ins->inst_destbasereg, ins->sreg1, 0);
@@ -3076,12 +3079,12 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_MEMORY_BARRIER:
                        ia64_mf (code);
                        break;
-               case OP_IA64_FETCHADD4_IMM:
+               case OP_ATOMIC_ADD_IMM_NEW_I4:
                        g_assert (ins->inst_offset == 0);
                        ia64_fetchadd4_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
                        ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
                        break;
-               case OP_IA64_FETCHADD8_IMM:
+               case OP_ATOMIC_ADD_IMM_NEW_I8:
                        g_assert (ins->inst_offset == 0);
                        ia64_fetchadd8_acq_hint (code, ins->dreg, ins->inst_basereg, ins->inst_imm, 0);
                        ia64_adds_imm (code, ins->dreg, ins->inst_imm, ins->dreg);
@@ -4768,38 +4771,29 @@ mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethod
                           (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
 
                if (strcmp (cmethod->name, "Increment") == 0) {
-                       MonoInst *ins_iconst;
                        guint32 opcode;
 
                        if (fsig->params [0]->type == MONO_TYPE_I4)
-                               opcode = OP_ATOMIC_ADD_NEW_I4;
+                               opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
                        else if (fsig->params [0]->type == MONO_TYPE_I8)
-                               opcode = OP_ATOMIC_ADD_NEW_I8;
+                               opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
                        else
                                g_assert_not_reached ();
                        MONO_INST_NEW (cfg, ins, opcode);
-                       MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
-                       ins_iconst->inst_imm = 1;
-
+                       ins->inst_imm = 1;
                        ins->inst_i0 = args [0];
-                       ins->inst_i1 = ins_iconst;
                } else if (strcmp (cmethod->name, "Decrement") == 0) {
-                       MonoInst *ins_iconst;
                        guint32 opcode;
 
                        if (fsig->params [0]->type == MONO_TYPE_I4)
-                               opcode = OP_ATOMIC_ADD_NEW_I4;
+                               opcode = OP_ATOMIC_ADD_IMM_NEW_I4;
                        else if (fsig->params [0]->type == MONO_TYPE_I8)
-                               opcode = OP_ATOMIC_ADD_NEW_I8;
+                               opcode = OP_ATOMIC_ADD_IMM_NEW_I8;
                        else
                                g_assert_not_reached ();
                        MONO_INST_NEW (cfg, ins, opcode);
-                       MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
-                       ins_iconst->inst_imm = -1;
-
+                       ins->inst_imm = -1;
                        ins->inst_i0 = args [0];
-                       ins->inst_i1 = ins_iconst;
-                       /* FIXME: */
                } else if (strcmp (cmethod->name, "Exchange") == 0) {
                        guint32 opcode;