#include "config.h"
#include "system.h"
#include "coretypes.h"
#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 "tree-pass.h"
#include "timevar.h"
#include "flags.h"
struct loops *
loop_optimizer_init (unsigned flags)
{
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 ();
}
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);
if (flow_loops_find (loops) <= 1)
{
flow_loops_free (loops);
free (loops);
return NULL;
}
free (loops->cfg.rc_order);
loops->cfg.rc_order = NULL;
free (loops->cfg.dfs_order);
loops->cfg.dfs_order = NULL;
if (flags & LOOPS_HAVE_PREHEADERS)
create_preheaders (loops, CP_SIMPLE_PREHEADERS);
if (flags & LOOPS_HAVE_SIMPLE_LATCHES)
force_single_succ_latches (loops);
if (flags & LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS)
mark_irreducible_loops (loops);
if (flags & LOOPS_HAVE_MARKED_SINGLE_EXITS)
mark_single_exit_loops (loops);
flow_loops_dump (loops, dump_file, NULL, 1);
#ifdef ENABLE_CHECKING
verify_dominators (CDI_DOMINATORS);
verify_loop_structure (loops);
#endif
return loops;
}
void
loop_optimizer_finalize (struct loops *loops)
{
unsigned i;
if (!loops)
return;
for (i = 1; i < loops->num; i++)
if (loops->parray[i])
free_simple_loop_desc (loops->parray[i]);
flow_loops_free (loops);
free (loops);
#ifdef ENABLE_CHECKING
verify_flow_info ();
#endif
}
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",
gate_handle_loop2,
NULL,
NULL,
NULL,
0,
TV_LOOP,
0,
0,
0,
0,
TODO_dump_func |
TODO_ggc_collect,
'L'
};
static unsigned int
rtl_loop_init (void)
{
if (dump_file)
dump_flow_info (dump_file, dump_flags);
cfg_layout_initialize (0);
current_loops = loop_optimizer_init (LOOPS_NORMAL);
return 0;
}
struct tree_opt_pass pass_rtl_loop_init =
{
"loop2_init",
NULL,
rtl_loop_init,
NULL,
NULL,
0,
TV_LOOP,
0,
0,
0,
0,
TODO_dump_func,
'L'
};
static unsigned int
rtl_loop_done (void)
{
basic_block bb;
if (current_loops)
loop_optimizer_finalize (current_loops);
free_dominance_info (CDI_DOMINATORS);
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",
NULL,
rtl_loop_done,
NULL,
NULL,
0,
TV_LOOP,
0,
0,
0,
0,
TODO_dump_func,
'L'
};
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",
gate_rtl_move_loop_invariants,
rtl_move_loop_invariants,
NULL,
NULL,
0,
TV_LOOP,
0,
0,
0,
0,
TODO_dump_func,
'L'
};
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",
gate_rtl_unswitch,
rtl_unswitch,
NULL,
NULL,
0,
TV_LOOP,
0,
0,
0,
0,
TODO_dump_func,
'L'
};
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",
gate_rtl_unroll_and_peel_loops,
rtl_unroll_and_peel_loops,
NULL,
NULL,
0,
TV_LOOP,
0,
0,
0,
0,
TODO_dump_func,
'L'
};
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",
gate_rtl_doloop,
rtl_doloop,
NULL,
NULL,
0,
TV_LOOP,
0,
0,
0,
0,
TODO_dump_func,
'L'
};