[runtime] Simplify mono-debug.c since we no longer have to serialize a lot of the...
[mono.git] / mono / mini / branch-opts.c
index 3d27d244404c66266be048f9c53d9c1dc5739c8e..2be95e736424d43c562b3e52612273e3372788f1 100644 (file)
@@ -5,6 +5,7 @@
  *   Patrik Torstensson (Patrik.Torstesson at gmail.com)
  *
  * (C) 2005 Ximian, Inc.  http://www.ximian.com
+ * Copyright 2011 Xamarin Inc.  http://www.xamarin.com
  */
  #include "mini.h"
 
@@ -32,8 +33,7 @@ mono_bb_is_fall_through (MonoCompile *cfg, MonoBasicBlock *bb)
 MonoInst *
 mono_branch_optimize_exception_target (MonoCompile *cfg, MonoBasicBlock *bb, const char * exname)
 {
-       MonoMethod *method = cfg->method;
-       MonoMethodHeader *header = mono_method_get_header (method);
+       MonoMethodHeader *header = cfg->header;
        MonoExceptionClause *clause;
        MonoClass *exclass;
        int i;
@@ -94,6 +94,9 @@ mono_branch_optimize_exception_target (MonoCompile *cfg, MonoBasicBlock *bb, con
                                                return jump;
                                        } 
 
+                                       return NULL;
+                               } else {
+                                       /* Branching to an outer clause could skip inner clauses */
                                        return NULL;
                                }
                        } else {
@@ -132,7 +135,7 @@ static const int long_cmov_opcodes [] = {
        OP_CMOV_LGT_UN
 };
 
-static int
+static G_GNUC_UNUSED int
 br_to_br_un (int opcode)
 {
        switch (opcode) {
@@ -532,6 +535,13 @@ mono_if_conversion (MonoCompile *cfg)
                        if (cfg->ret && ins1->dreg == cfg->ret->dreg)
                                continue;
 
+                       if (!(cfg->opt & MONO_OPT_DEADCE))
+                               /* 
+                                * It is possible that dreg is never set before, so we can't use
+                                * it as an sreg of the cmov instruction (#582322).
+                                */
+                               continue;
+
                        if (cfg->verbose_level > 2) {
                                printf ("\tBranch -> CMove optimization (2) in BB%d on\n", bb->block_num);
                                printf ("\t\t"); mono_print_ins (compare);
@@ -745,7 +755,8 @@ mono_if_conversion (MonoCompile *cfg)
                mono_handle_global_vregs (cfg);
                if (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP))
                        mono_local_cprop (cfg);
-               mono_local_deadce (cfg);
+               if (cfg->opt & MONO_OPT_DEADCE)
+                       mono_local_deadce (cfg);
        }
 #endif
 }
@@ -805,6 +816,15 @@ replace_in_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl
 static void
 replace_out_block_in_code (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl) {
        MonoInst *ins;
+
+#if defined(__native_client_codegen__)
+       /* Need to maintain this flag for the new block because */
+       /* we can't jump indirectly to a non-aligned block.     */
+       if (orig->flags & BB_INDIRECT_JUMP_TARGET)
+       {
+               repl->flags |= BB_INDIRECT_JUMP_TARGET;
+       }
+#endif
        
        for (ins = bb->code; ins != NULL; ins = ins->next) {
                switch (ins->opcode) {
@@ -951,6 +971,12 @@ mono_merge_basic_blocks (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *b
        bb->has_array_access |= bbn->has_array_access;
        bb->extended |= bbn->extended;
 
+       /* Compute prev_bb if possible to avoid the linear search below */
+       prev_bb = NULL;
+       for (i = 0; i < bbn->in_count; ++i)
+               if (bbn->in_bb [0]->next_bb == bbn)
+                       prev_bb = bbn->in_bb [0];
+
        mono_unlink_bblock (cfg, bb, bbn);
        for (i = 0; i < bbn->out_count; ++i)
                mono_link_bblock (cfg, bb, bbn->out_bb [i]);
@@ -1003,8 +1029,10 @@ mono_merge_basic_blocks (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *b
                bb->last_ins = bbn->last_ins;
        }
 
-       for (prev_bb = cfg->bb_entry; prev_bb && prev_bb->next_bb != bbn; prev_bb = prev_bb->next_bb)
-               ;
+       if (!prev_bb) {
+               for (prev_bb = cfg->bb_entry; prev_bb && prev_bb->next_bb != bbn; prev_bb = prev_bb->next_bb)
+                       ;
+       }
        if (prev_bb) {
                prev_bb->next_bb = bbn->next_bb;
        } else {
@@ -1270,8 +1298,8 @@ mono_optimize_branches (MonoCompile *cfg)
                                        /* the block are in sequence anyway ... */
 
                                        /* branches to the following block can be removed */
-                                       if (bb->last_ins && bb->last_ins->opcode == OP_BR) {
-                                               bb->last_ins->opcode = OP_NOP;
+                                       if (bb->last_ins && bb->last_ins->opcode == OP_BR && !bbn->out_of_line) {
+                                               NULLIFY_INS (bb->last_ins);
                                                changed = TRUE;
                                                if (cfg->verbose_level > 2)
                                                        g_print ("br removal triggered %d -> %d\n", bb->block_num, bbn->block_num);
@@ -1419,7 +1447,7 @@ mono_optimize_branches (MonoCompile *cfg)
                                }
 
                                if (bb->last_ins && MONO_IS_COND_BRANCH_NOFP (bb->last_ins)) {
-                                       if (bb->last_ins->inst_false_bb && bb->last_ins->inst_false_bb->out_of_line && (bb->region == bb->last_ins->inst_false_bb->region)) {
+                                       if (bb->last_ins->inst_false_bb && bb->last_ins->inst_false_bb->out_of_line && (bb->region == bb->last_ins->inst_false_bb->region) && !cfg->disable_out_of_line_bblocks) {
                                                /* Reverse the branch */
                                                bb->last_ins->opcode = mono_reverse_branch_op (bb->last_ins->opcode);
                                                bbn = bb->last_ins->inst_false_bb;