OSDN Git Service

gcc/
[pf3gnuchains/gcc-fork.git] / gcc / cfglayout.c
index b40695f..0885af7 100644 (file)
@@ -1,11 +1,12 @@
 /* Basic block reordering routines for the GNU compiler.
-   Copyright (C) 2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2008
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -14,9 +15,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -37,6 +37,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "alloc-pool.h"
 #include "flags.h"
 #include "tree-pass.h"
+#include "df.h"
 #include "vecprim.h"
 
 /* Holds the interesting trailing notes for the function.  */
@@ -52,7 +53,7 @@ static void change_scope (rtx, tree, tree);
 
 void verify_insn_chain (void);
 static void fixup_fallthru_exit_predecessor (void);
-static tree insn_scope (rtx);
+static tree insn_scope (const_rtx);
 \f
 rtx
 unlink_insn_chain (rtx first, rtx last)
@@ -98,15 +99,11 @@ skip_insns_after_block (basic_block bb)
          continue;
 
        case NOTE:
-         switch (NOTE_LINE_NUMBER (insn))
+         switch (NOTE_KIND (insn))
            {
            case NOTE_INSN_BLOCK_END:
-             last_insn = insn;
-             continue;
-           case NOTE_INSN_DELETED:
-           case NOTE_INSN_DELETED_LABEL:
+             gcc_unreachable ();
              continue;
-
            default:
              continue;
              break;
@@ -146,9 +143,11 @@ skip_insns_after_block (basic_block bb)
     {
       prev = PREV_INSN (insn);
       if (NOTE_P (insn))
-       switch (NOTE_LINE_NUMBER (insn))
+       switch (NOTE_KIND (insn))
          {
          case NOTE_INSN_BLOCK_END:
+           gcc_unreachable ();
+           break;
          case NOTE_INSN_DELETED:
          case NOTE_INSN_DELETED_LABEL:
            continue;
@@ -191,7 +190,7 @@ record_effective_endpoints (void)
   for (insn = get_insns ();
        insn
        && NOTE_P (insn)
-       && NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK;
+       && NOTE_KIND (insn) != NOTE_INSN_BASIC_BLOCK;
        insn = NEXT_INSN (insn))
     continue;
   /* No basic blocks at all?  */
@@ -239,7 +238,7 @@ int prologue_locator;
 int epilogue_locator;
 
 /* Hold current location information and last location information, so the
-   datastructures are built lazilly only when some instructions in given
+   datastructures are built lazily only when some instructions in given
    place are needed.  */
 location_t curr_location, last_location;
 static tree curr_block, last_block;
@@ -256,13 +255,8 @@ insn_locators_alloc (void)
   locations_locators_locs = VEC_alloc (int, heap, 32);
   locations_locators_vals = VEC_alloc (location_t, heap, 32);
 
-#ifdef USE_MAPPED_LOCATION
   last_location = -1;
   curr_location = -1;
-#else
-  last_location.line = -1;
-  curr_location.line = -1;
-#endif
   curr_block = NULL;
   last_block = NULL;
   curr_rtl_loc = 0;
@@ -285,15 +279,8 @@ set_curr_insn_source_location (location_t location)
      time locators are not initialized.  */
   if (curr_rtl_loc == -1)
     return;
-#ifdef USE_MAPPED_LOCATION
   if (location == last_location)
     return;
-#else
-  if (location.file && last_location.file
-      && !strcmp (location.file, last_location.file)
-      && location.line == last_location.line)
-    return;
-#endif
   curr_location = location;
 }
 
@@ -322,12 +309,7 @@ curr_insn_locator (void)
       VEC_safe_push (tree, gc, block_locators_blocks, curr_block);
       last_block = curr_block;
     }
-#ifdef USE_MAPPED_LOCATION
   if (last_location != curr_location)
-#else
-  if (last_location.file != curr_location.file
-      || last_location.line != curr_location.line)
-#endif
     {
       curr_rtl_loc++;
       VEC_safe_push (int, heap, locations_locators_locs, curr_rtl_loc);
@@ -358,8 +340,10 @@ outof_cfg_layout_mode (void)
   return 0;
 }
 
-struct tree_opt_pass pass_into_cfg_layout_mode =
+struct rtl_opt_pass pass_into_cfg_layout_mode =
 {
+ {
+  RTL_PASS,
   "into_cfglayout",                     /* name */
   NULL,                                 /* gate */
   into_cfg_layout_mode,                 /* execute */
@@ -372,11 +356,13 @@ struct tree_opt_pass pass_into_cfg_layout_mode =
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
   TODO_dump_func,                       /* todo_flags_finish */
-  0                                     /* letter */
+ }
 };
 
-struct tree_opt_pass pass_outof_cfg_layout_mode =
+struct rtl_opt_pass pass_outof_cfg_layout_mode =
 {
+ {
+  RTL_PASS,
   "outof_cfglayout",                    /* name */
   NULL,                                 /* gate */
   outof_cfg_layout_mode,                /* execute */
@@ -389,7 +375,7 @@ struct tree_opt_pass pass_outof_cfg_layout_mode =
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
   TODO_dump_func,                       /* todo_flags_finish */
-  0                                     /* letter */
+ }
 };
 \f
 /* Return sope resulting from combination of S1 and S2.  */
@@ -451,7 +437,7 @@ change_scope (rtx orig_insn, tree s1, tree s2)
 
 /* Return lexical scope block insn belong to.  */
 static tree
-insn_scope (rtx insn)
+insn_scope (const_rtx insn)
 {
   int max = VEC_length (int, block_locators_locs);
   int min = 0;
@@ -528,7 +514,7 @@ locator_line (int loc)
 
 /* Return line number of the statement that produced this insn.  */
 int
-insn_line (rtx insn)
+insn_line (const_rtx insn)
 {
   return locator_line (INSN_LOCATOR (insn));
 }
@@ -547,7 +533,7 @@ locator_file (int loc)
 
 /* Return source file of the statement that produced this insn.  */
 const char *
-insn_file (rtx insn)
+insn_file (const_rtx insn)
 {
   return locator_file (INSN_LOCATOR (insn));
 }
@@ -629,7 +615,7 @@ relink_block_chain (bool stay_in_cfglayout_mode)
       fprintf (dump_file, "Reordered sequence:\n");
       for (bb = ENTRY_BLOCK_PTR->next_bb, index = NUM_FIXED_BLOCKS;
           bb;
-          bb = bb->aux, index++)
+          bb = (basic_block) bb->aux, index++)
        {
          fprintf (dump_file, " %i ", index);
          if (get_bb_original (bb))
@@ -647,7 +633,7 @@ relink_block_chain (bool stay_in_cfglayout_mode)
   /* Now reorder the blocks.  */
   prev_bb = ENTRY_BLOCK_PTR;
   bb = ENTRY_BLOCK_PTR->next_bb;
-  for (; bb; prev_bb = bb, bb = bb->aux)
+  for (; bb; prev_bb = bb, bb = (basic_block) bb->aux)
     {
       bb->prev_bb = prev_bb;
       prev_bb->next_bb = bb;
@@ -695,7 +681,7 @@ fixup_reorder_chain (void)
   /* First do the bulk reordering -- rechain the blocks without regard to
      the needed changes to jumps and labels.  */
 
-  for (bb = ENTRY_BLOCK_PTR->next_bb; bb; bb = bb->aux)
+  for (bb = ENTRY_BLOCK_PTR->next_bb; bb; bb = (basic_block) bb->aux)
     {
       if (bb->il.rtl->header)
        {
@@ -738,7 +724,7 @@ fixup_reorder_chain (void)
   /* Now add jumps and labels as needed to match the blocks new
      outgoing edges.  */
 
-  for (bb = ENTRY_BLOCK_PTR->next_bb; bb ; bb = bb->aux)
+  for (bb = ENTRY_BLOCK_PTR->next_bb; bb ; bb = (basic_block) bb->aux)
     {
       edge e_fall, e_taken, e;
       rtx bb_end_insn;
@@ -885,7 +871,7 @@ fixup_reorder_chain (void)
       FOR_EACH_EDGE (e, ei, bb->succs)
        if (e->flags & EDGE_FALLTHRU)
          break;
-
+      
       if (e && !can_fallthru (e->src, e->dest))
        force_nonfallthru (e);
     }
@@ -953,16 +939,66 @@ fixup_fallthru_exit_predecessor (void)
        }
 
       while (c->aux != bb)
-       c = c->aux;
+       c = (basic_block) c->aux;
 
       c->aux = bb->aux;
       while (c->aux)
-       c = c->aux;
+       c = (basic_block) c->aux;
 
       c->aux = bb;
       bb->aux = NULL;
     }
 }
+
+/* In case there are more than one fallthru predecessors of exit, force that
+   there is only one.  */
+
+static void
+force_one_exit_fallthru (void)
+{
+  edge e, predecessor = NULL;
+  bool more = false;
+  edge_iterator ei;
+  basic_block forwarder, bb;
+
+  FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
+    if (e->flags & EDGE_FALLTHRU)
+      {
+       if (predecessor == NULL)
+         predecessor = e;
+       else
+         {
+           more = true;
+           break;
+         }
+      }
+
+  if (!more)
+    return;
+
+  /* Exit has several fallthru predecessors.  Create a forwarder block for
+     them.  */
+  forwarder = split_edge (predecessor);
+  for (ei = ei_start (EXIT_BLOCK_PTR->preds); (e = ei_safe_edge (ei)); )
+    {
+      if (e->src == forwarder
+         || !(e->flags & EDGE_FALLTHRU))
+       ei_next (&ei);
+      else
+       redirect_edge_and_branch_force (e, forwarder);
+    }
+
+  /* Fix up the chain of blocks -- make FORWARDER immediately precede the
+     exit block.  */
+  FOR_EACH_BB (bb)
+    {
+      if (bb->aux == NULL && bb != forwarder)
+       {
+         bb->aux = forwarder;
+         break;
+       }
+    }
+}
 \f
 /* Return true in case it is possible to duplicate the basic block BB.  */
 
@@ -970,10 +1006,10 @@ fixup_fallthru_exit_predecessor (void)
    only be used through the cfghooks interface, and we do not want to move
    it to cfgrtl.c since it would require also moving quite a lot of related
    code.  */
-extern bool cfg_layout_can_duplicate_bb_p (basic_block);
+extern bool cfg_layout_can_duplicate_bb_p (const_basic_block);
 
 bool
-cfg_layout_can_duplicate_bb_p (basic_block bb)
+cfg_layout_can_duplicate_bb_p (const_basic_block bb)
 {
   /* Do not attempt to duplicate tablejumps, as we need to unshare
      the dispatch table.  This is difficult to do, as the instructions
@@ -1033,7 +1069,7 @@ duplicate_insn_chain (rtx from, rtx to)
          break;
 
        case NOTE:
-         switch (NOTE_LINE_NUMBER (insn))
+         switch (NOTE_KIND (insn))
            {
              /* In case prologue is empty and function contain label
                 in first BB, we may want to copy the block.  */
@@ -1059,11 +1095,7 @@ duplicate_insn_chain (rtx from, rtx to)
            default:
              /* All other notes should have already been eliminated.
               */
-             gcc_assert (NOTE_LINE_NUMBER (insn) >= 0);
-
-             /* It is possible that no_line_number is set and the note
-                won't be emitted.  */
-             emit_note_copy (insn);
+             gcc_unreachable ();
            }
          break;
        default:
@@ -1114,35 +1146,34 @@ cfg_layout_duplicate_bb (basic_block bb)
        new_bb->il.rtl->footer = unlink_insn_chain (insn, get_last_insn ());
     }
 
-  if (bb->il.rtl->global_live_at_start)
-    {
-      new_bb->il.rtl->global_live_at_start = ALLOC_REG_SET (&reg_obstack);
-      new_bb->il.rtl->global_live_at_end = ALLOC_REG_SET (&reg_obstack);
-      COPY_REG_SET (new_bb->il.rtl->global_live_at_start,
-                   bb->il.rtl->global_live_at_start);
-      COPY_REG_SET (new_bb->il.rtl->global_live_at_end,
-                   bb->il.rtl->global_live_at_end);
-    }
-
   return new_bb;
 }
