In .:
[mono.git] / mono / mini / decompose.c
index 659081b99a04b7133d260361a4170e700088395a..359163009e0214921bc77ea8fd455b44ee9a65f7 100644 (file)
@@ -164,6 +164,36 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
                MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
                ins->opcode = OP_NOP;
                break;
+#if defined(__ppc__)
+       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);
+               ins->opcode = OP_NOP;
+               g_assert_not_reached ();
+               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);
+               ins->opcode = OP_NOP;
+               g_assert_not_reached ();
+               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);
+               ins->opcode = OP_NOP;
+               g_assert_not_reached ();
+               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);
+               ins->opcode = OP_NOP;
+               g_assert_not_reached ();
+               break;
+#else
        case OP_LADD_OVF:
                MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
                MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
@@ -184,6 +214,7 @@ mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
                MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
                ins->opcode = OP_NOP;
                break;
+#endif
                
        case OP_ICONV_TO_OVF_I8:
        case OP_ICONV_TO_OVF_I:
@@ -634,6 +665,29 @@ mono_decompose_long_opts (MonoCompile *cfg)
                                MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
                                MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
                                break;
+
+#if defined(__ppc__)
+                       case OP_LADD_OVF:
+                               /* ADC sets the condition code */
+                               MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
+                               MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
+                               break;
+                       case OP_LADD_OVF_UN:
+                               /* ADC sets the condition code */
+                               MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
+                               MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
+                               break;
+                       case OP_LSUB_OVF:
+                               /* SBB sets the condition code */
+                               MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
+                               MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
+                               break;
+                       case OP_LSUB_OVF_UN:
+                               /* SBB sets the condition code */
+                               MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
+                               MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
+                               break;
+#else
                        case OP_LADD_OVF:
                                /* ADC sets the condition code */
                                MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
@@ -658,6 +712,7 @@ mono_decompose_long_opts (MonoCompile *cfg)
                                MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
                                MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
                                break;
+#endif
                        case OP_LAND:
                                MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
                                MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
@@ -690,6 +745,13 @@ mono_decompose_long_opts (MonoCompile *cfg)
 #elif defined(__arm__)
                                MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSBS_IMM, tree->dreg + 1, tree->sreg1 + 1, 0);
                                MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSC_IMM, tree->dreg + 2, tree->sreg1 + 2, 0);
+#elif defined(__ppc__)
+                               /* This is the old version from inssel-long32.brg */
+                               MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
+                               MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
+                               /* ADC sets the condition codes */
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 1, tree->dreg + 1, 1);
+                               MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->dreg + 2, 0);
 #else
                                NOT_IMPLEMENTED;
 #endif
@@ -1088,6 +1150,7 @@ mono_decompose_vtype_opts (MonoCompile *cfg)
                                case OP_VCALL_REG:
                                case OP_VCALL_MEMBASE: {
                                        MonoCallInst *call = (MonoCallInst*)ins;
+                                       int size;
 
                                        if (call->vret_in_reg) {
                                                MonoCallInst *call2;
@@ -1111,13 +1174,33 @@ mono_decompose_vtype_opts (MonoCompile *cfg)
 
                                                /* Compute the vtype location */
                                                dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
-                                               /* This was already created when OP_OUTARG_VTRETADDR was processed */
-                                               g_assert (dest_var);
+                                               if (!dest_var)
+                                                       dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
                                                EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
 
                                                /* Save the result */
-                                               /* This assumes the vtype is sizeof (gpointer) long */
-                                               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
+                                               if (dest_var->backend.is_pinvoke)
+                                                       size = mono_class_native_size (dest->inst_vtype->data.klass, NULL);
+                                               else
+                                                       size = mono_type_size (dest_var->inst_vtype, NULL);
+                                               switch (size) {
+                                               case 1:
+                                                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
+                                                       break;
+                                               case 2:
+                                                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
+                                                       break;
+                                               case 4:
+                                                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
+                                                       break;
+                                               case 8:
+                                                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
+                                                       break;
+                                               default:
+                                                       /* This assumes the vtype is sizeof (gpointer) long */
+                                                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
+                                                       break;
+                                               }
                                        } else {
                                                switch (ins->opcode) {
                                                case OP_VCALL: