OSDN Git Service

* bb-reorder.c (make_reorder_chain_1): Modified.
[pf3gnuchains/gcc-fork.git] / gcc / cfgrtl.c
index 5bf33bc..d2025b8 100644 (file)
@@ -1,6 +1,6 @@
 /* Control flow graph manipulation code for GNU compiler.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -56,6 +56,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "toplev.h"
 #include "tm_p.h"
 #include "obstack.h"
+#include "insn-config.h"
 
 /* Stubs in case we don't have a return insn.  */
 #ifndef HAVE_return
@@ -88,7 +89,8 @@ can_delete_note_p (note)
      rtx note;
 {
   return (NOTE_LINE_NUMBER (note) == NOTE_INSN_DELETED
-         || NOTE_LINE_NUMBER (note) == NOTE_INSN_BASIC_BLOCK);
+         || NOTE_LINE_NUMBER (note) == NOTE_INSN_BASIC_BLOCK
+          || NOTE_LINE_NUMBER (note) == NOTE_INSN_PREDICTION);
 }
 
 /* True if a given label can be deleted.  */
@@ -101,8 +103,7 @@ can_delete_label_p (label)
          /* User declared labels must be preserved.  */
          && LABEL_NAME (label) == 0
          && !in_expr_list_p (forced_labels, label)
-         && !in_expr_list_p (label_value_list, label)
-         && !in_expr_list_p (exception_handler_labels, label));
+         && !in_expr_list_p (label_value_list, label));
 }
 
 /* Delete INSN by patching it out.  Return the next insn.  */
@@ -247,12 +248,14 @@ delete_insn_chain_and_edges (first, last)
    the note and basic block struct in BB_NOTE, if any and do not grow
    BASIC_BLOCK chain and should be used directly only by CFG construction code.
    END can be NULL in to create new empty basic block before HEAD.  Both END
-   and HEAD can be NULL to create basic block at the end of INSN chain.  */
+   and HEAD can be NULL to create basic block at the end of INSN chain.
+   AFTER is the basic block we should be put after.  */
 
 basic_block
-create_basic_block_structure (index, head, end, bb_note)
+create_basic_block_structure (index, head, end, bb_note, after)
      int index;
      rtx head, end, bb_note;
+     basic_block after;
 {
   basic_block bb;
 
@@ -310,6 +313,7 @@ create_basic_block_structure (index, head, end, bb_note)
   bb->end = end;
   bb->index = index;
   bb->flags = BB_NEW;
+  link_block (bb, after);
   BASIC_BLOCK (index) = bb;
   if (basic_block_for_insn)
     update_bb_for_insn (bb);
@@ -322,17 +326,18 @@ create_basic_block_structure (index, head, end, bb_note)
 }
 
 /* Create new basic block consisting of instructions in between HEAD and END
-   and place it to the BB chain at position INDEX.  END can be NULL in to
+   and place it to the BB chain after block AFTER.  END can be NULL in to
    create new empty basic block before HEAD.  Both END and HEAD can be NULL to
    create basic block at the end of INSN chain.  */
 
 basic_block
-create_basic_block (index, head, end)
-     int index;
+create_basic_block (head, end, after)
      rtx head, end;
+     basic_block after;
 {
   basic_block bb;
   int i;
+  int index = after->index + 1;
 
   /* Place the new block just after the block being split.  */
   VARRAY_GROW (basic_block_info, ++n_basic_blocks);
@@ -348,7 +353,7 @@ create_basic_block (index, head, end)
       tmp->index = i;
     }
 
-  bb = create_basic_block_structure (index, head, end, NULL);
+  bb = create_basic_block_structure (index, head, end, NULL, after);
   bb->aux = NULL;
   return bb;
 }
@@ -362,7 +367,7 @@ create_basic_block (index, head, end)
    to post-process the stream to remove empty blocks, loops, ranges, etc.  */
 
 int
