/* Loop optimizer initialization routines and RTL loop optimization passes.
- Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+ Copyright (C) 2002-2021 Free Software Foundation, Inc.
This file is part of GCC.
#include "config.h"
#include "system.h"
#include "coretypes.h"
-#include "tm.h"
+#include "backend.h"
+#include "target.h"
#include "rtl.h"
-#include "hard-reg-set.h"
-#include "obstack.h"
-#include "basic-block.h"
+#include "tree.h"
+#include "cfghooks.h"
+#include "df.h"
+#include "regs.h"
+#include "cfgcleanup.h"
#include "cfgloop.h"
-#include "cfglayout.h"
#include "tree-pass.h"
-#include "timevar.h"
-#include "flags.h"
-#include "df.h"
-#include "ggc.h"
+#include "tree-ssa-loop-niter.h"
+#include "loop-unroll.h"
+#include "tree-scalar-evolution.h"
+#include "tree-cfgcleanup.h"
\f
-/* Initialize loop structures. This is used by the tree and RTL loop
- optimizers. FLAGS specify what properties to compute and/or ensure for
- loops. */
+/* Apply FLAGS to the loop state. */
-void
-loop_optimizer_init (unsigned flags)
+static void
+apply_loop_flags (unsigned flags)
{
- struct loops *loops;
-
- gcc_assert (!current_loops);
- loops = GGC_CNEW (struct loops);
-
- /* Find the loops. */
-
- flow_loops_find (loops);
- current_loops = loops;
-
if (flags & LOOPS_MAY_HAVE_MULTIPLE_LATCHES)
{
/* If the loops may have multiple latches, we cannot canonicalize
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_HAVE_RECORDED_EXITS
+ | LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS)) == 0);
loops_state_set (LOOPS_MAY_HAVE_MULTIPLE_LATCHES);
}
else
/* Create pre-headers. */
if (flags & LOOPS_HAVE_PREHEADERS)
- create_preheaders (CP_SIMPLE_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. */
if (flags & LOOPS_HAVE_SIMPLE_LATCHES)
if (flags & LOOPS_HAVE_RECORDED_EXITS)
record_loop_exits ();
+}
+
+/* Initialize loop structures. This is used by the tree and RTL loop
+ optimizers. FLAGS specify what properties to compute and/or ensure for
+ loops. */
+
+void
+loop_optimizer_init (unsigned flags)
+{
+ timevar_push (TV_LOOP_INIT);
+
+ if (!current_loops)
+ {
+ gcc_assert (!(cfun->curr_properties & PROP_loops));
+
+ /* Find the loops. */
+ current_loops = flow_loops_find (NULL);
+ }
+ else
+ {
+ bool recorded_exits = loops_state_satisfies_p (LOOPS_HAVE_RECORDED_EXITS);
+ bool needs_fixup = loops_state_satisfies_p (LOOPS_NEED_FIXUP);
+
+ gcc_assert (cfun->curr_properties & PROP_loops);
+
+ /* Ensure that the dominators are computed, like flow_loops_find does. */
+ calculate_dominance_info (CDI_DOMINATORS);
+
+ if (!needs_fixup)
+ checking_verify_loop_structure ();
+
+ /* Clear all flags. */
+ if (recorded_exits)
+ release_recorded_exits (cfun);
+ loops_state_clear (~0U);
+
+ if (needs_fixup)
+ {
+ /* Apply LOOPS_MAY_HAVE_MULTIPLE_LATCHES early as fix_loop_structure
+ re-applies flags. */
+ loops_state_set (flags & LOOPS_MAY_HAVE_MULTIPLE_LATCHES);
+ fix_loop_structure (NULL);
+ }
+ }
+
+ /* Apply flags to loops. */
+ apply_loop_flags (flags);
/* Dump loops. */
flow_loops_dump (dump_file, NULL, 1);
-#ifdef ENABLE_CHECKING
- verify_dominators (CDI_DOMINATORS);
- verify_loop_structure ();
-#endif
+ checking_verify_loop_structure ();
+
+ timevar_pop (TV_LOOP_INIT);
}
/* Finalize loop structures. */
void
-loop_optimizer_finalize (void)
+loop_optimizer_finalize (struct function *fn, bool clean_loop_closed_phi)
{
- loop_iterator li;
- struct loop *loop;
basic_block bb;
- gcc_assert (current_loops != NULL);
+ timevar_push (TV_LOOP_FINI);
+
+ if (clean_loop_closed_phi && loops_state_satisfies_p (fn, LOOP_CLOSED_SSA))
+ {
+ clean_up_loop_closed_phi (fn);
+ loops_state_clear (fn, LOOP_CLOSED_SSA);
+ }
+
+ if (loops_state_satisfies_p (fn, LOOPS_HAVE_RECORDED_EXITS))
+ release_recorded_exits (fn);
- FOR_EACH_LOOP (li, loop, 0)
+ free_numbers_of_iterations_estimates (fn);
+
+ /* If we should preserve loop structure, do not free it but clear
+ flags that advanced properties are there as we are not preserving
+ that in full. */
+ if (fn->curr_properties & PROP_loops)
{
- free_simple_loop_desc (loop);
+ loops_state_clear (fn, LOOP_CLOSED_SSA
+ | LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS
+ | LOOPS_HAVE_PREHEADERS
+ | LOOPS_HAVE_SIMPLE_LATCHES
+ | LOOPS_HAVE_FALLTHRU_PREHEADERS);
+ loops_state_set (fn, LOOPS_MAY_HAVE_MULTIPLE_LATCHES);
+ goto loop_fini_done;
}
+ for (auto loop : loops_list (fn, 0))
+ free_simple_loop_desc (loop);
+
/* Clean up. */
- if (loops_state_satisfies_p (LOOPS_HAVE_RECORDED_EXITS))
- release_recorded_exits ();
- flow_loops_free (current_loops);
- ggc_free (current_loops);
- current_loops = NULL;
+ flow_loops_free (loops_for_fn (fn));
+ ggc_free (loops_for_fn (fn));
+ set_loops_for_fn (fn, NULL);
- FOR_ALL_BB (bb)
+ FOR_ALL_BB_FN (bb, fn)
{
bb->loop_father = NULL;
}
- /* Checking. */
-#ifdef ENABLE_CHECKING
- verify_flow_info ();
-#endif
+loop_fini_done:
+ timevar_pop (TV_LOOP_FINI);
}
-\f
-/* Gate for the RTL loop superpass. The actual passes are subpasses.
- See passes.c for more on that. */
+/* The structure of loops might have changed. Some loops might get removed
+ (and their headers and latches were set to NULL), loop exists might get
+ removed (thus the loop nesting may be wrong), and some blocks and edges
+ were changed (so the information about bb --> loop mapping does not have
+ to be correct). But still for the remaining loops the header dominates
+ the latch, and loops did not get new subloops (new loops might possibly
+ get created, but we are not interested in them). Fix up the mess.
+
+ If CHANGED_BBS is not NULL, basic blocks whose loop depth has changed are
+ marked in it.
-static bool
-gate_handle_loop2 (void)
+ Returns the number of new discovered loops. */
+
+unsigned
+fix_loop_structure (bitmap changed_bbs)
{
- 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
- ));
+ basic_block bb;
+ int record_exits = 0;
+ class loop *loop;
+ unsigned old_nloops, i;
+
+ timevar_push (TV_LOOP_INIT);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "fix_loop_structure: fixing up loops for function\n");
+
+ /* We need exact and fast dominance info to be available. */
+ gcc_assert (dom_info_state (CDI_DOMINATORS) == DOM_OK);
+
+ if (loops_state_satisfies_p (LOOPS_HAVE_RECORDED_EXITS))
+ {
+ release_recorded_exits (cfun);
+ record_exits = LOOPS_HAVE_RECORDED_EXITS;
+ }
+
+ /* Remember the depth of the blocks in the loop hierarchy, so that we can
+ recognize blocks whose loop nesting relationship has changed. */
+ if (changed_bbs)
+ FOR_EACH_BB_FN (bb, cfun)
+ bb->aux = (void *) (size_t) loop_depth (bb->loop_father);
+
+ /* Remove the dead loops from structures. We start from the innermost
+ loops, so that when we remove the loops, we know that the loops inside
+ are preserved, and do not waste time relinking loops that will be
+ removed later. */
+ for (auto loop : loops_list (cfun, LI_FROM_INNERMOST))
+ {
+ /* Detect the case that the loop is no longer present even though
+ it wasn't marked for removal.
+ ??? If we do that we can get away with not marking loops for
+ removal at all. And possibly avoid some spurious removals. */
+ if (loop->header
+ && bb_loop_header_p (loop->header))
+ continue;
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "fix_loop_structure: removing loop %d\n",
+ loop->num);
+
+ while (loop->inner)
+ {
+ class loop *ploop = loop->inner;
+ flow_loop_tree_node_remove (ploop);
+ flow_loop_tree_node_add (loop_outer (loop), ploop);
+ }
+
+ /* Remove the loop. */
+ if (loop->header)
+ loop->former_header = loop->header;
+ else
+ gcc_assert (loop->former_header != NULL);
+ loop->header = NULL;
+ flow_loop_tree_node_remove (loop);
+ }
+
+ /* Remember the number of loops so we can return how many new loops
+ flow_loops_find discovered. */
+ old_nloops = number_of_loops (cfun);
+
+ /* Re-compute loop structure in-place. */
+ flow_loops_find (current_loops);
+
+ /* Mark the blocks whose loop has changed. */
+ if (changed_bbs)
+ {
+ FOR_EACH_BB_FN (bb, cfun)
+ {
+ if ((void *) (size_t) loop_depth (bb->loop_father) != bb->aux)
+ bitmap_set_bit (changed_bbs, bb->index);
+
+ bb->aux = NULL;
+ }
+ }
+
+ /* Finally free deleted loops. */
+ bool any_deleted = false;
+ FOR_EACH_VEC_ELT (*get_loops (cfun), i, loop)
+ if (loop && loop->header == NULL)
+ {
+ if (dump_file
+ && ((unsigned) loop->former_header->index
+ < basic_block_info_for_fn (cfun)->length ()))
+ {
+ basic_block former_header
+ = BASIC_BLOCK_FOR_FN (cfun, loop->former_header->index);
+ /* If the old header still exists we want to check if the
+ original loop is re-discovered or the old header is now
+ part of a newly discovered loop.
+ In both cases we should have avoided removing the loop. */
+ if (former_header == loop->former_header)
+ {
+ if (former_header->loop_father->header == former_header)
+ fprintf (dump_file, "fix_loop_structure: rediscovered "
+ "removed loop %d as loop %d with old header %d\n",
+ loop->num, former_header->loop_father->num,
+ former_header->index);
+ else if ((unsigned) former_header->loop_father->num
+ >= old_nloops)
+ fprintf (dump_file, "fix_loop_structure: header %d of "
+ "removed loop %d is part of the newly "
+ "discovered loop %d with header %d\n",
+ former_header->index, loop->num,
+ former_header->loop_father->num,
+ former_header->loop_father->header->index);
+ }
+ }
+ (*get_loops (cfun))[i] = NULL;
+ flow_loop_free (loop);
+ any_deleted = true;
+ }
+
+ /* If we deleted loops then the cached scalar evolutions refering to
+ those loops become invalid. */
+ if (any_deleted && scev_initialized_p ())
+ scev_reset_htab ();
+
+ loops_state_clear (LOOPS_NEED_FIXUP);
+
+ /* Apply flags to loops. */
+ apply_loop_flags (current_loops->state | record_exits);
+
+ checking_verify_loop_structure ();
+
+ timevar_pop (TV_LOOP_INIT);
+
+ return number_of_loops (cfun) - old_nloops;
}
+\f
+/* The RTL loop superpass. The actual passes are subpasses. See passes.c for
+ more on that. */
+
+namespace {
-struct rtl_opt_pass pass_loop2 =
+const pass_data pass_data_loop2 =
{
- {
- 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 */
- }
+ RTL_PASS, /* type */
+ "loop2", /* name */
+ OPTGROUP_LOOP, /* optinfo_flags */
+ TV_LOOP, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
};
+class pass_loop2 : public rtl_opt_pass
+{
+public:
+ pass_loop2 (gcc::context *ctxt)
+ : rtl_opt_pass (pass_data_loop2, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ virtual bool gate (function *);
+
+}; // class pass_loop2
+
+bool
+pass_loop2::gate (function *fun)
+{
+ if (optimize > 0
+ && (flag_move_loop_invariants
+ || flag_unswitch_loops
+ || flag_unroll_loops
+ || (flag_branch_on_count_reg && targetm.have_doloop_end ())
+ || cfun->has_unroll))
+ return true;
+ else
+ {
+ /* No longer preserve loops, remove them now. */
+ fun->curr_properties &= ~PROP_loops;
+ if (current_loops)
+ loop_optimizer_finalize ();
+ return false;
+ }
+}
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_loop2 (gcc::context *ctxt)
+{
+ return new pass_loop2 (ctxt);
+}
+
\f
/* 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_flags);
+ {
+ dump_reg_info (dump_file);
+ dump_flow_info (dump_file, dump_flags);
+ }
- loop_optimizer_init (LOOPS_NORMAL);
+ loop_optimizer_init (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS);
return 0;
}
-struct rtl_opt_pass pass_rtl_loop_init =
+namespace {
+
+const pass_data pass_data_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 */
- }
+ RTL_PASS, /* type */
+ "loop2_init", /* name */
+ OPTGROUP_LOOP, /* optinfo_flags */
+ TV_LOOP, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
};
+class pass_rtl_loop_init : public rtl_opt_pass
+{
+public:
+ pass_rtl_loop_init (gcc::context *ctxt)
+ : rtl_opt_pass (pass_data_rtl_loop_init, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ virtual unsigned int execute (function *) { return rtl_loop_init (); }
+
+}; // class pass_rtl_loop_init
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_rtl_loop_init (gcc::context *ctxt)
+{
+ return new pass_rtl_loop_init (ctxt);
+}
+
\f
/* Finalization of the RTL loop passes. */
-static unsigned int
-rtl_loop_done (void)
+namespace {
+
+const pass_data pass_data_rtl_loop_done =
+{
+ RTL_PASS, /* type */
+ "loop2_done", /* name */
+ OPTGROUP_LOOP, /* optinfo_flags */
+ TV_LOOP, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ PROP_loops, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
+};
+
+class pass_rtl_loop_done : public rtl_opt_pass
+{
+public:
+ pass_rtl_loop_done (gcc::context *ctxt)
+ : rtl_opt_pass (pass_data_rtl_loop_done, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ virtual unsigned int execute (function *);
+
+}; // class pass_rtl_loop_done
+
+unsigned int
+pass_rtl_loop_done::execute (function *fun)
{
+ /* No longer preserve loops, remove them now. */
+ fun->curr_properties &= ~PROP_loops;
loop_optimizer_finalize ();
free_dominance_info (CDI_DOMINATORS);
cleanup_cfg (0);
if (dump_file)
- dump_flow_info (dump_file, dump_flags);
+ {
+ dump_reg_info (dump_file);
+ dump_flow_info (dump_file, dump_flags);
+ }
return 0;
}
-struct rtl_opt_pass pass_rtl_loop_done =
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_rtl_loop_done (gcc::context *ctxt)
{
- {
- 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 */
- }
-};
+ return new pass_rtl_loop_done (ctxt);
+}
\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 (number_of_loops () > 1)
- move_loop_invariants ();
- return 0;
-}
+namespace {
-struct rtl_opt_pass pass_rtl_move_loop_invariants =
+const pass_data pass_data_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, /* 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 */
- }
+ RTL_PASS, /* type */
+ "loop2_invariant", /* name */
+ OPTGROUP_LOOP, /* optinfo_flags */
+ 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_flags_finish */
};
-\f
-/* Loop unswitching for RTL. */
-static bool
-gate_rtl_unswitch (void)
+class pass_rtl_move_loop_invariants : public rtl_opt_pass
{
- return flag_unswitch_loops;
-}
+public:
+ pass_rtl_move_loop_invariants (gcc::context *ctxt)
+ : rtl_opt_pass (pass_data_rtl_move_loop_invariants, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ virtual bool gate (function *) { return flag_move_loop_invariants; }
+ virtual unsigned int execute (function *fun)
+ {
+ if (number_of_loops (fun) > 1)
+ move_loop_invariants ();
+ return 0;
+ }
-static unsigned int
-rtl_unswitch (void)
+}; // class pass_rtl_move_loop_invariants
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_rtl_move_loop_invariants (gcc::context *ctxt)
{
- if (number_of_loops () > 1)
- unswitch_loops ();
- return 0;
+ return new pass_rtl_move_loop_invariants (ctxt);
}
-struct rtl_opt_pass pass_rtl_unswitch =
+\f
+namespace {
+
+const pass_data pass_data_rtl_unroll_loops =
{
- {
- RTL_PASS,
- "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_verify_rtl_sharing, /* todo_flags_finish */
- }
+ RTL_PASS, /* type */
+ "loop2_unroll", /* name */
+ OPTGROUP_LOOP, /* optinfo_flags */
+ TV_LOOP_UNROLL, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
};
-\f
-/* Loop unswitching for RTL. */
-static bool
-gate_rtl_unroll_and_peel_loops (void)
+class pass_rtl_unroll_loops : public rtl_opt_pass
{
- return (flag_peel_loops || flag_unroll_loops || flag_unroll_all_loops);
-}
+public:
+ pass_rtl_unroll_loops (gcc::context *ctxt)
+ : rtl_opt_pass (pass_data_rtl_unroll_loops, ctxt)
+ {}
-static unsigned int
-rtl_unroll_and_peel_loops (void)
+ /* opt_pass methods: */
+ virtual bool gate (function *)
+ {
+ return (flag_unroll_loops || flag_unroll_all_loops || cfun->has_unroll);
+ }
+
+ virtual unsigned int execute (function *);
+
+}; // class pass_rtl_unroll_loops
+
+unsigned int
+pass_rtl_unroll_loops::execute (function *fun)
{
- if (number_of_loops () > 1)
+ if (number_of_loops (fun) > 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);
+ unroll_loops (flags);
}
return 0;
}
-struct rtl_opt_pass pass_rtl_unroll_and_peel_loops =
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_rtl_unroll_loops (gcc::context *ctxt)
{
- {
- 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, /* 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 */
- }
-};
+ return new pass_rtl_unroll_loops (ctxt);
+}
\f
-/* The doloop optimization. */
-static bool
-gate_rtl_doloop (void)
+namespace {
+
+const pass_data pass_data_rtl_doloop =
{
-#ifdef HAVE_doloop_end
- return (flag_branch_on_count_reg && HAVE_doloop_end);
-#else
- return 0;
-#endif
+ RTL_PASS, /* type */
+ "loop2_doloop", /* name */
+ OPTGROUP_LOOP, /* optinfo_flags */
+ TV_LOOP_DOLOOP, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
+};
+
+class pass_rtl_doloop : public rtl_opt_pass
+{
+public:
+ pass_rtl_doloop (gcc::context *ctxt)
+ : rtl_opt_pass (pass_data_rtl_doloop, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ virtual bool gate (function *);
+ virtual unsigned int execute (function *);
+
+}; // class pass_rtl_doloop
+
+bool
+pass_rtl_doloop::gate (function *)
+{
+ return (flag_branch_on_count_reg && targetm.have_doloop_end ());
}
-static unsigned int
-rtl_doloop (void)
+unsigned int
+pass_rtl_doloop::execute (function *fun)
{
-#ifdef HAVE_doloop_end
- if (number_of_loops () > 1)
+ if (number_of_loops (fun) > 1)
doloop_optimize_loops ();
-#endif
return 0;
}
-struct rtl_opt_pass pass_rtl_doloop =
-{
- {
- RTL_PASS,
- "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_verify_rtl_sharing /* todo_flags_finish */
- }
-};
+} // anon namespace
+rtl_opt_pass *
+make_pass_rtl_doloop (gcc::context *ctxt)
+{
+ return new pass_rtl_doloop (ctxt);
+}