2005-12-11 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini.c
index 7a67bc1c237a98eaae752917e6e86e902ac45c9e..194f58b034e674dbdd99a0030631e4628cb27110 100644 (file)
@@ -62,6 +62,8 @@
 
 #include "jit-icalls.c"
 
+#include "aliasing.h"
+
 /* 
  * this is used to determine when some branch optimizations are possible: we exclude FP compares
  * because they have weird semantics with NaNs.
@@ -449,7 +451,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 
 #define NEW_LOCLOADA(cfg,dest,num) do {        \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->ssa_op = MONO_SSA_MAYBE_LOAD;   \
+               (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
                (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
                (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
                (dest)->opcode = OP_LDADDR;     \
@@ -461,7 +463,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 
 #define NEW_RETLOADA(cfg,dest) do {    \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->ssa_op = MONO_SSA_MAYBE_LOAD;   \
+               (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
                (dest)->inst_i0 = (cfg)->ret;   \
                (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
                (dest)->opcode = cfg->ret_var_is_local ? OP_LDADDR : CEE_LDIND_I;       \
@@ -473,7 +475,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 #define NEW_ARGLOADA(cfg,dest,num) do {        \
                 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->ssa_op = MONO_SSA_MAYBE_LOAD;   \
+               (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
                (dest)->inst_i0 = arg_array [(num)];    \
                (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
                (dest)->opcode = OP_LDADDR;     \
@@ -493,7 +495,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 
 #define NEW_TEMPLOADA(cfg,dest,num) do {       \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->ssa_op = MONO_SSA_MAYBE_LOAD;   \
+               (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
                (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
                (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
                (dest)->opcode = OP_LDADDR;     \
@@ -2372,6 +2374,7 @@ mono_get_element_address_signature (int arity)
 
        res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
 
+       res->pinvoke = 1;
 #ifdef MONO_ARCH_VARARG_ICALLS
        /* Only set this only some archs since not all backends can handle varargs+pinvoke */
        res->call_convention = MONO_CALL_VARARG;
@@ -2407,6 +2410,7 @@ mono_get_array_new_va_signature (int arity)
 
        res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
 
+       res->pinvoke = 1;
 #ifdef MONO_ARCH_VARARG_ICALLS
        /* Only set this only some archs since not all backends can handle varargs+pinvoke */
        res->call_convention = MONO_CALL_VARARG;
@@ -2564,13 +2568,35 @@ handle_alloc (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, gboole
 
        return mono_emit_jit_icall (cfg, bblock, alloc_ftn, iargs, ip);
 }
+
+/**
+ * Handles unbox of a Nullable<T>, returning a temp variable
+ * where the result is stored
+ */
+static int
+handle_unbox_nullable (MonoCompile* cfg, MonoBasicBlock* bblock, MonoInst* val, const guchar *ip, MonoClass* klass)
+{
+       MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
+       return mono_emit_method_call_spilled (cfg, bblock, method, mono_method_signature (method), &val, ip, NULL);
        
+}
+
+
+
 static MonoInst *
 handle_box (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip, MonoClass *klass)
 {
        MonoInst *dest, *vtoffset, *add, *vstore;
        int temp;
 
+       if (mono_class_is_nullable (klass)) {
+               MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
+               temp = mono_emit_method_call_spilled (cfg, bblock, method, mono_method_signature (method), &val, ip, NULL);
+               NEW_TEMPLOAD (cfg, dest, temp);
+               return dest;
+       }
+
+
        temp = handle_alloc (cfg, bblock, klass, TRUE, ip);
        NEW_TEMPLOAD (cfg, dest, temp);
        NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
@@ -2897,7 +2923,7 @@ mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSigna
                        return ins;
                } else
                        return NULL;