-flow_delete_block (b)
+flow_delete_block_noexpunge (b)
      basic_block b;
 {
   int deleted_handler = 0;
@@ -375,6 +380,16 @@ flow_delete_block (b)
      and remove the associated NOTE_INSN_EH_REGION_BEG and
      NOTE_INSN_EH_REGION_END notes.  */
 
+  /* Get rid of all NOTE_INSN_PREDICTIONs hanging before the block.  */
+  
+  for (insn = PREV_INSN (b->head); insn; insn = PREV_INSN (insn))
+    {
+      if (GET_CODE (insn) != NOTE)
+        break;
+      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_PREDICTION)
+        NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+    }
+
   insn = b->head;
 
   never_reached_warning (insn, b->end);
@@ -411,6 +426,15 @@ flow_delete_block (b)
   b->pred = NULL;
   b->succ = NULL;
 
+  return deleted_handler;
+}
+
+int
+flow_delete_block (b)
+     basic_block b;
+{
+  int deleted_handler = flow_delete_block_noexpunge (b);
+  
   /* Remove the basic block from the array, and compact behind it.  */
   expunge_block (b);
 
@@ -517,7 +541,7 @@ split_block (bb, insn)
     return 0;
 
   /* Create the new basic block.  */
-  new_bb = create_basic_block (bb->index + 1, NEXT_INSN (insn), bb->end);
+  new_bb = create_basic_block (NEXT_INSN (insn), bb->end, bb);
   new_bb->count = bb->count;
   new_bb->frequency = bb->frequency;
   new_bb->loop_depth = bb->loop_depth;
@@ -546,6 +570,15 @@ split_block (bb, insn)
       propagate_block (new_bb, new_bb->global_live_at_start, NULL, NULL, 0);
       COPY_REG_SET (bb->global_live_at_end,
                    new_bb->global_live_at_start);
+#ifdef HAVE_conditional_execution
+      /* In the presence of conditional execution we are not able to update
+        liveness precisely.  */
+      if (reload_completed)
+       {
+         bb->flags |= BB_DIRTY;
+         new_bb->flags |= BB_DIRTY;
+       }
+#endif
     }
 
   return new_edge;
@@ -651,9 +684,9 @@ merge_blocks_nomove (a, b)
          rtx x;
 
          for (x = a_end; x != b_end; x = NEXT_INSN (x))
-           BLOCK_FOR_INSN (x) = a;
+           set_block_for_insn (x, a);
 
-         BLOCK_FOR_INSN (b_end) = a;
+         set_block_for_insn (b_end, a);
        }
 
       a_end = b_end;
@@ -695,7 +728,7 @@ try_redirect_by_replacing_jump (e, target)
   basic_block src = e->src;
   rtx insn = src->end, kill_from;
   edge tmp;
-  rtx set;
+  rtx set, table;
   int fallthru = 0;
 
   /* Verify that all targets will be TARGET.  */
@@ -705,6 +738,12 @@ try_redirect_by_replacing_jump (e, target)
 
   if (tmp || !onlyjump_p (insn))
     return false;
+  if (reload_completed && JUMP_LABEL (insn)
+      && (table = NEXT_INSN (JUMP_LABEL (insn))) != NULL_RTX
+      && GET_CODE (table) == JUMP_INSN
+      && (GET_CODE (PATTERN (table)) == ADDR_VEC
+         || GET_CODE (PATTERN (table)) == ADDR_DIFF_VEC))
+    return false;
 
   /* Avoid removing branch with side effects.  */
   set = single_set (insn);
@@ -963,7 +1002,7 @@ force_nonfallthru_and_redirect (e, target)
       /* We can't redirect the entry block.  Create an empty block at the
          start of the function which we use to add the new jump.  */
       edge *pe1;
-      basic_block bb = create_basic_block (0, e->dest->head, NULL);
+      basic_block bb = create_basic_block (e->dest->head, NULL, ENTRY_BLOCK_PTR);
 
       /* Change the existing edge's source to be the new block, and add
         a new edge from the entry block to the new block.  */
