X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Floop-init.c;h=854bb9708799967a9b7d66424bc2b1fa0978d3f2;hb=398d7b2bf98caebd8885c9c274a35a25f539b1e8;hp=375b2bf23a5e310b13a31a400e5a0e8455909e18;hpb=77fce4cd57cbc9db7cdbc15bba96e178dbd0f879;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/loop-init.c b/gcc/loop-init.c index 375b2bf23a5..854bb970879 100644 --- a/gcc/loop-init.c +++ b/gcc/loop-init.c @@ -1,11 +1,12 @@ -/* Loop optimizer initialization routines. - Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. +/* Loop optimizer initialization routines and RTL loop optimization passes. + Copyright (C) 2002, 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 +. */ #include "config.h" #include "system.h" @@ -31,176 +31,372 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "tree-pass.h" #include "timevar.h" #include "flags.h" +#include "df.h" +#include "ggc.h" -/* Initialize loop optimizer. */ + +/* Initialize loop structures. 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 (FILE *dumpfile) +void +loop_optimizer_init (unsigned flags) { - struct loops *loops = xcalloc (1, sizeof (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. */ + struct loops *loops; - 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); + gcc_assert (!current_loops); + loops = GGC_CNEW (struct loops); /* Find the loops. */ - if (flow_loops_find (loops) <= 1) - { - /* No loops. */ - flow_loops_free (loops); - free (loops); + flow_loops_find (loops); + current_loops = loops; - return NULL; + if (flags & LOOPS_MAY_HAVE_MULTIPLE_LATCHES) + { + /* If the loops may have multiple latches, we cannot canonicalize + them further (and most of the loop manipulation functions will + not work). However, we avoid modifying cfg, which some + passes may want. */ + gcc_assert ((flags & ~(LOOPS_MAY_HAVE_MULTIPLE_LATCHES + | LOOPS_HAVE_RECORDED_EXITS)) == 0); + loops_state_set (LOOPS_MAY_HAVE_MULTIPLE_LATCHES); } - - /* Not going to update these. */ - free (loops->cfg.rc_order); - loops->cfg.rc_order = NULL; - free (loops->cfg.dfs_order); - loops->cfg.dfs_order = NULL; + else + disambiguate_loops_with_multiple_latches (); /* Create pre-headers. */ - create_preheaders (loops, CP_SIMPLE_PREHEADERS); + if (flags & LOOPS_HAVE_PREHEADERS) + { + int cp_flags = CP_SIMPLE_PREHEADERS; + + if (flags & LOOPS_HAVE_FALLTHRU_PREHEADERS) + cp_flags |= CP_FALLTHRU_PREHEADERS; + + create_preheaders (cp_flags); + } /* Force all latches to have only single successor. */ - force_single_succ_latches (loops); + if (flags & LOOPS_HAVE_SIMPLE_LATCHES) + force_single_succ_latches (); /* Mark irreducible loops. */ - mark_irreducible_loops (loops); + if (flags & LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS) + mark_irreducible_loops (); + + if (flags & LOOPS_HAVE_RECORDED_EXITS) + record_loop_exits (); /* Dump loops. */ - flow_loops_dump (loops, dumpfile, NULL, 1); + flow_loops_dump (dump_file, NULL, 1); #ifdef ENABLE_CHECKING verify_dominators (CDI_DOMINATORS); - verify_loop_structure (loops); + verify_loop_structure (); #endif - - return loops; } -/* Finalize loop optimizer. */ +/* Finalize loop structures. */ + void -loop_optimizer_finalize (struct loops *loops, FILE *dumpfile) +loop_optimizer_finalize (void) { - unsigned i; - - if (!loops) - return; + loop_iterator li; + struct loop *loop; + basic_block bb; - for (i = 1; i < loops->num; i++) - if (loops->parray[i]) - free_simple_loop_desc (loops->parray[i]); + gcc_assert (current_loops != NULL); - /* Another dump. */ - flow_loops_dump (loops, dumpfile, NULL, 1); + FOR_EACH_LOOP (li, loop, 0) + { + free_simple_loop_desc (loop); + } /* Clean up. */ - flow_loops_free (loops); - free (loops); + if (loops_state_satisfies_p (LOOPS_HAVE_RECORDED_EXITS)) + release_recorded_exits (); + flow_loops_free (current_loops); + ggc_free (current_loops); + current_loops = NULL; + + FOR_ALL_BB (bb) + { + bb->loop_father = NULL; + } /* Checking. */ #ifdef ENABLE_CHECKING - verify_flow_info (); + /* FIXME: no point to verify flow info after bundling on ia64. Use this + hack for achieving this. */ + if (!reload_completed) + verify_flow_info (); #endif } + +/* 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_loop_optimize2 + return (optimize > 0 && (flag_move_loop_invariants || flag_unswitch_loops || flag_peel_loops || flag_unroll_loops - || flag_branch_on_count_reg)); +#ifdef HAVE_doloop_end + || (flag_branch_on_count_reg && HAVE_doloop_end) +#endif + )); } -/* Perform loop optimizations. It might be better to do them a bit - sooner, but we want the profile feedback to work more - efficiently. */ -static void -rest_of_handle_loop2 (void) +struct rtl_opt_pass pass_loop2 = { - struct loops *loops; - basic_block bb; + { + RTL_PASS, + "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 */ + } +}; + + +/* Initialization of the RTL loop passes. */ +static unsigned int +rtl_loop_init (void) +{ + gcc_assert (current_ir_type () == IR_RTL_CFGLAYOUT); if (dump_file) - dump_flow_info (dump_file); + dump_flow_info (dump_file, dump_flags); - /* Initialize structures for layout changes. */ - cfg_layout_initialize (0); + loop_optimizer_init (LOOPS_NORMAL); + return 0; +} - loops = loop_optimizer_init (dump_file); +struct rtl_opt_pass pass_rtl_loop_init = +{ + { + RTL_PASS, + "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_verify_rtl_sharing /* todo_flags_finish */ + } +}; - if (loops) - { - /* The optimizations: */ - if (flag_move_loop_invariants) - move_loop_invariants (loops); + +/* Finalization of the RTL loop passes. */ - if (flag_unswitch_loops) - unswitch_loops (loops); +static unsigned int +rtl_loop_done (void) +{ + loop_optimizer_finalize (); + free_dominance_info (CDI_DOMINATORS); - if (flag_peel_loops || flag_unroll_loops) - unroll_and_peel_loops (loops, - (flag_peel_loops ? UAP_PEEL : 0) | - (flag_unroll_loops ? UAP_UNROLL : 0) | - (flag_unroll_all_loops ? UAP_UNROLL_ALL : 0)); + cleanup_cfg (0); + if (dump_file) + dump_flow_info (dump_file, dump_flags); -#ifdef HAVE_doloop_end - if (flag_branch_on_count_reg && HAVE_doloop_end) - doloop_optimize_loops (loops); -#endif /* HAVE_doloop_end */ + return 0; +} + +struct rtl_opt_pass pass_rtl_loop_done = +{ + { + RTL_PASS, + "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_verify_rtl_sharing /* todo_flags_finish */ + } +}; + + +/* 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 (number_of_loops () > 1) + move_loop_invariants (); + return 0; +} + +struct rtl_opt_pass pass_rtl_move_loop_invariants = +{ + { + RTL_PASS, + "loop2_invariant", /* name */ + gate_rtl_move_loop_invariants, /* gate */ + rtl_move_loop_invariants, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_LOOP_MOVE_INVARIANTS, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_df_verify | + TODO_df_finish | TODO_verify_rtl_sharing | + TODO_dump_func /* todo_flags_finish */ + } +}; + + +/* Loop unswitching for RTL. */ +static bool +gate_rtl_unswitch (void) +{ + return flag_unswitch_loops; +} + +static unsigned int +rtl_unswitch (void) +{ + if (number_of_loops () > 1) + unswitch_loops (); + return 0; +} - loop_optimizer_finalize (loops, dump_file); +struct rtl_opt_pass pass_rtl_unswitch = +{ + { + RTL_PASS, + "loop2_unswitch", /* name */ + gate_rtl_unswitch, /* gate */ + rtl_unswitch, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_LOOP_UNSWITCH, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func | TODO_verify_rtl_sharing, /* todo_flags_finish */ + } +}; + + +/* 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 (number_of_loops () > 1) + { + int flags = 0; + if (dump_file) + df_dump (dump_file); + + 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 (flags); } + return 0; +} - free_dominance_info (CDI_DOMINATORS); +struct rtl_opt_pass pass_rtl_unroll_and_peel_loops = +{ + { + RTL_PASS, + "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_UNROLL, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func | TODO_verify_rtl_sharing, /* todo_flags_finish */ + } +}; - /* Finalize layout changes. */ - FOR_EACH_BB (bb) - if (bb->next_bb != EXIT_BLOCK_PTR) - bb->aux = bb->next_bb; - cfg_layout_finalize (); + +/* 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 +} - 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); +static unsigned int +rtl_doloop (void) +{ +#ifdef HAVE_doloop_end + if (number_of_loops () > 1) + doloop_optimize_loops (); +#endif + return 0; } -struct tree_opt_pass pass_loop2 = +struct rtl_opt_pass pass_rtl_doloop = { - "loop2", /* name */ - gate_handle_loop2, /* gate */ - rest_of_handle_loop2, /* execute */ + { + RTL_PASS, + "loop2_doloop", /* name */ + gate_rtl_doloop, /* gate */ + rtl_doloop, /* execute */ NULL, /* sub */ NULL, /* next */ 0, /* static_pass_number */ - TV_LOOP, /* tv_id */ + TV_LOOP_DOLOOP, /* 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 */ + TODO_dump_func | TODO_verify_rtl_sharing /* todo_flags_finish */ + } };