OSDN Git Service

* check.c (same_type_check): Typo fix in comment.
[pf3gnuchains/gcc-fork.git] / gcc / loop-init.c
index 44b9d61..d2c6340 100644 (file)
@@ -1,5 +1,5 @@
-/* Loop optimizer initialization routines.
-   Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+/* Loop optimizer initialization routines and RTL loop optimization passes.
+   Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -15,8 +15,8 @@ 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, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 #include "config.h"
 #include "system.h"
@@ -24,34 +24,50 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "tm.h"
 #include "rtl.h"
 #include "hard-reg-set.h"
+#include "obstack.h"
 #include "basic-block.h"
 #include "cfgloop.h"
 #include "cfglayout.h"
-#include "gcov-io.h"
-#include "profile.h"
+#include "tree-pass.h"
+#include "timevar.h"
+#include "flags.h"
 
-/* Initialize loop optimizer.  */
+\f
+/* Initialize loop optimizer.  This is used by the tree and RTL loop
+   optimizers.  FLAGS specify what properties to compute and/or ensure for
+   loops.  */
 
 struct loops *
-loop_optimizer_init (dumpfile)
-     FILE *dumpfile;
+loop_optimizer_init (unsigned flags)
 {
-  struct loops *loops = xcalloc (1, sizeof (struct loops));
+  struct loops *loops = XCNEW (struct loops);
   edge e;
+  edge_iterator ei;
+  static bool first_time = true;
+
+  if (first_time)
+    {
+      first_time = false;
+      init_set_costs ();
+    }
 
   /* Avoid annoying special cases of edges going to exit
      block.  */
-  for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
-    if ((e->flags & EDGE_FALLTHRU) && e->src->succ->succ_next)
+
+  for (ei = ei_start (EXIT_BLOCK_PTR->preds); (e = ei_safe_edge (ei)); )
+    if ((e->flags & EDGE_FALLTHRU) && !single_succ_p (e->src))
       split_edge (e);
+    else
+      ei_next (&ei);
 
   /* Find the loops.  */
 
-  if (flow_loops_find (loops, LOOP_TREE) <= 1)
+  if (flow_loops_find (loops) <= 1)
     {
       /* No loops.  */
       flow_loops_free (loops);
       free (loops);
+
       return NULL;
     }
 
@@ -61,23 +77,26 @@ loop_optimizer_init (dumpfile)
   free (loops->cfg.dfs_order);
   loops->cfg.dfs_order = NULL;
 
-  /* Initialize structures for layout changes.  */
-  cfg_layout_initialize (loops);
-
   /* Create pre-headers.  */
-  create_preheaders (loops, CP_SIMPLE_PREHEADERS | CP_INSIDE_CFGLAYOUT);
+  if (flags & LOOPS_HAVE_PREHEADERS)
+    create_preheaders (loops, CP_SIMPLE_PREHEADERS);
 
   /* Force all latches to have only single successor.  */
-  force_single_succ_latches (loops);
+  if (flags & LOOPS_HAVE_SIMPLE_LATCHES)
+    force_single_succ_latches (loops);
 
   /* Mark irreducible loops.  */
-  mark_irreducible_loops (loops);
+  if (flags & LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS)
+    mark_irreducible_loops (loops);
+
+  if (flags & LOOPS_HAVE_MARKED_SINGLE_EXITS)
+    mark_single_exit_loops (loops);
 
   /* Dump loops.  */
-  flow_loops_dump (loops, dumpfile, NULL, 1);
+  flow_loops_dump (loops, dump_file, NULL, 1);
 
 #ifdef ENABLE_CHECKING
-  verify_dominators (loops->cfg.dom);
+  verify_dominators (CDI_DOMINATORS);
   verify_loop_structure (loops);
 #endif
 
@@ -86,27 +105,20 @@ loop_optimizer_init (dumpfile)
 
 /* Finalize loop optimizer.  */
 void
-loop_optimizer_finalize (loops, dumpfile)
-     struct loops *loops;
-     FILE *dumpfile;
+loop_optimizer_finalize (struct loops *loops)
 {
-  basic_block bb;
+  unsigned i;
 
-  /* Finalize layout changes.  */
-  /* Make chain.  */
-  FOR_EACH_BB (bb)
-    if (bb->next_bb != EXIT_BLOCK_PTR)
-      RBI (bb)->next = bb->next_bb;
+  if (!loops)
+    return;
 
-  /* Another dump.  */
-  flow_loops_dump (loops, dumpfile, NULL, 1);
+  for (i = 1; i < loops->num; i++)
+    if (loops->parray[i])
+      free_simple_loop_desc (loops->parray[i]);
 
   /* Clean up.  */
   flow_loops_free (loops);
   free (loops);
-  /* Finalize changes.  */
-  cfg_layout_finalize ();
 
   /* Checking.  */
 #ifdef ENABLE_CHECKING
@@ -114,3 +126,265 @@ loop_optimizer_finalize (loops, dumpfile)
 #endif
 }
 
+\f
+/* Gate for the RTL loop superpass.  The actual passes are subpasses.
+   See passes.c for more on that.  */
+
+static bool
+gate_handle_loop2 (void)
+{
+  return (optimize > 0
+         && (flag_move_loop_invariants
+              || flag_unswitch_loops
+              || flag_peel_loops
+              || flag_unroll_loops
+#ifdef HAVE_doloop_end
+             || (flag_branch_on_count_reg && HAVE_doloop_end)
+#endif
+             ));
+}
+
+struct tree_opt_pass pass_loop2 =
+{
+  "loop2",                              /* name */
+  gate_handle_loop2,                   /* gate */
+  NULL,                                 /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_LOOP,                              /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_dump_func |
+  TODO_ggc_collect,                     /* todo_flags_finish */
+  'L'                                   /* letter */
+};
+
+\f
+/* Initialization of the RTL loop passes.  */
+static unsigned int
+rtl_loop_init (void)
+{
+  if (dump_file)
+    dump_flow_info (dump_file, dump_flags);
+
+  /* Initialize structures for layout changes.  */
+  cfg_layout_initialize (0);
+
+  current_loops = loop_optimizer_init (LOOPS_NORMAL);
+  return 0;
+}
+
+struct tree_opt_pass pass_rtl_loop_init =
+{
+  "loop2_init",                           /* name */
+  NULL,                                 /* gate */
+  rtl_loop_init,                        /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_LOOP,                              /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_dump_func,                       /* todo_flags_finish */
+  'L'                                   /* letter */
+};
+
+\f
+/* Finalization of the RTL loop passes.  */
+static unsigned int
+rtl_loop_done (void)
+{
+  basic_block bb;
+
+  if (current_loops)
+    loop_optimizer_finalize (current_loops);
+
+  free_dominance_info (CDI_DOMINATORS);
+
+  /* Finalize layout changes.  */
+  FOR_EACH_BB (bb)
+    if (bb->next_bb != EXIT_BLOCK_PTR)
+      bb->aux = bb->next_bb;
+  cfg_layout_finalize ();
+
+  cleanup_cfg (CLEANUP_EXPENSIVE);
+  delete_trivially_dead_insns (get_insns (), max_reg_num ());
+  reg_scan (get_insns (), max_reg_num ());
+  if (dump_file)
+    dump_flow_info (dump_file, dump_flags);
+
+  current_loops = NULL;
+  return 0;
+}
+
+struct tree_opt_pass pass_rtl_loop_done =
+{
+  "loop2_done",                          /* name */
+  NULL,                                 /* gate */
+  rtl_loop_done,                        /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_LOOP,                              /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_dump_func,                       /* todo_flags_finish */
+  'L'                                   /* letter */
+};
+
+\f
+/* Loop invariant code motion.  */
+static bool
+gate_rtl_move_loop_invariants (void)
+{
+  return flag_move_loop_invariants;
+}
+
+static unsigned int
+rtl_move_loop_invariants (void)
+{
+  if (current_loops)
+    move_loop_invariants (current_loops);
+  return 0;
+}
+
+struct tree_opt_pass pass_rtl_move_loop_invariants =
+{
+  "loop2_invariant",                     /* name */
+  gate_rtl_move_loop_invariants,        /* gate */
+  rtl_move_loop_invariants,             /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_LOOP,                              /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_dump_func,                       /* todo_flags_finish */
+  'L'                                   /* letter */
+};
+
+\f
+/* Loop unswitching for RTL.  */
+static bool
+gate_rtl_unswitch (void)
+{
+  return flag_unswitch_loops;
+}
+
+static unsigned int
+rtl_unswitch (void)
+{
+  if (current_loops)
+    unswitch_loops (current_loops);
+  return 0;
+}
+
+struct tree_opt_pass pass_rtl_unswitch =
+{
+  "loop2_unswitch",                      /* name */
+  gate_rtl_unswitch,                    /* gate */
+  rtl_unswitch,                         /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_LOOP,                              /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_dump_func,                       /* todo_flags_finish */
+  'L'                                   /* letter */
+};
+
+\f
+/* Loop unswitching for RTL.  */
+static bool
+gate_rtl_unroll_and_peel_loops (void)
+{
+  return (flag_peel_loops || flag_unroll_loops || flag_unroll_all_loops);
+}
+
+static unsigned int
+rtl_unroll_and_peel_loops (void)
+{
+  if (current_loops)
+    {
+      int flags = 0;
+
+      if (flag_peel_loops)
+       flags |= UAP_PEEL;
+      if (flag_unroll_loops)
+       flags |= UAP_UNROLL;
+      if (flag_unroll_all_loops)
+       flags |= UAP_UNROLL_ALL;
+
+      unroll_and_peel_loops (current_loops, flags);
+    }
+  return 0;
+}
+
+struct tree_opt_pass pass_rtl_unroll_and_peel_loops =
+{
+  "loop2_unroll",                        /* name */
+  gate_rtl_unroll_and_peel_loops,       /* gate */
+  rtl_unroll_and_peel_loops,            /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_LOOP,                              /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_dump_func,                       /* todo_flags_finish */
+  'L'                                   /* letter */
+};
+
+\f
+/* The doloop optimization.  */
+static bool
+gate_rtl_doloop (void)
+{
+#ifdef HAVE_doloop_end
+  return (flag_branch_on_count_reg && HAVE_doloop_end);
+#else
+  return 0;
+#endif
+}
+
+static unsigned int
+rtl_doloop (void)
+{
+#ifdef HAVE_doloop_end
+  if (current_loops)
+    doloop_optimize_loops (current_loops);
+#endif
+  return 0;
+}
+
+struct tree_opt_pass pass_rtl_doloop =
+{
+  "loop2_doloop",                        /* name */
+  gate_rtl_doloop,                      /* gate */
+  rtl_doloop,                           /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_LOOP,                              /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_dump_func,                       /* todo_flags_finish */
+  'L'                                   /* letter */
+};
+