@@ -984,7 +1023,7 @@ force_nonfallthru_and_redirect (e, target)
       /* Create the new structures.  */
       note = last_loop_beg_note (e->src->end);
       jump_block
-       = create_basic_block (e->src->index + 1, NEXT_INSN (note), NULL);
+       = create_basic_block (NEXT_INSN (note), NULL, e->src);
       jump_block->count = e->count;
       jump_block->frequency = EDGE_FREQUENCY (e);
       jump_block->loop_depth = target->loop_depth;
@@ -1086,8 +1125,9 @@ tidy_fallthru_edge (e, b, c)
      So search through a sequence of barriers, labels, and notes for
      the head of block C and assert that we really do fall through.  */
 
-  if (next_real_insn (b->end) != next_real_insn (PREV_INSN (c->head)))
-    return;
+  for (q = NEXT_INSN (b->end); q != c->head; q = NEXT_INSN (q))
+    if (INSN_P (q))
+      return;
 
   /* Remove what will soon cease being the jump insn from the source block.
      If block B consisted only of this single jump, turn it into a deleted
@@ -1132,8 +1172,8 @@ tidy_fallthru_edges ()
 
   for (i = 1; i < n_basic_blocks; i++)
     {
-      basic_block b = BASIC_BLOCK (i - 1);
       basic_block c = BASIC_BLOCK (i);
+      basic_block b = c->prev_bb;
       edge s;
 
       /* We care about simple conditional or unconditional jumps with
@@ -1250,8 +1290,7 @@ split_edge (edge_in)
   else
     before = NULL_RTX;
 
-  bb = create_basic_block (edge_in->dest == EXIT_BLOCK_PTR ? n_basic_blocks
-                          : edge_in->dest->index, before, NULL);
+  bb = create_basic_block (before, NULL, edge_in->dest->prev_bb);
   bb->count = edge_in->count;
   bb->frequency = EDGE_FREQUENCY (edge_in);
 
@@ -1683,12 +1722,49 @@ verify_flow_info ()
   size_t *edge_checksum;
   rtx x;
   int i, last_bb_num_seen, num_bb_notes, err = 0;
+  basic_block bb, last_bb_seen;
 
   bb_info = (basic_block *) xcalloc (max_uid, sizeof (basic_block));
   last_visited = (basic_block *) xcalloc (n_basic_blocks + 2,
                                          sizeof (basic_block));
   edge_checksum = (size_t *) xcalloc (n_basic_blocks + 2, sizeof (size_t));
 
+  /* Check bb chain & numbers.  */
+  last_bb_seen = ENTRY_BLOCK_PTR;
+  FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR->next_bb, NULL, next_bb)
+    {
+      if (bb != EXIT_BLOCK_PTR
+         && bb != BASIC_BLOCK (bb->index))
+       {
+         error ("bb %d on wrong place", bb->index);
+         err = 1;
+       }
+
+      if (bb->prev_bb != last_bb_seen)
+       {
+         error ("prev_bb of %d should be %d, not %d",
+                bb->index, last_bb_seen->index, bb->prev_bb->index);
+         err = 1;
+       }
+
+      /* For now, also check that we didn't change the order.  */
+      if (bb != EXIT_BLOCK_PTR && bb->index != last_bb_seen->index + 1)
+       {
+         error ("Wrong order of blocks %d and %d",
+                last_bb_seen->index, bb->index);
+         err = 1;
+       }
+
+      if (bb == EXIT_BLOCK_PTR && last_bb_seen->index != n_basic_blocks - 1)
+       {
+         error ("Only %d of %d blocks in chain",
+                last_bb_seen->index + 1, n_basic_blocks);
+         err = 1;
+       }
+
+      last_bb_seen = bb;
+    }
+
   for (i = n_basic_blocks - 1; i >= 0; i--)
     {
       basic_block bb = BASIC_BLOCK (i);
@@ -1746,6 +1822,7 @@ verify_flow_info ()
 
       if (INSN_P (bb->end)
          && (note = find_reg_note (bb->end, REG_BR_PROB, NULL_RTX))
+         && bb->succ && bb->succ->succ_next
          && any_condjump_p (bb->end))
        {
          if (INTVAL (XEXP (note, 0)) != BRANCH_EDGE (bb)->probability)
@@ -1810,7 +1887,7 @@ verify_flow_info ()
            {
              rtx insn;
 
-             if (e->src->index + 1 != e->dest->index)
+             if (e->src->next_bb != e->dest)
                {
                  error
                    ("verify_flow_info: Incorrect blocks for fallthru %i->%i",
@@ -1875,7 +1952,7 @@ verify_flow_info ()
          err = 1;
        }
       if (n_branch != 1 && any_condjump_p (bb->end)
-         && JUMP_LABEL (bb->end) != BASIC_BLOCK (bb->index + 1)->head)
+         && JUMP_LABEL (bb->end) != bb->next_bb->head)
        {
          error ("Wrong amount of branch edges after conditional jump %i", bb->index);
          err = 1;
@@ -2094,19 +2171,29 @@ purge_dead_edges (bb)
        remove_note (insn, note);
     }
 
-  /* Cleanup abnormal edges caused by throwing insns that have been
-     eliminated.  */
-  if (! can_throw_internal (bb->end))
-    for (e = bb->succ; e; e = next)
-      {
-       next = e->succ_next;
-       if (e->flags & EDGE_EH)
-         {
-           remove_edge (e);
-           bb->flags |= BB_DIRTY;
-           purged = true;
-         }
-      }
+  /* Cleanup abnormal edges caused by exceptions or non-local gotos.  */
+  for (e = bb->succ; e; e = next)
+    {
+      next = e->succ_next;
+      if (e->flags & EDGE_EH)
+       {
+         if (can_throw_internal (bb->end))
+           continue;
+       }
+      else if (e->flags & EDGE_ABNORMAL_CALL)
+       {
+         if (GET_CODE (bb->end) == CALL_INSN
+             && (! (note = find_reg_note (insn, REG_EH_REGION, NULL))
+                 || INTVAL (XEXP (note, 0)) >= 0))
+           continue;
+       }
+      else
+       continue;
+
+      remove_edge (e);
+      bb->flags |= BB_DIRTY;
+      purged = true;
+    }
 
   if (GET_CODE (insn) == JUMP_INSN)
     {
@@ -2139,17 +2226,26 @@ purge_dead_edges (bb)
  
          e->flags &= ~EDGE_ABNORMAL;
 
-         /* Check purposes we can have edge.  */
-         if ((e->flags & EDGE_FALLTHRU)
-             && any_condjump_p (insn))
+         /* See if this edge is one we should keep.  */
+         if ((e->flags & EDGE_FALLTHRU) && any_condjump_p (insn))
+           /* A conditional jump can fall through into the next
+              block, so we should keep the edge.  */
            continue;
          else if (e->dest != EXIT_BLOCK_PTR
                   && e->dest->head == JUMP_LABEL (insn))
+           /* If the destination block is the target of the jump,
+              keep the edge.  */
+           continue;
+         else if (e->dest == EXIT_BLOCK_PTR && returnjump_p (insn))
+           /* If the destination block is the exit block, and this
+              instruction is a return, then keep the edge.  */
            continue;
-         else if (e->dest == EXIT_BLOCK_PTR
-                  && returnjump_p (insn))
+         else if ((e->flags & EDGE_EH) && can_throw_internal (insn))
+           /* Keep the edges that correspond to exceptions thrown by
+              this instruction.  */
            continue;
 
+         /* We do not need this edge.  */
          bb->flags |= BB_DIRTY;
          purged = true;
          remove_edge (e);