OSDN Git Service

2009-05-13 Jonathan Wakely <jwakely.gcc@gmail.com>
[pf3gnuchains/gcc-fork.git] / gcc / cfgrtl.c
index c157e08..a2c0e0f 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, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -53,6 +53,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "toplev.h"
 #include "tm_p.h"
 #include "obstack.h"
+#include "insn-attr.h"
 #include "insn-config.h"
 #include "cfglayout.h"
 #include "expr.h"
@@ -64,7 +65,6 @@ along with GCC; see the file COPYING3.  If not see
 
 static int can_delete_note_p (const_rtx);
 static int can_delete_label_p (const_rtx);
-static void commit_one_edge_insertion (edge);
 static basic_block rtl_split_edge (edge);
 static bool rtl_move_block_after (basic_block, basic_block);
 static int rtl_verify_flow_info (void);
@@ -76,7 +76,7 @@ static void rtl_delete_block (basic_block);
 static basic_block rtl_redirect_edge_and_branch_force (edge, basic_block);
 static edge rtl_redirect_edge_and_branch (edge, basic_block);
 static basic_block rtl_split_block (basic_block, void *);
-static void rtl_dump_bb (basic_block, FILE *, int);
+static void rtl_dump_bb (basic_block, FILE *, int, int);
 static int rtl_verify_flow_info_1 (void);
 static void rtl_make_forwarder_block (edge);
 \f
@@ -232,22 +232,6 @@ delete_insn_chain (rtx start, rtx finish, bool clear_bb)
       start = next;
     }
 }
-
-/* Like delete_insn_chain but also purge dead edges from BB.  */
-
-void
-delete_insn_chain_and_edges (rtx first, rtx last)
-{
-  bool purge = false;
-
-  if (INSN_P (last)
-      && BLOCK_FOR_INSN (last)
-      && BB_END (BLOCK_FOR_INSN (last)) == last)
-    purge = true;
-  delete_insn_chain (first, last, false);
-  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
@@ -379,8 +363,6 @@ rtl_delete_block (basic_block b)
      label for an exception handler which can't be reached.  We need
      to remove the label from the exception_handler_label list.  */
   insn = BB_HEAD (b);
-  if (LABEL_P (insn))
-    maybe_remove_eh_handler (insn);
 
   end = get_last_bb_insn (b);
 
@@ -427,21 +409,37 @@ free_bb_for_insn (void)
   return 0;
 }
 
-struct tree_opt_pass pass_free_cfg =
+static unsigned int
+rest_of_pass_free_cfg (void)
 {
+#ifdef DELAY_SLOTS
+  /* The resource.c machinery uses DF but the CFG isn't guaranteed to be
+     valid at that point so it would be too late to call df_analyze.  */
+  if (optimize > 0 && flag_delayed_branch)
+    df_analyze ();
+#endif
+
+  free_bb_for_insn ();
+  return 0;
+}
+
+struct rtl_opt_pass pass_free_cfg =
+{
+ {
+  RTL_PASS,
   NULL,                                 /* name */
   NULL,                                 /* gate */
-  free_bb_for_insn,                     /* execute */
+  rest_of_pass_free_cfg,                /* execute */
   NULL,                                 /* sub */
   NULL,                                 /* next */
   0,                                    /* static_pass_number */
-  0,                                    /* tv_id */
+  TV_NONE,                              /* tv_id */
   0,                                    /* properties_required */
   0,                                    /* properties_provided */
   PROP_cfg,                             /* properties_destroyed */
   0,                                    /* todo_flags_start */
   0,                                    /* todo_flags_finish */
-  0                                     /* letter */
+ }
 };
 
 /* Return RTX to emit after when we want to emit code on the entry of function.  */
