OSDN Git Service

* config/i386/i386.c (ix86_expand_prologue): Use
[pf3gnuchains/gcc-fork.git] / gcc / cfgcleanup.c
index 62f7f30..32a9e65 100644 (file)
@@ -77,7 +77,6 @@ static bool label_is_jump_target_p (rtx, rtx);
 static bool tail_recursion_label_p (rtx);
 static void merge_blocks_move_predecessor_nojumps (basic_block, basic_block);
 static void merge_blocks_move_successor_nojumps (basic_block, basic_block);
-static basic_block merge_blocks (edge,basic_block,basic_block, int);
 static bool try_optimize_cfg (int);
 static bool try_simplify_condjump (basic_block);
 static bool try_forward_edges (int, basic_block);
@@ -119,6 +118,8 @@ try_simplify_condjump (basic_block cbranch_block)
   basic_block jump_block, jump_dest_block, cbranch_dest_block;
   edge cbranch_jump_edge, cbranch_fallthru_edge;
   rtx cbranch_insn;
+  rtx insn, next;
+  rtx end;
 
   /* Verify that there are exactly two successors.  */
   if (!cbranch_block->succ
@@ -171,6 +172,26 @@ try_simplify_condjump (basic_block cbranch_block)
   cbranch_fallthru_edge->flags &= ~EDGE_FALLTHRU;
   update_br_prob_note (cbranch_block);
 
+  end = jump_block->end;
+  /* Deleting a block may produce unreachable code warning even when we are
+     not deleting anything live.  Supress it by moving all the line number
+     notes out of the block.  */
+  for (insn = jump_block->head; insn != NEXT_INSN (jump_block->end);
+       insn = next)
+    {
+      next = NEXT_INSN (insn);
+      if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
+       {
+         if (insn == jump_block->end)
+           {
+             jump_block->end = PREV_INSN (insn);
+             if (insn == end)
+               break;
+           }
+         reorder_insns_nobb (insn, insn, end);
+         end = insn;
+       }
+    }
   /* Delete the block with the unconditional jump, and clean up the mess.  */
   delete_block (jump_block);
   tidy_fallthru_edge (cbranch_jump_edge, cbranch_block, cbranch_dest_block);
@@ -228,7 +249,7 @@ mark_effect (rtx exp, regset nonequal)
     }
 }
 
-/* Return nonzero if X is an register set in regset DATA.
+/* Return nonzero if X is a register set in regset DATA.
    Called via for_each_rtx.  */
 static int
 mentions_nonequal_regs (rtx *x, void *data)
@@ -640,7 +661,8 @@ label_is_jump_target_p (rtx label, rtx jump_insn)
 
   if (tablejump_p (jump_insn, NULL, &tmp))
     {
-      rtvec vec = XVEC (tmp, GET_CODE (tmp) == ADDR_DIFF_VEC);
+      rtvec vec = XVEC (PATTERN (tmp),
+                       GET_CODE (PATTERN (tmp)) == ADDR_DIFF_VEC);
       int i, veclen = GET_NUM_ELEM (vec);
 
       for (i = 0; i < veclen; ++i)
@@ -704,7 +726,7 @@ merge_blocks_move_predecessor_nojumps (basic_block a, basic_block b)
   link_block (a, b->prev_bb);
 
   /* Now blocks A and B are contiguous.  Merge them.  */
-  merge_blocks_nomove (a, b);
+  merge_blocks (a, b);
 }
 
 /* Blocks A and B are to be merged into a single block.  B has no outgoing
@@ -715,25 +737,20 @@ static void
 merge_blocks_move_successor_nojumps (basic_block a, basic_block b)
 {
   rtx barrier, real_b_end;
+  rtx label, table;
 
   real_b_end = b->end;
-  barrier = NEXT_INSN (b->end);
 
-  /* Recognize a jump table following block B.  */
-  if (barrier
-      && GET_CODE (barrier) == CODE_LABEL
-      && NEXT_INSN (barrier)
-      && GET_CODE (NEXT_INSN (barrier)) == JUMP_INSN
-      && (GET_CODE (PATTERN (NEXT_INSN (barrier))) == ADDR_VEC
-         || GET_CODE (PATTERN (NEXT_INSN (barrier))) == ADDR_DIFF_VEC))
+  /* If there is a jump table following block B temporarily add the jump table
+     to block B so that it will also be moved to the correct location.  */
+  if (tablejump_p (b->end, &label, &table)
+      && prev_active_insn (label) == b->end)
     {
-      /* Temporarily add the table jump insn to b, so that it will also
-        be moved to the correct location.  */
-      b->end = NEXT_INSN (barrier);
-      barrier = NEXT_INSN (b->end);
+      b->end = table;
     }
 
   /* There had better have been a barrier there.  Delete it.  */
+  barrier = NEXT_INSN (b->end);
   if (barrier && GET_CODE (barrier) == BARRIER)
     delete_insn (barrier);
 
@@ -758,23 +775,23 @@ merge_blocks_move_successor_nojumps (basic_block a, basic_block b)
             b->index, a->index);
 
   /* Now blocks A and B are contiguous.  Merge them.  */
-  merge_blocks_nomove (a, b);
+  merge_blocks (a, b);
 }
 
 /* Attempt to merge basic blocks that are potentially non-adjacent.
    Return NULL iff the attempt failed, otherwise return basic block
    where cleanup_cfg should continue.  Because the merging commonly
    moves basic block away or introduces another optimization
-   possiblity, return basic block just before B so cleanup_cfg don't
+   possibility, return basic block just before B so cleanup_cfg don't
    need to iterate.
 
    It may be good idea to return basic block before C in the case
    C has been moved after B and originally appeared earlier in the
-   insn seqeunce, but we have no infromation available about the
+   insn sequence, but we have no information available about the
    relative ordering of these two.  Hopefully it is not too common.  */
 
 static basic_block