+
 \f
 /* Main entry point to this module - initialize the datastructures for
    CFG layout changes.  It keeps LOOPS up-to-date if not null.
 
-   FLAGS is a set of additional flags to pass to cleanup_cfg().  It should
-   include CLEANUP_UPDATE_LIFE if liveness information must be kept up
-   to date.  */
+   FLAGS is a set of additional flags to pass to cleanup_cfg().  */
 
 void
 cfg_layout_initialize (unsigned int flags)
 {
+  rtx x;
+  basic_block bb;
+
   initialize_original_copy_tables ();
 
   cfg_layout_rtl_register_cfg_hooks ();
 
   record_effective_endpoints ();
 
+  /* Make sure that the targets of non local gotos are marked.  */
+  for (x = nonlocal_goto_handler_labels; x; x = XEXP (x, 1))
+    {
+      bb = BLOCK_FOR_INSN (XEXP (x, 0));
+      bb->flags |= BB_NON_LOCAL_GOTO_TARGET;
+    }
+
   cleanup_cfg (CLEANUP_CFGLAYOUT | flags);
 }
 
@@ -1183,6 +1214,7 @@ cfg_layout_finalize (void)
 #ifdef ENABLE_CHECKING
   verify_flow_info ();
 #endif
+  force_one_exit_fallthru ();
   rtl_register_cfg_hooks ();
   if (reload_completed
 #ifdef HAVE_epilogue