@@ -570,10 +568,6 @@ rtl_merge_blocks (basic_block a, basic_block b)
   /* If there was a CODE_LABEL beginning B, delete it.  */
   if (LABEL_P (b_head))
     {
-      /* This might have been an EH label that no longer has incoming
-        EH edges.  Update data structures to match.  */
-      maybe_remove_eh_handler (b_head);
-
       /* Detect basic blocks with nothing but a label.  This can happen
         in particular at the end of a function.  */
       if (b_head == b_end)
@@ -876,31 +870,25 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
   return e;
 }
 
-/* Redirect edge representing branch of (un)conditional jump or tablejump,
-   NULL on failure  */
-static edge
-redirect_branch_edge (edge e, basic_block target)
+/* Subroutine of redirect_branch_edge that tries to patch the jump
+   instruction INSN so that it reaches block NEW.  Do this
+   only when it originally reached block OLD.  Return true if this
+   worked or the original target wasn't OLD, return false if redirection
+   doesn't work.  */
+
+static bool
+patch_jump_insn (rtx insn, rtx old_label, basic_block new_bb)
 {
   rtx tmp;
-  rtx old_label = BB_HEAD (e->dest);
-  basic_block src = e->src;
-  rtx insn = BB_END (src);
-
-  /* We can only redirect non-fallthru edges of jump insn.  */
-  if (e->flags & EDGE_FALLTHRU)
-    return NULL;
-  else if (!JUMP_P (insn))
-    return NULL;
-
   /* Recognize a tablejump and adjust all matching cases.  */
   if (tablejump_p (insn, NULL, &tmp))
     {
       rtvec vec;
       int j;
-      rtx new_label = block_label (target);
+      rtx new_label = block_label (new_bb);
 
-      if (target == EXIT_BLOCK_PTR)
-       return NULL;
+      if (new_bb == EXIT_BLOCK_PTR)
+       return false;
       if (GET_CODE (PATTERN (tmp)) == ADDR_VEC)
        vec = XVEC (PATTERN (tmp), 0);
       else
@@ -935,20 +923,55 @@ redirect_branch_edge (edge e, basic_block target)
       if (computed_jump_p (insn)
          /* A return instruction can't be redirected.  */
          || returnjump_p (insn))
-       return NULL;
-
-      /* If the insn doesn't go where we think, we're confused.  */
-      gcc_assert (JUMP_LABEL (insn) == old_label);
+       return false;
 
-      /* If the substitution doesn't succeed, die.  This can happen
-        if the back end emitted unrecognizable instructions or if
-        target is exit block on some arches.  */
-      if (!redirect_jump (insn, block_label (target), 0))
+      if (!currently_expanding_to_rtl || JUMP_LABEL (insn) == old_label)
        {
-         gcc_assert (target == EXIT_BLOCK_PTR);
-         return NULL;
+         /* If the insn doesn't go where we think, we're confused.  */
+         gcc_assert (JUMP_LABEL (insn) == old_label);
+
+         /* If the substitution doesn't succeed, die.  This can happen
+            if the back end emitted unrecognizable instructions or if
+            target is exit block on some arches.  */
+         if (!redirect_jump (insn, block_label (new_bb), 0))
+           {
+             gcc_assert (new_bb == EXIT_BLOCK_PTR);
+             return false;
+           }
        }
     }
+  return true;
+}
+
+
+/* Redirect edge representing branch of (un)conditional jump or tablejump,
+   NULL on failure  */
+static edge
+redirect_branch_edge (edge e, basic_block target)
+{
+  rtx old_label = BB_HEAD (e->dest);
+  basic_block src = e->src;
+  rtx insn = BB_END (src);
+
+  /* We can only redirect non-fallthru edges of jump insn.  */
+  if (e->flags & EDGE_FALLTHRU)
+    return NULL;
+  else if (!JUMP_P (insn) && !currently_expanding_to_rtl)
+    return NULL;
+
+  if (!currently_expanding_to_rtl)
+    {
+      if (!patch_jump_insn (insn, old_label, target))
+       return NULL;
+    }
+  else
+    /* When expanding this BB might actually contain multiple
+       jumps (i.e. not yet split by find_many_sub_basic_blocks).
+       Redirect all of those that match our label.  */
+    for (insn = BB_HEAD (src); insn != NEXT_INSN (BB_END (src));
+        insn = NEXT_INSN (insn))
+      if (JUMP_P (insn) && !patch_jump_insn (insn, old_label, target))
+       return NULL;
 
   if (dump_file)
     fprintf (dump_file, "Edge %i->%i redirected to %i\n",
@@ -1007,6 +1030,7 @@ force_nonfallthru_and_redirect (edge e, basic_block target)
   rtx note;
   edge new_edge;
   int abnormal_edge_flags = 0;
+  int loc;
 
   /* In the case the last instruction is conditional jump to the next
      instruction, first redirect the jump itself and then continue
@@ -1109,11 +1133,7 @@ force_nonfallthru_and_redirect (edge e, basic_block target)
          && JUMP_P (BB_END (jump_block))
          && !any_condjump_p (BB_END (jump_block))
          && (EDGE_SUCC (jump_block, 0)->flags & EDGE_CROSSING))
-       REG_NOTES (BB_END (jump_block)) = gen_rtx_EXPR_LIST (REG_CROSSING_JUMP,
-                                                            NULL_RTX,
-                                                            REG_NOTES
-                                                            (BB_END
-                                                             (jump_block)));
+       add_reg_note (BB_END (jump_block), REG_CROSSING_JUMP, NULL_RTX);
 
       /* Wire edge in.  */
       new_edge = make_edge (e->src, jump_block, EDGE_FALLTHRU);
@@ -1129,11 +1149,15 @@ force_nonfallthru_and_redirect (edge e, basic_block target)
   else
     jump_block = e->src;
 
+  if (e->goto_locus && e->goto_block == NULL)
+    loc = e->goto_locus;
+  else
+    loc = 0;
   e->flags &= ~EDGE_FALLTHRU;
   if (target == EXIT_BLOCK_PTR)
     {
 #ifdef HAVE_return
-       emit_jump_insn_after_noloc (gen_return (), BB_END (jump_block));
+       emit_jump_insn_after_setloc (gen_return (), BB_END (jump_block), loc);
 #else
        gcc_unreachable ();
 #endif
@@ -1141,7 +1165,7 @@ force_nonfallthru_and_redirect (edge e, basic_block target)
   else
     {
       rtx label = block_label (target);
-      emit_jump_insn_after_noloc (gen_jump (label), BB_END (jump_block));
+      emit_jump_insn_after_setloc (gen_jump (label), BB_END (jump_block), loc);
       JUMP_LABEL (BB_END (jump_block)) = label;
       LABEL_NUSES (label)++;
     }
@@ -1332,7 +1356,7 @@ insert_insn_on_edge (rtx pattern, edge e)
 
 /* Update the CFG for the instructions queued on edge E.  */
 
-static void
+void
 commit_one_edge_insertion (edge e)
 {
   rtx before = NULL_RTX, after = NULL_RTX, insns, tmp, last;
@@ -1416,8 +1440,7 @@ commit_one_edge_insertion (edge e)
              if (JUMP_P (BB_END (bb))
                  && !any_condjump_p (BB_END (bb))
                  && (single_succ_edge (bb)->flags & EDGE_CROSSING))
-               REG_NOTES (BB_END (bb)) = gen_rtx_EXPR_LIST
-                 (REG_CROSSING_JUMP, NULL_RTX, REG_NOTES (BB_END (bb)));
+               add_reg_note (BB_END (bb), REG_CROSSING_JUMP, NULL_RTX);
            }
        }
     }
@@ -1513,7 +1536,7 @@ commit_edge_insertions (void)
    at start and end).  */
 
 static void