-merge_blocks (edge e, basic_block b, basic_block c, int mode)
+merge_blocks_move (edge e, basic_block b, basic_block c, int mode)
 {
   basic_block next;
   /* If C has a tail recursion label, do not merge.  There is no
@@ -790,7 +807,7 @@ merge_blocks (edge e, basic_block b, basic_block c, int mode)
   if (e->flags & EDGE_FALLTHRU)
     {
       int b_index = b->index, c_index = c->index;
-      merge_blocks_nomove (b, c);
+      merge_blocks (b, c);
       update_forwarder_flag (b);
 
       if (rtl_dump_file)
@@ -1343,17 +1360,19 @@ outgoing_edges_match (int mode, basic_block bb1, basic_block bb2)
        return false;
     }
 
-  /* In case we do have EH edges, ensure we are in the same region.  */
-  if (nehedges1)
-    {
-      rtx n1 = find_reg_note (bb1->end, REG_EH_REGION, 0);
-      rtx n2 = find_reg_note (bb2->end, REG_EH_REGION, 0);
+  /* Ensure the same EH region.  */
+  {
+    rtx n1 = find_reg_note (bb1->end, REG_EH_REGION, 0);
+    rtx n2 = find_reg_note (bb2->end, REG_EH_REGION, 0);
 
-      if (XEXP (n1, 0) != XEXP (n2, 0))
-       return false;
-    }
+    if (!n1 && n2)
+      return false;
 
-  /* We don't need to match the rest of edges as above checks should be enought
+    if (n1 && (!n2 || XEXP (n1, 0) != XEXP (n2, 0)))
+      return false;
+  }
+
+  /* We don't need to match the rest of edges as above checks should be enough
      to ensure that they are equivalent.  */
   return true;
 }
@@ -1686,7 +1705,8 @@ try_optimize_cfg (int mode)
                             b->index);
 
                  delete_block (b);
-                 changed = true;
+                 if (!(mode & CLEANUP_CFGLAYOUT))
+                   changed = true;
                  b = c;
                }
 
@@ -1712,15 +1732,24 @@ try_optimize_cfg (int mode)
                {
                  rtx label = b->head;
 
-                 b->head = NEXT_INSN (b->head);
                  delete_insn_chain (label, label);
+                 /* In the case label is undeletable, move it after the
+                    BASIC_BLOCK note.  */
+                 if (NOTE_LINE_NUMBER (b->head) == NOTE_INSN_DELETED_LABEL)
+                   {
+                     rtx bb_note = NEXT_INSN (b->head);
+
+                     reorder_insns_nobb (label, label, bb_note);
+                     b->head = bb_note;
+                   }
                  if (rtl_dump_file)
                    fprintf (rtl_dump_file, "Deleted label in block %i.\n",
                             b->index);
                }
 
              /* If we fall through an empty block, we can remove it.  */
-             if (b->pred->pred_next == NULL
+             if (!(mode & CLEANUP_CFGLAYOUT)
+                 && b->pred->pred_next == NULL
                  && (b->pred->flags & EDGE_FALLTHRU)
                  && GET_CODE (b->head) != CODE_LABEL
                  && FORWARDER_BLOCK_P (b)
@@ -1746,21 +1775,39 @@ try_optimize_cfg (int mode)
                  && !(s->flags & EDGE_COMPLEX)
                  && (c = s->dest) != EXIT_BLOCK_PTR
                  && c->pred->pred_next == NULL
-                 && b != c
-                 /* If the jump insn has side effects,
-                    we can't kill the edge.  */
-                 && (GET_CODE (b->end) != JUMP_INSN
-                     || (flow2_completed
-                         ? simplejump_p (b->end)
-                         : onlyjump_p (b->end)))
-                 && (next = merge_blocks (s, b, c, mode)))
-               {
-                 b = next;
-                 changed_here = true;
+                 && b != c)
+               {
+                 /* When not in cfg_layout mode use code aware of reordering
+                    INSN.  This code possibly creates new basic blocks so it
+                    does not fit merge_blocks interface and is kept here in
+                    hope that it will become useless once more of compiler
+                    is transformed to use cfg_layout mode.  */
+                    
+                 if ((mode & CLEANUP_CFGLAYOUT)
+                     && can_merge_blocks_p (b, c))
+                   {
+                     merge_blocks (b, c);
+                     update_forwarder_flag (b);
+                     changed_here = true;
+                   }
+                 else if (!(mode & CLEANUP_CFGLAYOUT)
+                          /* If the jump insn has side effects,
+                             we can't kill the edge.  */
+                          && (GET_CODE (b->end) != JUMP_INSN
+                              || (flow2_completed
+                                  ? simplejump_p (b->end)
+                                  : onlyjump_p (b->end)))
+                          && (next = merge_blocks_move (s, b, c, mode)))
+                     {
+                       b = next;
+                       changed_here = true;
+                     }
                }
 
              /* Simplify branch over branch.  */
-             if ((mode & CLEANUP_EXPENSIVE) && try_simplify_condjump (b))
+             if ((mode & CLEANUP_EXPENSIVE)
+                  && !(mode & CLEANUP_CFGLAYOUT)
+                  && try_simplify_condjump (b))
                changed_here = true;
 
              /* If B has a single outgoing edge, but uses a