OSDN Git Service

* configure.in: Add *-*-freebsd* configurations.
[pf3gnuchains/gcc-fork.git] / gcc / cfgrtl.c
index 1b00a61..a56eea2 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
@@ -74,7 +75,7 @@ rtx tail_recursion_label_list;
 
 static int can_delete_note_p           PARAMS ((rtx));
 static int can_delete_label_p          PARAMS ((rtx));
-static void commit_one_edge_insertion  PARAMS ((edge));
+static void commit_one_edge_insertion  PARAMS ((edge, int));
 static bool try_redirect_by_replacing_jump PARAMS ((edge, basic_block));
 static rtx last_loop_beg_note          PARAMS ((rtx));
 static bool back_edge_of_syntactic_loop_p PARAMS ((basic_block, basic_block));
@@ -101,8 +102,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.  */
@@ -178,6 +178,26 @@ delete_insn (insn)
   return next;
 }
 
+/* Like delete_insn but also purge dead edges from BB.  */
+rtx
+delete_insn_and_edges (insn)
+     rtx insn;
+{
+  rtx x;
+  bool purge = false;
+
+  if (basic_block_for_insn
+      && INSN_P (insn)
+      && (unsigned int)INSN_UID (insn) < basic_block_for_insn->num_elements
+      && BLOCK_FOR_INSN (insn)
+      && BLOCK_FOR_INSN (insn)->end == insn)
+    purge = true;
+  x = delete_insn (insn);
+  if (purge)
+    purge_dead_edges (BLOCK_FOR_INSN (insn));
+  return x;
+}
+
 /* Unlink a chain of insns between START and FINISH, leaving notes
    that must be paired.  */
 
@@ -203,6 +223,24 @@ delete_insn_chain (start, finish)
       start = next;
     }
 }
+
+/* Like delete_insn but also purge dead edges from BB.  */
+void
+delete_insn_chain_and_edges (first, last)
+     rtx first, last;
+{
+  bool purge = false;
+
+  if (basic_block_for_insn
+      && INSN_P (last)
+      && (unsigned int)INSN_UID (last) < basic_block_for_insn->num_elements
+      && BLOCK_FOR_INSN (last)
+      && BLOCK_FOR_INSN (last)->end == last)
+    purge = true;
+  delete_insn_chain (first, last);
+  if (purge)
+    purge_dead_edges (BLOCK_FOR_INSN (last));
+}
 \f
 /* Create a new basic block consisting of the instructions between HEAD and END
    inclusive.  This function is designed to allow fast BB construction - reuses
@@ -324,7 +362,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;
@@ -373,6 +411,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);
 
@@ -508,6 +555,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;
@@ -613,9 +669,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;
@@ -1271,8 +1327,9 @@ insert_insn_on_edge (pattern, e)
 /* Update the CFG for the instructions queued on edge E.  */
 
 static void
-commit_one_edge_insertion (e)
+commit_one_edge_insertion (e, watch_calls)
      edge e;