-rtl_dump_bb (basic_block bb, FILE *outf, int indent)
+rtl_dump_bb (basic_block bb, FILE *outf, int indent, int flags ATTRIBUTE_UNUSED)
 {
   rtx insn;
   rtx last;
@@ -1649,10 +1672,10 @@ print_rtl_with_bb (FILE *outf, const_rtx rtx_first)
       free (in_bb_p);
     }
 
-  if (current_function_epilogue_delay_list != 0)
+  if (crtl->epilogue_delay_list != 0)
     {
       fprintf (outf, "\n;; Insns in epilogue delay list:\n\n");
-      for (tmp_rtx = current_function_epilogue_delay_list; tmp_rtx != 0;
+      for (tmp_rtx = crtl->epilogue_delay_list; tmp_rtx != 0;
           tmp_rtx = XEXP (tmp_rtx, 1))
        print_rtl_single (outf, XEXP (tmp_rtx, 0));
     }
@@ -2596,10 +2619,6 @@ cfg_layout_merge_blocks (basic_block a, basic_block b)
   /* If there was a CODE_LABEL beginning B, delete it.  */
   if (LABEL_P (BB_HEAD (b)))
     {
-      /* This might have been an EH label that no longer has incoming
-        EH edges.  Update data structures to match.  */
-      maybe_remove_eh_handler (BB_HEAD (b));
-
       delete_insn (BB_HEAD (b));
     }
 
@@ -2609,6 +2628,34 @@ cfg_layout_merge_blocks (basic_block a, basic_block b)
     try_redirect_by_replacing_jump (EDGE_SUCC (a, 0), b, true);
   gcc_assert (!JUMP_P (BB_END (a)));
 
+  /* When not optimizing and the edge is the only place in RTL which holds
+     some unique locus, emit a nop with that locus in between.  */
+  if (!optimize && EDGE_SUCC (a, 0)->goto_locus)
+    {
+      rtx insn = BB_END (a), end = PREV_INSN (BB_HEAD (a));
+      int goto_locus = EDGE_SUCC (a, 0)->goto_locus;
+
+      while (insn != end && (!INSN_P (insn) || INSN_LOCATOR (insn) == 0))
+       insn = PREV_INSN (insn);
+      if (insn != end && locator_eq (INSN_LOCATOR (insn), goto_locus))
+       goto_locus = 0;
+      else
+       {
+         insn = BB_HEAD (b);
+         end = NEXT_INSN (BB_END (b));
+         while (insn != end && !INSN_P (insn))
+           insn = NEXT_INSN (insn);
+         if (insn != end && INSN_LOCATOR (insn) != 0
+             && locator_eq (INSN_LOCATOR (insn), goto_locus))
+           goto_locus = 0;
+       }
+      if (goto_locus)
+       {
+         BB_END (a) = emit_insn_after_noloc (gen_nop (), BB_END (a), a);
+         INSN_LOCATOR (BB_END (a)) = goto_locus;
+       }
+    }
+
   /* Possible line number notes should appear in between.  */
   if (b->il.rtl->header)
     {
@@ -2743,7 +2790,7 @@ need_fake_edge_p (const_rtx insn)
   if ((CALL_P (insn)
        && !SIBLING_CALL_P (insn)
        && !find_reg_note (insn, REG_NORETURN, NULL)
-       && !CONST_OR_PURE_CALL_P (insn)))
+       && !(RTL_CONST_OR_PURE_CALL_P (insn))))
     return true;
 
   return ((GET_CODE (PATTERN (insn)) == ASM_OPERANDS
@@ -2807,7 +2854,7 @@ rtl_flow_call_edges_add (sbitmap blocks)
          e = find_edge (bb, EXIT_BLOCK_PTR);
          if (e)
            {
-             insert_insn_on_edge (gen_rtx_USE (VOIDmode, const0_rtx), e);
+             insert_insn_on_edge (gen_use (const0_rtx), e);
              commit_edge_insertions ();
            }
        }