First set of licensing changes
[mono.git] / mono / mini / branch-opts.c
index b31ea8d602b8f0dab7d2b632f06d0467835f7eda..7b2bedd56470c901f27cba63a015a2309c382c16 100644 (file)
@@ -6,6 +6,7 @@
  *
  * (C) 2005 Ximian, Inc.  http://www.ximian.com
  * Copyright 2011 Xamarin Inc.  http://www.xamarin.com
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
  #include "mini.h"
 
@@ -44,7 +45,7 @@ mono_branch_optimize_exception_target (MonoCompile *cfg, MonoBasicBlock *bb, con
        if (bb->region == -1 || !MONO_BBLOCK_IS_IN_REGION (bb, MONO_REGION_TRY))
                return NULL;
 
-       exclass = mono_class_from_name (mono_get_corlib (), "System", exname);
+       exclass = mono_class_load_from_name (mono_get_corlib (), "System", exname);
        /* search for the handler */
        for (i = 0; i < header->num_clauses; ++i) {
                clause = &header->clauses [i];
@@ -85,7 +86,7 @@ mono_branch_optimize_exception_target (MonoCompile *cfg, MonoBasicBlock *bb, con
                                                MONO_INST_NEW (cfg, jump, OP_BR);
 
                                                /* Allocate memory for our branch target */
-                                               jump->inst_i1 = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
+                                               jump->inst_i1 = (MonoInst *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
                                                jump->inst_true_bb = targetbb;
 
                                                if (cfg->verbose_level > 2) 
@@ -278,6 +279,7 @@ mono_if_conversion (MonoCompile *cfg)
 #ifdef MONO_ARCH_HAVE_CMOV_OPS
        MonoBasicBlock *bb;
        gboolean changed = FALSE;
+       int filter = FILTER_NOP | FILTER_IL_SEQ_POINT;
 
        if (!(cfg->opt & MONO_OPT_CMOV))
                return;
@@ -317,14 +319,15 @@ mono_if_conversion (MonoCompile *cfg)
                        int dreg, tmp_reg;
                        CompType comp_type;
 
-                       if (bb->last_ins && (bb->last_ins->opcode == OP_BR_REG || bb->last_ins->opcode == OP_BR))
+                       branch = mono_bb_last_inst (bb, filter);
+
+                       if (!branch || branch->opcode == OP_BR_REG || branch->opcode == OP_BR)
                                continue;
 
                        /* Find the compare instruction */
-                       if (!bb->last_ins || !bb->last_ins->prev)
+                       compare = mono_inst_prev (branch, filter);
+                       if (!compare)
                                continue;
-                       branch = bb->last_ins;
-                       compare = branch->prev;
 
                        if (!MONO_IS_COND_BRANCH_OP (branch))
                                /* This can happen if a cond branch is optimized away */
@@ -338,22 +341,19 @@ mono_if_conversion (MonoCompile *cfg)
                         * variable.
                         */
                        /* FIXME: Get rid of the nops earlier */
-                       ins1 = true_bb->code;
-                       while (ins1 && ins1->opcode == OP_NOP)
-                               ins1 = ins1->next;
-                       ins2 = false_bb->code;
-                       while (ins2 && ins2->opcode == OP_NOP)
-                               ins2 = ins2->next;
+                       ins1 = mono_bb_first_inst (true_bb, filter);
+                       ins2 = mono_bb_first_inst (false_bb, filter);
+
                        if (!(ins1 && ins2 && ins1->dreg == ins2->dreg && ins1->dreg != -1))
                                continue;
 
                        simple = TRUE;
                        for (tmp = ins1->next; tmp; tmp = tmp->next)
-                               if (!((tmp->opcode == OP_NOP) || (tmp->opcode == OP_BR)))
+                               if (!((tmp->opcode == OP_NOP) || (tmp->opcode == OP_IL_SEQ_POINT) || (tmp->opcode == OP_BR)))
                                        simple = FALSE;
                                        
                        for (tmp = ins2->next; tmp; tmp = tmp->next)
-                               if (!((tmp->opcode == OP_NOP) || (tmp->opcode == OP_BR)))
+                               if (!((tmp->opcode == OP_NOP) || (tmp->opcode == OP_IL_SEQ_POINT) || (tmp->opcode == OP_BR)))
                                        simple = FALSE;
 
                        if (!simple)
@@ -381,7 +381,7 @@ mono_if_conversion (MonoCompile *cfg)
                        if (cfg->verbose_level > 2) {
                                printf ("\tBranch -> CMove optimization in BB%d on\n", bb->block_num);
                                printf ("\t\t"); mono_print_ins (compare);
-                               printf ("\t\t"); mono_print_ins (compare->next);
+                               printf ("\t\t"); mono_print_ins (mono_inst_next (compare, filter));
                                printf ("\t\t"); mono_print_ins (ins1);
                                printf ("\t\t"); mono_print_ins (ins2);
                        }
@@ -489,15 +489,15 @@ mono_if_conversion (MonoCompile *cfg)
                                next_bb = bb2;
                        }
 
-                       ins1 = code_bb->code;
+                       ins1 = mono_bb_first_inst (code_bb, filter);
 
                        if (!ins1)
                                continue;
 
                        /* Check that code_bb is simple */
                        simple = TRUE;
-                       for (tmp = ins1->next; tmp; tmp = tmp->next)
-                               if (!((tmp->opcode == OP_NOP) || (tmp->opcode == OP_BR)))
+                       for (tmp = ins1; tmp; tmp = tmp->next)
+                               if (!((tmp->opcode == OP_NOP) || (tmp->opcode == OP_IL_SEQ_POINT) || (tmp->opcode == OP_BR)))
                                        simple = FALSE;
 
                        if (!simple)
@@ -507,15 +507,15 @@ mono_if_conversion (MonoCompile *cfg)
                        if (!MONO_INS_HAS_NO_SIDE_EFFECT (ins1))
                                continue;
 
-                       if (bb->last_ins && bb->last_ins->opcode == OP_BR_REG)
+                       branch = mono_bb_last_inst (bb, filter);
+
+                       if (!branch || branch->opcode == OP_BR_REG)
                                continue;
 
                        /* Find the compare instruction */
-
-                       if (!bb->last_ins || !bb->last_ins->prev)
+                       compare = mono_inst_prev (branch, filter);
+                       if (!compare)
                                continue;
-                       branch = bb->last_ins;
-                       compare = branch->prev;
 
                        if (!MONO_IS_COND_BRANCH_OP (branch))
                                /* This can happen if a cond branch is optimized away */
@@ -545,7 +545,7 @@ mono_if_conversion (MonoCompile *cfg)
                        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);
-                               printf ("\t\t"); mono_print_ins (compare->next);
+                               printf ("\t\t"); mono_print_ins (mono_inst_next (compare, filter));
                                printf ("\t\t"); mono_print_ins (ins1);
                        }
 
@@ -627,8 +627,8 @@ mono_if_conversion (MonoCompile *cfg)
         * optimize_branches () since the IR is already optimized.
         */
        for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-               MonoBasicBlock *bb1, *bb2, *true_bb, *false_bb, *next_bb;
-               MonoInst *branch1, *branch2, *compare1, *ins;
+               MonoBasicBlock *bb1, *bb2, *next_bb;
+               MonoInst *branch1, *branch2, *compare1, *ins, *next;
 
                /* Look for the IR code generated from if (<var> < 0 || v > <limit>)
                 * after branch opts which is:
@@ -654,39 +654,38 @@ mono_if_conversion (MonoCompile *cfg)
                next_bb = bb2;
 
                /* Check first branch */
-               branch1 = bb->last_ins;
+               branch1 = mono_bb_last_inst (bb, filter);
                if (!(branch1 && ((branch1->opcode == OP_IBLT) || (branch1->opcode == OP_LBLT)) && (branch1->inst_false_bb == next_bb)))
                        continue;
 
-               true_bb = branch1->inst_true_bb;
-
                /* Check second branch */
-               branch2 = next_bb->last_ins;
+               branch2 = mono_bb_last_inst (next_bb, filter);
                if (!branch2)
                        continue;
 
                /* mcs sometimes generates inverted branches */
                if (((branch2->opcode == OP_IBGT) || (branch2->opcode == OP_LBGT)) && branch2->inst_true_bb == branch1->inst_true_bb)
-                       false_bb = branch2->inst_false_bb;
+                       ;
                else if (((branch2->opcode == OP_IBLE) || (branch2->opcode == OP_LBLE)) && branch2->inst_false_bb == branch1->inst_true_bb)
-                       false_bb = branch2->inst_true_bb;
+                       ;
                else
                        continue;
 
                /* Check first compare */
-               compare1 = bb->last_ins->prev;
+               compare1 = mono_inst_prev (mono_bb_last_inst (bb, filter), filter);
                if (!(compare1 && ((compare1->opcode == OP_ICOMPARE_IMM) || (compare1->opcode == OP_LCOMPARE_IMM)) && compare1->inst_imm == 0))
                        continue;
 
                /* Check second bblock */
-               ins = next_bb->code;
+               ins = mono_bb_first_inst (next_bb, filter);
                if (!ins)
                        continue;
-               if (((ins->opcode == OP_ICOMPARE_IMM) || (ins->opcode == OP_LCOMPARE_IMM)) && ins->sreg1 == compare1->sreg1 && ins->next == branch2) {
+               next = mono_inst_next (ins, filter);
+               if (((ins->opcode == OP_ICOMPARE_IMM) || (ins->opcode == OP_LCOMPARE_IMM)) && ins->sreg1 == compare1->sreg1 && next == branch2) {
                        /* The second arg must be positive */
                        if (ins->inst_imm < 0)
                                continue;
-               } else if (((ins->opcode == OP_LDLEN) || (ins->opcode == OP_STRLEN)) && ins->dreg != compare1->sreg1 && ins->next && ins->next->opcode == OP_ICOMPARE && ins->next->sreg1 == compare1->sreg1 && ins->next->sreg2 == ins->dreg && ins->next->next == branch2) {
+               } else if (((ins->opcode == OP_LDLEN) || (ins->opcode == OP_STRLEN)) && ins->dreg != compare1->sreg1 && next && next->opcode == OP_ICOMPARE && next->sreg1 == compare1->sreg1 && next->sreg2 == ins->dreg && mono_inst_next (next, filter) == branch2) {
                        /* Another common case: if (index < 0 || index > arr.Length) */
                } else {
                        continue;
@@ -695,7 +694,7 @@ mono_if_conversion (MonoCompile *cfg)
                if (cfg->verbose_level > 2) {
                        printf ("\tSigned->unsigned compare optimization in BB%d on\n", bb->block_num);
                        printf ("\t\t"); mono_print_ins (compare1);
-                       printf ("\t\t"); mono_print_ins (compare1->next);
+                       printf ("\t\t"); mono_print_ins (mono_inst_next (compare1, filter));
                        printf ("\t\t"); mono_print_ins (ins);
                }
 
@@ -853,7 +852,7 @@ replace_out_block_in_code (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBl
                                        ins->inst_false_bb = repl;
                        } else if (MONO_IS_JUMP_TABLE (ins)) {
                                int i;
-                               MonoJumpInfoBBTable *table = MONO_JUMP_TABLE_FROM_INS (ins);
+                               MonoJumpInfoBBTable *table = (MonoJumpInfoBBTable *)MONO_JUMP_TABLE_FROM_INS (ins);
                                for (i = 0; i < table->table_size; i++ ) {
                                        if (table->table [i] == orig)
                                                table->table [i] = repl;
@@ -997,7 +996,7 @@ mono_merge_basic_blocks (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *b
                for (inst = bb->code; inst != NULL; inst = inst->next) {
                        if (MONO_IS_JUMP_TABLE (inst)) {
                                int i;
-                               MonoJumpInfoBBTable *table = MONO_JUMP_TABLE_FROM_INS (inst);
+                               MonoJumpInfoBBTable *table = (MonoJumpInfoBBTable *)MONO_JUMP_TABLE_FROM_INS (inst);
                                for (i = 0; i < table->table_size; i++ ) {
                                        /* Might be already NULL from a previous merge */
                                        if (table->table [i])
@@ -1139,7 +1138,7 @@ mono_remove_critical_edges (MonoCompile *cfg)
                                 * overwrite the sreg1 of the ins.
                                 */
                                if ((in_bb->out_count > 1) || (in_bb->out_count == 1 && in_bb->last_ins && in_bb->last_ins->opcode == OP_BR_REG)) {
-                                       MonoBasicBlock *new_bb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
+                                       MonoBasicBlock *new_bb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
                                        new_bb->block_num = cfg->num_bblocks++;
 //                                     new_bb->real_offset = bb->real_offset;
                                        new_bb->region = bb->region;
@@ -1163,7 +1162,7 @@ mono_remove_critical_edges (MonoCompile *cfg)
                                                        /* We cannot add any inst to the entry BB, so we must */
                                                        /* put a new BB in the middle to hold the OP_BR */
                                                        MonoInst *jump;
-                                                       MonoBasicBlock *new_bb_after_entry = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
+                                                       MonoBasicBlock *new_bb_after_entry = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
                                                        new_bb_after_entry->block_num = cfg->num_bblocks++;
 //                                                     new_bb_after_entry->real_offset = bb->real_offset;
                                                        new_bb_after_entry->region = bb->region;
@@ -1192,10 +1191,10 @@ mono_remove_critical_edges (MonoCompile *cfg)
                                        previous_bb = new_bb;
                                        
                                        /* Setup in_bb and out_bb */
-                                       new_bb->in_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
+                                       new_bb->in_bb = (MonoBasicBlock **)mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
                                        new_bb->in_bb [0] = in_bb;
                                        new_bb->in_count = 1;
-                                       new_bb->out_bb = mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
+                                       new_bb->out_bb = (MonoBasicBlock **)mono_mempool_alloc ((cfg)->mempool, sizeof (MonoBasicBlock*));
                                        new_bb->out_bb [0] = bb;
                                        new_bb->out_count = 1;
                                        
@@ -1240,9 +1239,11 @@ mono_remove_critical_edges (MonoCompile *cfg)
 void
 mono_optimize_branches (MonoCompile *cfg)
 {
-       int i, changed = FALSE;
+       int i, count = 0, changed = FALSE;
        MonoBasicBlock *bb, *bbn;
        guint32 niterations;
+       MonoInst *bbn_first_inst;
+       int filter = FILTER_IL_SEQ_POINT;
 
        /*
         * Some crazy loops could cause the code below to go into an infinite
@@ -1261,6 +1262,11 @@ mono_optimize_branches (MonoCompile *cfg)
 
                /* we skip the entry block (exit is handled specially instead ) */
                for (previous_bb = cfg->bb_entry, bb = cfg->bb_entry->next_bb; bb; previous_bb = bb, bb = bb->next_bb) {
+                       count ++;
+                       if (count == 1000) {
+                               mono_threads_safepoint ();
+                               count = 0;
+                       }
                        /* dont touch code inside exception clauses */
                        if (bb->region != -1)
                                continue;
@@ -1339,17 +1345,18 @@ mono_optimize_branches (MonoCompile *cfg)
 
                                if (bb->last_ins && bb->last_ins->opcode == OP_BR) {
                                        bbn = bb->last_ins->inst_target_bb;
-                                       if (bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
-                                               bbn->code->inst_target_bb != bbn &&
-                                           bbn->code->inst_target_bb->region == bb->region) {
+                                       bbn_first_inst = mono_bb_first_inst (bbn, filter);
+                                       if (bb->region == bbn->region && bbn_first_inst && bbn_first_inst->opcode == OP_BR &&
+                                               bbn_first_inst->inst_target_bb != bbn &&
+                                               bbn_first_inst->inst_target_bb->region == bb->region) {
                                                
                                                if (cfg->verbose_level > 2)
-                                                       g_print ("branch to branch triggered %d -> %d -> %d\n", bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num);
+                                                       g_print ("branch to branch triggered %d -> %d -> %d\n", bb->block_num, bbn->block_num, bbn_first_inst->inst_target_bb->block_num);
 
                                                replace_in_block (bbn, bb, NULL);
-                                               replace_out_block (bb, bbn, bbn->code->inst_target_bb);
-                                               mono_link_bblock (cfg, bb, bbn->code->inst_target_bb);
-                                               bb->last_ins->inst_target_bb = bbn->code->inst_target_bb;
+                                               replace_out_block (bb, bbn, bbn_first_inst->inst_target_bb);
+                                               mono_link_bblock (cfg, bb, bbn_first_inst->inst_target_bb);
+                                               bb->last_ins->inst_target_bb = bbn_first_inst->inst_target_bb;
                                                changed = TRUE;
                                                continue;
                                        }
@@ -1385,12 +1392,13 @@ mono_optimize_branches (MonoCompile *cfg)
                                                continue;
                                        }
                                        bbn = bb->last_ins->inst_true_bb;
-                                       if (bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
-                                           bbn->code->inst_target_bb->region == bb->region) {
+                                       bbn_first_inst = mono_bb_first_inst (bbn, filter);
+                                       if (bb->region == bbn->region && bbn_first_inst && bbn_first_inst->opcode == OP_BR &&
+                                           bbn_first_inst->inst_target_bb->region == bb->region) {
                                                if (cfg->verbose_level > 2)             
                                                        g_print ("cbranch1 to branch triggered %d -> (%d) %d (0x%02x)\n", 
-                                                                bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num, 
-                                                                bbn->code->opcode);
+                                                                bb->block_num, bbn->block_num, bbn_first_inst->inst_target_bb->block_num, 
+                                                                bbn_first_inst->opcode);
 
                                                /* 
                                                 * Unlink, then relink bblocks to avoid various
@@ -1400,7 +1408,7 @@ mono_optimize_branches (MonoCompile *cfg)
                                                mono_unlink_bblock (cfg, bb, bb->last_ins->inst_true_bb);
                                                mono_unlink_bblock (cfg, bb, bb->last_ins->inst_false_bb);
 
-                                               bb->last_ins->inst_true_bb = bbn->code->inst_target_bb;
+                                               bb->last_ins->inst_true_bb = bbn_first_inst->inst_target_bb;
 
                                                mono_link_bblock (cfg, bb, bb->last_ins->inst_true_bb);
                                                mono_link_bblock (cfg, bb, bb->last_ins->inst_false_bb);
@@ -1410,17 +1418,18 @@ mono_optimize_branches (MonoCompile *cfg)
                                        }
 
                                        bbn = bb->last_ins->inst_false_bb;
-                                       if (bbn && bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
-                                           bbn->code->inst_target_bb->region == bb->region) {
+                                       bbn_first_inst = mono_bb_first_inst (bbn, filter);
+                                       if (bbn && bb->region == bbn->region && bbn_first_inst && bbn_first_inst->opcode == OP_BR &&
+                                               bbn_first_inst->inst_target_bb->region == bb->region) {
                                                if (cfg->verbose_level > 2)
                                                        g_print ("cbranch2 to branch triggered %d -> (%d) %d (0x%02x)\n", 
-                                                                bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num, 
-                                                                bbn->code->opcode);
+                                                                bb->block_num, bbn->block_num, bbn_first_inst->inst_target_bb->block_num, 
+                                                                bbn_first_inst->opcode);
 
                                                mono_unlink_bblock (cfg, bb, bb->last_ins->inst_true_bb);
                                                mono_unlink_bblock (cfg, bb, bb->last_ins->inst_false_bb);
 
-                                               bb->last_ins->inst_false_bb = bbn->code->inst_target_bb;
+                                               bb->last_ins->inst_false_bb = bbn_first_inst->inst_target_bb;
 
                                                mono_link_bblock (cfg, bb, bb->last_ins->inst_true_bb);
                                                mono_link_bblock (cfg, bb, bb->last_ins->inst_false_bb);