+     int watch_calls;
 {
   rtx before = NULL_RTX, after = NULL_RTX, insns, tmp, last;
   basic_block bb;
@@ -1281,63 +1338,84 @@ commit_one_edge_insertion (e)
   insns = e->insns;
   e->insns = NULL_RTX;
 
-  /* Figure out where to put these things.  If the destination has
-     one predecessor, insert there.  Except for the exit block.  */
-  if (e->dest->pred->pred_next == NULL
-      && e->dest != EXIT_BLOCK_PTR)
+  /* Special case -- avoid inserting code between call and storing
+     its return value.  */
+  if (watch_calls && (e->flags & EDGE_FALLTHRU) && !e->dest->pred->pred_next
+      && e->src != ENTRY_BLOCK_PTR
+      && GET_CODE (e->src->end) == CALL_INSN)
     {
+      rtx next = next_nonnote_insn (e->src->end);
+
+      after = e->dest->head;
+      /* The first insn after the call may be a stack pop, skip it.  */
+      while (next
+            && keep_with_call_p (next))
+        {
+          after = next;
+         next = next_nonnote_insn (next);
+       }
       bb = e->dest;
-
-      /* Get the location correct wrt a code label, and "nice" wrt
-        a basic block note, and before everything else.  */
-      tmp = bb->head;
-      if (GET_CODE (tmp) == CODE_LABEL)
-       tmp = NEXT_INSN (tmp);
-      if (NOTE_INSN_BASIC_BLOCK_P (tmp))
-       tmp = NEXT_INSN (tmp);
-      if (tmp == bb->head)
-       before = tmp;
-      else
-       after = PREV_INSN (tmp);
     }
-
-  /* If the source has one successor and the edge is not abnormal,
-     insert there.  Except for the entry block.  */
-  else if ((e->flags & EDGE_ABNORMAL) == 0
-          && e->src->succ->succ_next == NULL
-          && e->src != ENTRY_BLOCK_PTR)
+  if (!before && !after)
     {
-      bb = e->src;
-
-      /* It is possible to have a non-simple jump here.  Consider a target
-        where some forms of unconditional jumps clobber a register.  This
-        happens on the fr30 for example.
-
-        We know this block has a single successor, so we can just emit
-        the queued insns before the jump.  */
-      if (GET_CODE (bb->end) == JUMP_INSN)
-       for (before = bb->end;
-            GET_CODE (PREV_INSN (before)) == NOTE
-            && NOTE_LINE_NUMBER (PREV_INSN (before)) == NOTE_INSN_LOOP_BEG;
-            before = PREV_INSN (before))
-         ;
-      else
+      /* Figure out where to put these things.  If the destination has
+         one predecessor, insert there.  Except for the exit block.  */
+      if (e->dest->pred->pred_next == NULL && e->dest != EXIT_BLOCK_PTR)
        {
-         /* We'd better be fallthru, or we've lost track of what's what.  */
-         if ((e->flags & EDGE_FALLTHRU) == 0)
-           abort ();
+         bb = e->dest;
+
+         /* Get the location correct wrt a code label, and "nice" wrt
+            a basic block note, and before everything else.  */
+         tmp = bb->head;
+         if (GET_CODE (tmp) == CODE_LABEL)
+           tmp = NEXT_INSN (tmp);
+         if (NOTE_INSN_BASIC_BLOCK_P (tmp))
+           tmp = NEXT_INSN (tmp);
+         if (tmp == bb->head)
+           before = tmp;
+         else if (tmp)
+           after = PREV_INSN (tmp);
+         else
+           after = get_last_insn ();
+       }
 
+      /* If the source has one successor and the edge is not abnormal,
+         insert there.  Except for the entry block.  */
+      else if ((e->flags & EDGE_ABNORMAL) == 0
+              && e->src->succ->succ_next == NULL
+              && e->src != ENTRY_BLOCK_PTR)
+       {
+         bb = e->src;
+
+         /* It is possible to have a non-simple jump here.  Consider a target
+            where some forms of unconditional jumps clobber a register.  This
+            happens on the fr30 for example.
+
+            We know this block has a single successor, so we can just emit
+            the queued insns before the jump.  */
+         if (GET_CODE (bb->end) == JUMP_INSN)
+           for (before = bb->end;
+                GET_CODE (PREV_INSN (before)) == NOTE
+                && NOTE_LINE_NUMBER (PREV_INSN (before)) ==
+                NOTE_INSN_LOOP_BEG; before = PREV_INSN (before))
+             ;
+         else
+           {
+             /* We'd better be fallthru, or we've lost track of what's what.  */
+             if ((e->flags & EDGE_FALLTHRU) == 0)
+               abort ();
+
+             after = bb->end;
+           }
+       }
+      /* Otherwise we must split the edge.  */
+      else
+       {
+         bb = split_edge (e);
          after = bb->end;
        }
     }
 
-  /* Otherwise we must split the edge.  */
-  else
-    {
-      bb = split_edge (e);
-      after = bb->end;
-    }
-
   /* Now that we've found the spot, do the insertion.  */
 
   if (before)
@@ -1352,13 +1430,12 @@ commit_one_edge_insertion (e)
     {
       /* ??? Remove all outgoing edges from BB and add one for EXIT.
          This is not currently a problem because this only happens
-        for the (single) epilogue, which already has a fallthru edge
-        to EXIT.  */
+         for the (single) epilogue, which already has a fallthru edge
+         to EXIT.  */
 
       e = bb->succ;
       if (e->dest != EXIT_BLOCK_PTR
-         || e->succ_next != NULL
-         || (e->flags & EDGE_FALLTHRU) == 0)
+         || e->succ_next != NULL || (e->flags & EDGE_FALLTHRU) == 0)
        abort ();
 
       e->flags &= ~EDGE_FALLTHRU;
@@ -1395,7 +1472,39 @@ commit_edge_insertions ()
        {
          next = e->succ_next;
          if (e->insns)
-           commit_one_edge_insertion (e);
+           commit_one_edge_insertion (e, false);
+       }
+
+      if (++i >= n_basic_blocks)
+       break;
+      bb = BASIC_BLOCK (i);
+    }
+}
+\f
+/* Update the CFG for all queued instructions, taking special care of inserting
+   code on edges between call and storing its return value.  */
+
+void
+commit_edge_insertions_watch_calls ()
+{
+  int i;
+  basic_block bb;
+
+#ifdef ENABLE_CHECKING
+  verify_flow_info ();
+#endif
+
+  i = -1;
+  bb = ENTRY_BLOCK_PTR;
+  while (1)
+    {
+      edge e, next;
+
+      for (e = bb->succ; e; e = next)
+       {
+         next = e->succ_next;
+         if (e->insns)
+           commit_one_edge_insertion (e, true);
        }
 
       if (++i >= n_basic_blocks)
@@ -1649,9 +1758,33 @@ verify_flow_info ()
   for (i = n_basic_blocks - 1; i >= 0; i--)
     {
       basic_block bb = BASIC_BLOCK (i);
-      int has_fallthru = 0;
+      int n_fallthru = 0, n_eh = 0, n_call = 0, n_abnormal = 0, n_branch = 0;
       edge e;
+      rtx note;
 
+      if (INSN_P (bb->end)
+         && (note = find_reg_note (bb->end, REG_BR_PROB, NULL_RTX))
+         && any_condjump_p (bb->end))
+       {
+         if (INTVAL (XEXP (note, 0)) != BRANCH_EDGE (bb)->probability)
+           {
+             error ("verify_flow_info: REG_BR_PROB does not match cfg %i %i",
+                    INTVAL (XEXP (note, 0)), BRANCH_EDGE (bb)->probability);
+             err = 1;
+           }
+       }
+      if (bb->count < 0)
+        {
+          error ("verify_flow_info: Wrong count of block %i %i",
+                bb->index, (int)bb->count);
+          err = 1;
+        }
+      if (bb->frequency < 0)
+        {
+          error ("verify_flow_info: Wrong frequency of block %i %i",
+                bb->index, bb->frequency);
+          err = 1;
+        }
       for (e = bb->succ; e; e = e->succ_next)
        {
          if (last_visited [e->dest->index + 2] == bb)
@@ -1660,11 +1793,34 @@ verify_flow_info ()
                     e->src->index, e->dest->index);
              err = 1;
            }
+         if (e->probability < 0 || e->probability > REG_BR_PROB_BASE)
+           {
+             error ("verify_flow_info: Wrong probability of edge %i->%i %i",
+                    e->src->index, e->dest->index, e->probability);
+             err = 1;
+           }
+         if (e->count < 0)
+           {
+             error ("verify_flow_info: Wrong count of edge %i->%i %i",
+                    e->src->index, e->dest->index, (int)e->count);
+             err = 1;
+           }
 
          last_visited [e->dest->index + 2] = bb;
 
          if (e->flags & EDGE_FALLTHRU)
-           has_fallthru = 1;
+           n_fallthru++;
+
+         if ((e->flags & ~EDGE_DFS_BACK) == 0)
+           n_branch++;
+
+         if (e->flags & EDGE_ABNORMAL_CALL)
+           n_call++;
+
+         if (e->flags & EDGE_EH)
+           n_eh++;
+         else if (e->flags & EDGE_ABNORMAL)
+           n_abnormal++;
 
          if ((e->flags & EDGE_FALLTHRU)
              && e->src != ENTRY_BLOCK_PTR
@@ -1712,7 +1868,52 @@ verify_flow_info ()
          edge_checksum[e->dest->index + 2] += (size_t) e;
        }
 
-      if (!has_fallthru)
+      if (n_eh && GET_CODE (PATTERN (bb->end)) != RESX
+         && !find_reg_note (bb->end, REG_EH_REGION, NULL_RTX))
+       {
+         error ("Missing REG_EH_REGION note in the end of bb %i", bb->index);
+         err = 1;
+       }
+      if (n_branch
+         && (GET_CODE (bb->end) != JUMP_INSN
+             || (n_branch > 1 && (any_uncondjump_p (bb->end)
+                                  || any_condjump_p (bb->end)))))
+       {
+         error ("Too many outgoing branch edges from bb %i", bb->index);
+         err = 1;
+       }
+      if (n_fallthru && any_uncondjump_p (bb->end))
+       {
+         error ("Fallthru edge after unconditional jump %i", bb->index);
+         err = 1;
+       }
+      if (n_branch != 1 && any_uncondjump_p (bb->end))
+       {
+         error ("Wrong amount of branch edges after unconditional jump %i", bb->index);
+         err = 1;
+       }
+      if (n_branch != 1 && any_condjump_p (bb->end)
+         && JUMP_LABEL (bb->end) != BASIC_BLOCK (bb->index + 1)->head)
+       {
+         error ("Wrong amount of branch edges after conditional jump %i", bb->index);
+         err = 1;
+       }
+      if (n_call && GET_CODE (bb->end) != CALL_INSN)
+       {
+         error ("Call edges for non-call insn in bb %i", bb->index);
+         err = 1;
+       }
+      if (n_abnormal
+         && (GET_CODE (bb->end) != CALL_INSN && n_call != n_abnormal)
+         && (GET_CODE (bb->end) != JUMP_INSN
+             || any_condjump_p (bb->end)
+             || any_uncondjump_p (bb->end)))
+       {
+         error ("Abnormal edges for no purpose in bb %i", bb->index);
+         err = 1;
+       }
+       
+      if (!n_fallthru)
        {
          rtx insn;
 
@@ -1899,9 +2100,31 @@ purge_dead_edges (bb)
   rtx insn = bb->end, note;
   bool purged = false;
 
-  /* ??? This makes no sense since the later test includes more cases.  */
-  if (GET_CODE (insn) == JUMP_INSN && !simplejump_p (insn))
-    return false;
+  /* If this instruction cannot trap, remove REG_EH_REGION notes.  */
+  if (GET_CODE (insn) == INSN
+      && (note = find_reg_note (insn, REG_EH_REGION, NULL)))
+    {
+      rtx eqnote;
+
+      if (! may_trap_p (PATTERN (insn))
+         || ((eqnote = find_reg_equal_equiv_note (insn))
+             && ! may_trap_p (XEXP (eqnote, 0))))
+       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;
+         }
+      }
 
   if (GET_CODE (insn) == JUMP_INSN)
     {
@@ -1912,7 +2135,18 @@ purge_dead_edges (bb)
       if (!any_condjump_p (insn)
          && !returnjump_p (insn)
          && !simplejump_p (insn))
-       return false;
+       return purged;
+
+      /* Branch probability/prediction notes are defined only for
+        condjumps.  We've possibly turned condjump into simplejump.  */
+      if (simplejump_p (insn))
+       {
+         note = find_reg_note (insn, REG_BR_PROB, NULL);
+         if (note)
+           remove_note (insn, note);
+         while ((note = find_reg_note (insn, REG_BR_PRED, NULL)))
+           remove_note (insn, note);
+       }
 
       for (e = bb->succ; e; e = next)
        {
@@ -1934,12 +2168,13 @@ purge_dead_edges (bb)
                   && returnjump_p (insn))
            continue;
 
+         bb->flags |= BB_DIRTY;
          purged = true;
          remove_edge (e);
        }
 
       if (!bb->succ || !purged)
-       return false;
+       return purged;
 
       if (rtl_dump_file)
        fprintf (rtl_dump_file, "Purged edges from bb %i\n", bb->index);
@@ -1970,31 +2205,6 @@ purge_dead_edges (bb)
       return purged;
     }
 
-  /* If this instruction cannot trap, remove REG_EH_REGION notes.  */
-  if (GET_CODE (insn) == INSN
-      && (note = find_reg_note (insn, REG_EH_REGION, NULL)))
-    {
-      rtx eqnote;
-
-      if (! may_trap_p (PATTERN (insn))
-         || ((eqnote = find_reg_equal_equiv_note (insn))
-             && ! may_trap_p (XEXP (eqnote, 0))))
-       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);
-           purged = true;
-         }
-      }
-
   /* If we don't see a jump insn, we don't know exactly why the block would
      have been broken at this point.  Look for a simple, non-fallthru edge,
      as these are only created by conditional branches.  If we find such an
@@ -2011,7 +2221,11 @@ purge_dead_edges (bb)
     {
       next = e->succ_next;
       if (!(e->flags & EDGE_FALLTHRU))
-       remove_edge (e), purged = true;
+       {
+         bb->flags |= BB_DIRTY;
+         remove_edge (e);
+         purged = true;
+       }
     }
 
   if (!bb->succ || bb->succ->succ_next)