-       } else if (mini_class_is_system_array (cmethod->klass)) {
+       } else if (cmethod->klass == mono_defaults.array_class) {
                if (cmethod->name [0] != 'g')
                        return NULL;
 
@@ -3290,7 +3316,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
        image = method->klass->image;
        header = mono_method_get_header (method);
-       generic_container = ((MonoMethodNormal *)method)->generic_container;
+       generic_container = method->generic_container;
        sig = mono_method_signature (method);
        num_args = sig->hasthis + sig->param_count;
        ip = (unsigned char*)header->code;
@@ -4831,12 +4857,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                goto load_error;
                        fsig = mono_method_get_signature (cmethod, image, token);
 
-                       if (mono_method_signature (cmethod)->pinvoke) {
-                               /* Happens with String ctors */
-                               cmethod = mono_marshal_get_native_wrapper (cmethod);
-                               fsig = mono_method_signature (cmethod);
-                       }
-
                        mono_class_init (cmethod->klass);
 
                        if (mono_use_security_manager) {
@@ -5041,6 +5061,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                break;
                        }
 
+                       if (mono_class_is_nullable (klass)) {
+                               int v = handle_unbox_nullable (cfg, bblock, *sp, ip, klass);
+                               NEW_TEMPLOAD (cfg, *sp, v);
+                               sp ++;
+                               ip += 5;
+                               break;
+                       }
+
                        MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
                        ins->type = STACK_OBJ;
                        ins->inst_left = *sp;
@@ -5091,6 +5119,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (!klass)
                                goto load_error;
 
+                       if (mono_class_is_nullable (klass)) {
+                               int v = handle_unbox_nullable (cfg, bblock, *sp, ip, klass);
+                               NEW_TEMPLOAD (cfg, *sp, v);
+                               sp ++;
+                               ip += 5;
+                               break;
+                       }
+
                        /* Needed by the code generated in inssel.brg */
                        mono_get_got_var (cfg);
 
@@ -8905,7 +8941,7 @@ mono_cprop_invalidate_values (MonoInst *tree, MonoInst **acp, int acp_size)
        case CEE_STIND_R4:
        case CEE_STIND_R8:
        case CEE_STOBJ:
-               if (tree->ssa_op == MONO_SSA_NOP) {
+               if ((tree->ssa_op == MONO_SSA_NOP) || (tree->ssa_op & MONO_SSA_ADDRESS_TAKEN)) {
                        memset (acp, 0, sizeof (MonoInst *) * acp_size);
                        return;
                }
@@ -9171,6 +9207,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        MonoCompile *cfg;
        MonoJitInfo *jinfo;
        int dfn = 0, i, code_size_ratio;
+       gboolean deadce_has_run = FALSE;
 
        if (!header)
                return NULL;
@@ -9193,7 +9230,8 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        cfg->compile_aot = compile_aot;
        cfg->intvars = mono_mempool_alloc0 (cfg->mempool, sizeof (guint16) * STACK_MAX * 
                                            mono_method_get_header (method)->max_stack);
-
+       cfg->aliasing_info = NULL;
+       
        if (cfg->verbose_level > 2)
                g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
 
@@ -9278,7 +9316,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 #else 
 
        /* fixme: add all optimizations which requires SSA */
-       if (cfg->opt & (MONO_OPT_DEADCE | MONO_OPT_ABCREM | MONO_OPT_SSAPRE)) {
+       if (cfg->opt & (MONO_OPT_SSA | MONO_OPT_ABCREM | MONO_OPT_SSAPRE)) {
                if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) {
                        mono_local_cprop (cfg);
                        mono_ssa_compute (cfg);
@@ -9303,16 +9341,23 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        }
 
        if (cfg->comp_done & MONO_COMP_SSA) {                   
-               mono_ssa_deadce (cfg);
+               //mono_ssa_deadce (cfg);
 
                //mono_ssa_strength_reduction (cfg);
 
+               if (cfg->opt & MONO_OPT_SSAPRE) {
+                       mono_perform_ssapre (cfg);
+                       //mono_local_cprop (cfg);
+               }
+               
+               if (cfg->opt & MONO_OPT_DEADCE) {
+                       mono_ssa_deadce (cfg);
+                       deadce_has_run = TRUE;
+               }
+               
                if ((cfg->flags & MONO_CFG_HAS_LDELEMA) && (cfg->opt & MONO_OPT_ABCREM))
                        mono_perform_abc_removal (cfg);
                
-               if (cfg->opt & MONO_OPT_SSAPRE)
-                       mono_perform_ssapre (cfg);
-               
                mono_ssa_remove (cfg);
 
                if (cfg->opt & MONO_OPT_BRANCH)
@@ -9348,18 +9393,33 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
        if (cfg->opt & MONO_OPT_LINEARS) {
                GList *vars, *regs;
+               
+               /* For now, compute aliasing info only if needed for deadce... */
+               if ((cfg->opt & MONO_OPT_DEADCE) && (! deadce_has_run) && (header->num_clauses == 0)) {
+                       cfg->aliasing_info = mono_build_aliasing_information (cfg);
+               }
 
                /* fixme: maybe we can avoid to compute livenesss here if already computed ? */
                cfg->comp_done &= ~MONO_COMP_LIVENESS;
                if (!(cfg->comp_done & MONO_COMP_LIVENESS))
                        mono_analyze_liveness (cfg);
 
+               if (cfg->aliasing_info != NULL) {
+                       mono_aliasing_deadce (cfg->aliasing_info);
+                       deadce_has_run = TRUE;
+               }
+               
                if ((vars = mono_arch_get_allocatable_int_vars (cfg))) {
                        regs = mono_arch_get_global_int_regs (cfg);
                        if (cfg->got_var)
                                regs = g_list_delete_link (regs, regs);
                        mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs);
                }
+               
+               if (cfg->aliasing_info != NULL) {
+                       mono_destroy_aliasing_information (cfg->aliasing_info);
+                       cfg->aliasing_info = NULL;
+               }
        }
 
        //mono_print_code (cfg);