OSDN Git Service

PR c/5420:
[pf3gnuchains/gcc-fork.git] / gcc / cfgcleanup.c
index 8cf7e68..13c5a8e 100644 (file)
@@ -177,6 +177,7 @@ try_simplify_condjump (cbranch_block)
                                                    jump_dest_block);
   cbranch_jump_edge->flags |= EDGE_FALLTHRU;
   cbranch_fallthru_edge->flags &= ~EDGE_FALLTHRU;
+  update_br_prob_note (cbranch_block);
 
   /* Delete the block with the unconditional jump, and clean up the mess.  */
   flow_delete_block (jump_block);
@@ -370,13 +371,13 @@ try_forward_edges (mode, b)
 {
   bool changed = false;
   edge e, next, *threaded_edges = NULL;
-  int nthreaded_edges = 0;
 
   for (e = b->succ; e; e = next)
     {
       basic_block target, first;
       int counter;
       bool threaded = false;
+      int nthreaded_edges = 0;
 
       next = e->succ_next;
 
@@ -412,7 +413,7 @@ try_forward_edges (mode, b)
              edge t = thread_jump (mode, e, target);
              if (t)
                {
-                 if (!nthreaded_edges)
+                 if (!threaded_edges)
                    threaded_edges = xmalloc (sizeof (*threaded_edges)
                                              * n_basic_blocks);
                  else
@@ -425,7 +426,10 @@ try_forward_edges (mode, b)
                        if (threaded_edges[i] == t)
                          break;
                      if (i < nthreaded_edges)
-                       break;
+                       {
+                         counter = n_basic_blocks;
+                         break;
+                       }
                    }
 
                  /* Detect an infinite loop across the start block.  */
@@ -521,17 +525,54 @@ try_forward_edges (mode, b)
              edge t;
 
              first->count -= edge_count;
-             first->succ->count -= edge_count;
+             if (first->count < 0)
+               first->count = 0;
              first->frequency -= edge_frequency;
+             if (first->frequency < 0)
+               first->frequency = 0;
              if (first->succ->succ_next)
                {
+                 edge e;
+                 int prob;
                  if (n >= nthreaded_edges)
                    abort ();
                  t = threaded_edges [n++];
+                 if (t->src != first)
+                   abort ();
+                 if (first->frequency)
+                   prob = edge_frequency * REG_BR_PROB_BASE / first->frequency;
+                 else
+                   prob = 0;
+                 if (prob > t->probability)
+                   prob = t->probability;
+                 t->probability -= prob;
+                 prob = REG_BR_PROB_BASE - prob;
+                 if (prob <= 0)
+                   {
+                     first->succ->probability = REG_BR_PROB_BASE;
+                     first->succ->succ_next->probability = 0;
+                   }
+                 else
+                   for (e = first->succ; e; e = e->succ_next)
+                     e->probability = ((e->probability * REG_BR_PROB_BASE)
+                                       / (double) prob);
+                 update_br_prob_note (first);
                }
              else
-               t = first->succ;
-
+               {
+                 /* It is possible that as the result of
+                    threading we've removed edge as it is
+                    threaded to the fallthru edge.  Avoid
+                    getting out of sync.  */
+                 if (n < nthreaded_edges
+                     && first == threaded_edges [n]->src)
+                   n++;
+                 t = first->succ;
+                }
+
+             t->count -= edge_count;
+             if (t->count < 0)
+               t->count = 0;
              first = t->dest;
            }
          while (first != target);
@@ -717,6 +758,7 @@ merge_blocks (e, b, c, mode)
   /* If B has a fallthru edge to C, no need to move anything.  */
   if (e->flags & EDGE_FALLTHRU)
     {
+      int b_index = b->index, c_index = c->index;
       /* We need to update liveness in case C already has broken liveness
         or B ends by conditional jump to next instructions that will be
         removed.  */
@@ -728,7 +770,7 @@ merge_blocks (e, b, c, mode)
 
       if (rtl_dump_file)
        fprintf (rtl_dump_file, "Merged %d and %d without moving.\n",
-                b->index, c->index);
+                 b_index, c_index);
 
       return true;
     }
@@ -1119,32 +1161,30 @@ outgoing_edges_match (mode, bb1, bb2)
         we will only have one branch prediction bit to work with.  Thus
         we require the existing branches to have probabilities that are
         roughly similar.  */
-      /* ??? We should use bb->frequency to allow merging in infrequently
-        executed blocks, but at the moment it is not available when
-        cleanup_cfg is run.  */
-      if (match && !optimize_size)
+      if (match
+         && !optimize_size
+         && bb1->frequency > BB_FREQ_MAX / 1000
+         && bb2->frequency > BB_FREQ_MAX / 1000)
        {
-         rtx note1, note2;
-         int prob1, prob2;
+         int prob2;
 
-         note1 = find_reg_note (bb1->end, REG_BR_PROB, 0);
-         note2 = find_reg_note (bb2->end, REG_BR_PROB, 0);
+         if (b1->dest == b2->dest)
+           prob2 = b2->probability;
+         else
+           /* Do not use f2 probability as f2 may be forwarded.  */
+           prob2 = REG_BR_PROB_BASE - b2->probability;
 
-         if (note1 && note2)
+         /* Fail if the difference in probabilities is
+            greater than 5%.  */
+         if (abs (b1->probability - prob2) > REG_BR_PROB_BASE / 20)
            {
-             prob1 = INTVAL (XEXP (note1, 0));
-             prob2 = INTVAL (XEXP (note2, 0));
-             if (reverse)
-               prob2 = REG_BR_PROB_BASE - prob2;
-
-             /* Fail if the difference in probabilities is
-                greater than 5%.  */
-             if (abs (prob1 - prob2) > REG_BR_PROB_BASE / 20)
-               return false;
-           }
+             if (rtl_dump_file)
+               fprintf (rtl_dump_file,
+                        "Outcomes of branch in bb %i and %i differs to much (%i %i)\n",
+                        bb1->index, bb2->index, b1->probability, prob2);
 
-         else if (note1 || note2)
-           return false;
+             return false;
+           }
        }
 
       if (rtl_dump_file && match)
@@ -1231,7 +1271,6 @@ try_crossjump_to_edge (mode, e1, e2)
   edge s;
   rtx last;
   rtx label;
-  rtx note;
 
   /* Search backward through forwarder blocks.  We don't need to worry
      about multiple entry or chained forwarders, as they will be optimized
@@ -1328,8 +1367,14 @@ try_crossjump_to_edge (mode, e1, e2)
       if (FORWARDER_BLOCK_P (s2->dest))
        {
          s2->dest->succ->count -= s2->count;
+         if (s2->dest->succ->count < 0)
+           s2->dest->succ->count = 0;
          s2->dest->count -= s2->count;
          s2->dest->frequency -= EDGE_FREQUENCY (s);
+         if (s2->dest->frequency < 0)
+           s2->dest->frequency = 0;
+         if (s2->dest->count < 0)
+           s2->dest->count = 0;
        }
 
       if (!redirect_to->frequency && !src1->frequency)
@@ -1341,9 +1386,7 @@ try_crossjump_to_edge (mode, e1, e2)
             / (redirect_to->frequency + src1->frequency));
     }
 
-  note = find_reg_note (redirect_to->end, REG_BR_PROB, 0);
-  if (note)
-    XEXP (note, 0) = GEN_INT (BRANCH_EDGE (redirect_to)->probability);
+  update_br_prob_note (redirect_to);
 
   /* Edit SRC1 to go to REDIRECT_TO at NEWPOS1.  */