xref: /dflybsd-src/contrib/gcc-8.0/gcc/loop-init.c (revision 38fd149817dfbff97799f62fcb70be98c4e32523)
1*38fd1498Szrj /* Loop optimizer initialization routines and RTL loop optimization passes.
2*38fd1498Szrj    Copyright (C) 2002-2018 Free Software Foundation, Inc.
3*38fd1498Szrj 
4*38fd1498Szrj This file is part of GCC.
5*38fd1498Szrj 
6*38fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
7*38fd1498Szrj the terms of the GNU General Public License as published by the Free
8*38fd1498Szrj Software Foundation; either version 3, or (at your option) any later
9*38fd1498Szrj version.
10*38fd1498Szrj 
11*38fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12*38fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
13*38fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14*38fd1498Szrj for more details.
15*38fd1498Szrj 
16*38fd1498Szrj You should have received a copy of the GNU General Public License
17*38fd1498Szrj along with GCC; see the file COPYING3.  If not see
18*38fd1498Szrj <http://www.gnu.org/licenses/>.  */
19*38fd1498Szrj 
20*38fd1498Szrj #include "config.h"
21*38fd1498Szrj #include "system.h"
22*38fd1498Szrj #include "coretypes.h"
23*38fd1498Szrj #include "backend.h"
24*38fd1498Szrj #include "target.h"
25*38fd1498Szrj #include "rtl.h"
26*38fd1498Szrj #include "tree.h"
27*38fd1498Szrj #include "cfghooks.h"
28*38fd1498Szrj #include "df.h"
29*38fd1498Szrj #include "regs.h"
30*38fd1498Szrj #include "cfgcleanup.h"
31*38fd1498Szrj #include "cfgloop.h"
32*38fd1498Szrj #include "tree-pass.h"
33*38fd1498Szrj #include "tree-ssa-loop-niter.h"
34*38fd1498Szrj #include "loop-unroll.h"
35*38fd1498Szrj #include "tree-scalar-evolution.h"
36*38fd1498Szrj 
37*38fd1498Szrj 
38*38fd1498Szrj /* Apply FLAGS to the loop state.  */
39*38fd1498Szrj 
40*38fd1498Szrj static void
apply_loop_flags(unsigned flags)41*38fd1498Szrj apply_loop_flags (unsigned flags)
42*38fd1498Szrj {
43*38fd1498Szrj   if (flags & LOOPS_MAY_HAVE_MULTIPLE_LATCHES)
44*38fd1498Szrj     {
45*38fd1498Szrj       /* If the loops may have multiple latches, we cannot canonicalize
46*38fd1498Szrj 	 them further (and most of the loop manipulation functions will
47*38fd1498Szrj 	 not work).  However, we avoid modifying cfg, which some
48*38fd1498Szrj 	 passes may want.  */
49*38fd1498Szrj       gcc_assert ((flags & ~(LOOPS_MAY_HAVE_MULTIPLE_LATCHES
50*38fd1498Szrj 			     | LOOPS_HAVE_RECORDED_EXITS)) == 0);
51*38fd1498Szrj       loops_state_set (LOOPS_MAY_HAVE_MULTIPLE_LATCHES);
52*38fd1498Szrj     }
53*38fd1498Szrj   else
54*38fd1498Szrj     disambiguate_loops_with_multiple_latches ();
55*38fd1498Szrj 
56*38fd1498Szrj   /* Create pre-headers.  */
57*38fd1498Szrj   if (flags & LOOPS_HAVE_PREHEADERS)
58*38fd1498Szrj     {
59*38fd1498Szrj       int cp_flags = CP_SIMPLE_PREHEADERS;
60*38fd1498Szrj 
61*38fd1498Szrj       if (flags & LOOPS_HAVE_FALLTHRU_PREHEADERS)
62*38fd1498Szrj         cp_flags |= CP_FALLTHRU_PREHEADERS;
63*38fd1498Szrj 
64*38fd1498Szrj       create_preheaders (cp_flags);
65*38fd1498Szrj     }
66*38fd1498Szrj 
67*38fd1498Szrj   /* Force all latches to have only single successor.  */
68*38fd1498Szrj   if (flags & LOOPS_HAVE_SIMPLE_LATCHES)
69*38fd1498Szrj     force_single_succ_latches ();
70*38fd1498Szrj 
71*38fd1498Szrj   /* Mark irreducible loops.  */
72*38fd1498Szrj   if (flags & LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS)
73*38fd1498Szrj     mark_irreducible_loops ();
74*38fd1498Szrj 
75*38fd1498Szrj   if (flags & LOOPS_HAVE_RECORDED_EXITS)
76*38fd1498Szrj     record_loop_exits ();
77*38fd1498Szrj }
78*38fd1498Szrj 
79*38fd1498Szrj /* Initialize loop structures.  This is used by the tree and RTL loop
80*38fd1498Szrj    optimizers.  FLAGS specify what properties to compute and/or ensure for
81*38fd1498Szrj    loops.  */
82*38fd1498Szrj 
83*38fd1498Szrj void
loop_optimizer_init(unsigned flags)84*38fd1498Szrj loop_optimizer_init (unsigned flags)
85*38fd1498Szrj {
86*38fd1498Szrj   timevar_push (TV_LOOP_INIT);
87*38fd1498Szrj 
88*38fd1498Szrj   if (!current_loops)
89*38fd1498Szrj     {
90*38fd1498Szrj       gcc_assert (!(cfun->curr_properties & PROP_loops));
91*38fd1498Szrj 
92*38fd1498Szrj       /* Find the loops.  */
93*38fd1498Szrj       current_loops = flow_loops_find (NULL);
94*38fd1498Szrj     }
95*38fd1498Szrj   else
96*38fd1498Szrj     {
97*38fd1498Szrj       bool recorded_exits = loops_state_satisfies_p (LOOPS_HAVE_RECORDED_EXITS);
98*38fd1498Szrj       bool needs_fixup = loops_state_satisfies_p (LOOPS_NEED_FIXUP);
99*38fd1498Szrj 
100*38fd1498Szrj       gcc_assert (cfun->curr_properties & PROP_loops);
101*38fd1498Szrj 
102*38fd1498Szrj       /* Ensure that the dominators are computed, like flow_loops_find does.  */
103*38fd1498Szrj       calculate_dominance_info (CDI_DOMINATORS);
104*38fd1498Szrj 
105*38fd1498Szrj       if (!needs_fixup)
106*38fd1498Szrj 	checking_verify_loop_structure ();
107*38fd1498Szrj 
108*38fd1498Szrj       /* Clear all flags.  */
109*38fd1498Szrj       if (recorded_exits)
110*38fd1498Szrj 	release_recorded_exits (cfun);
111*38fd1498Szrj       loops_state_clear (~0U);
112*38fd1498Szrj 
113*38fd1498Szrj       if (needs_fixup)
114*38fd1498Szrj 	{
115*38fd1498Szrj 	  /* Apply LOOPS_MAY_HAVE_MULTIPLE_LATCHES early as fix_loop_structure
116*38fd1498Szrj 	     re-applies flags.  */
117*38fd1498Szrj 	  loops_state_set (flags & LOOPS_MAY_HAVE_MULTIPLE_LATCHES);
118*38fd1498Szrj 	  fix_loop_structure (NULL);
119*38fd1498Szrj 	}
120*38fd1498Szrj     }
121*38fd1498Szrj 
122*38fd1498Szrj   /* Apply flags to loops.  */
123*38fd1498Szrj   apply_loop_flags (flags);
124*38fd1498Szrj 
125*38fd1498Szrj   /* Dump loops.  */
126*38fd1498Szrj   flow_loops_dump (dump_file, NULL, 1);
127*38fd1498Szrj 
128*38fd1498Szrj   checking_verify_loop_structure ();
129*38fd1498Szrj 
130*38fd1498Szrj   timevar_pop (TV_LOOP_INIT);
131*38fd1498Szrj }
132*38fd1498Szrj 
133*38fd1498Szrj /* Finalize loop structures.  */
134*38fd1498Szrj 
135*38fd1498Szrj void
loop_optimizer_finalize(struct function * fn)136*38fd1498Szrj loop_optimizer_finalize (struct function *fn)
137*38fd1498Szrj {
138*38fd1498Szrj   struct loop *loop;
139*38fd1498Szrj   basic_block bb;
140*38fd1498Szrj 
141*38fd1498Szrj   timevar_push (TV_LOOP_FINI);
142*38fd1498Szrj 
143*38fd1498Szrj   if (loops_state_satisfies_p (fn, LOOPS_HAVE_RECORDED_EXITS))
144*38fd1498Szrj     release_recorded_exits (fn);
145*38fd1498Szrj 
146*38fd1498Szrj   free_numbers_of_iterations_estimates (fn);
147*38fd1498Szrj 
148*38fd1498Szrj   /* If we should preserve loop structure, do not free it but clear
149*38fd1498Szrj      flags that advanced properties are there as we are not preserving
150*38fd1498Szrj      that in full.  */
151*38fd1498Szrj   if (fn->curr_properties & PROP_loops)
152*38fd1498Szrj     {
153*38fd1498Szrj       loops_state_clear (fn, LOOP_CLOSED_SSA
154*38fd1498Szrj 			 | LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS
155*38fd1498Szrj 			 | LOOPS_HAVE_PREHEADERS
156*38fd1498Szrj 			 | LOOPS_HAVE_SIMPLE_LATCHES
157*38fd1498Szrj 			 | LOOPS_HAVE_FALLTHRU_PREHEADERS);
158*38fd1498Szrj       loops_state_set (fn, LOOPS_MAY_HAVE_MULTIPLE_LATCHES);
159*38fd1498Szrj       goto loop_fini_done;
160*38fd1498Szrj     }
161*38fd1498Szrj 
162*38fd1498Szrj   FOR_EACH_LOOP_FN (fn, loop, 0)
163*38fd1498Szrj     free_simple_loop_desc (loop);
164*38fd1498Szrj 
165*38fd1498Szrj   /* Clean up.  */
166*38fd1498Szrj   flow_loops_free (loops_for_fn (fn));
167*38fd1498Szrj   ggc_free (loops_for_fn (fn));
168*38fd1498Szrj   set_loops_for_fn (fn, NULL);
169*38fd1498Szrj 
170*38fd1498Szrj   FOR_ALL_BB_FN (bb, fn)
171*38fd1498Szrj     {
172*38fd1498Szrj       bb->loop_father = NULL;
173*38fd1498Szrj     }
174*38fd1498Szrj 
175*38fd1498Szrj loop_fini_done:
176*38fd1498Szrj   timevar_pop (TV_LOOP_FINI);
177*38fd1498Szrj }
178*38fd1498Szrj 
179*38fd1498Szrj /* The structure of loops might have changed.  Some loops might get removed
180*38fd1498Szrj    (and their headers and latches were set to NULL), loop exists might get
181*38fd1498Szrj    removed (thus the loop nesting may be wrong), and some blocks and edges
182*38fd1498Szrj    were changed (so the information about bb --> loop mapping does not have
183*38fd1498Szrj    to be correct).  But still for the remaining loops the header dominates
184*38fd1498Szrj    the latch, and loops did not get new subloops (new loops might possibly
185*38fd1498Szrj    get created, but we are not interested in them).  Fix up the mess.
186*38fd1498Szrj 
187*38fd1498Szrj    If CHANGED_BBS is not NULL, basic blocks whose loop depth has changed are
188*38fd1498Szrj    marked in it.
189*38fd1498Szrj 
190*38fd1498Szrj    Returns the number of new discovered loops.  */
191*38fd1498Szrj 
192*38fd1498Szrj unsigned
fix_loop_structure(bitmap changed_bbs)193*38fd1498Szrj fix_loop_structure (bitmap changed_bbs)
194*38fd1498Szrj {
195*38fd1498Szrj   basic_block bb;
196*38fd1498Szrj   int record_exits = 0;
197*38fd1498Szrj   struct loop *loop;
198*38fd1498Szrj   unsigned old_nloops, i;
199*38fd1498Szrj 
200*38fd1498Szrj   timevar_push (TV_LOOP_INIT);
201*38fd1498Szrj 
202*38fd1498Szrj   if (dump_file && (dump_flags & TDF_DETAILS))
203*38fd1498Szrj     fprintf (dump_file, "fix_loop_structure: fixing up loops for function\n");
204*38fd1498Szrj 
205*38fd1498Szrj   /* We need exact and fast dominance info to be available.  */
206*38fd1498Szrj   gcc_assert (dom_info_state (CDI_DOMINATORS) == DOM_OK);
207*38fd1498Szrj 
208*38fd1498Szrj   if (loops_state_satisfies_p (LOOPS_HAVE_RECORDED_EXITS))
209*38fd1498Szrj     {
210*38fd1498Szrj       release_recorded_exits (cfun);
211*38fd1498Szrj       record_exits = LOOPS_HAVE_RECORDED_EXITS;
212*38fd1498Szrj     }
213*38fd1498Szrj 
214*38fd1498Szrj   /* Remember the depth of the blocks in the loop hierarchy, so that we can
215*38fd1498Szrj      recognize blocks whose loop nesting relationship has changed.  */
216*38fd1498Szrj   if (changed_bbs)
217*38fd1498Szrj     FOR_EACH_BB_FN (bb, cfun)
218*38fd1498Szrj       bb->aux = (void *) (size_t) loop_depth (bb->loop_father);
219*38fd1498Szrj 
220*38fd1498Szrj   /* Remove the dead loops from structures.  We start from the innermost
221*38fd1498Szrj      loops, so that when we remove the loops, we know that the loops inside
222*38fd1498Szrj      are preserved, and do not waste time relinking loops that will be
223*38fd1498Szrj      removed later.  */
224*38fd1498Szrj   FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
225*38fd1498Szrj     {
226*38fd1498Szrj       /* Detect the case that the loop is no longer present even though
227*38fd1498Szrj          it wasn't marked for removal.
228*38fd1498Szrj 	 ???  If we do that we can get away with not marking loops for
229*38fd1498Szrj 	 removal at all.  And possibly avoid some spurious removals.  */
230*38fd1498Szrj       if (loop->header
231*38fd1498Szrj 	  && bb_loop_header_p (loop->header))
232*38fd1498Szrj 	continue;
233*38fd1498Szrj 
234*38fd1498Szrj       if (dump_file && (dump_flags & TDF_DETAILS))
235*38fd1498Szrj 	fprintf (dump_file, "fix_loop_structure: removing loop %d\n",
236*38fd1498Szrj 		 loop->num);
237*38fd1498Szrj 
238*38fd1498Szrj       while (loop->inner)
239*38fd1498Szrj 	{
240*38fd1498Szrj 	  struct loop *ploop = loop->inner;
241*38fd1498Szrj 	  flow_loop_tree_node_remove (ploop);
242*38fd1498Szrj 	  flow_loop_tree_node_add (loop_outer (loop), ploop);
243*38fd1498Szrj 	}
244*38fd1498Szrj 
245*38fd1498Szrj       /* Remove the loop.  */
246*38fd1498Szrj       if (loop->header)
247*38fd1498Szrj 	loop->former_header = loop->header;
248*38fd1498Szrj       else
249*38fd1498Szrj 	gcc_assert (loop->former_header != NULL);
250*38fd1498Szrj       loop->header = NULL;
251*38fd1498Szrj       flow_loop_tree_node_remove (loop);
252*38fd1498Szrj     }
253*38fd1498Szrj 
254*38fd1498Szrj   /* Remember the number of loops so we can return how many new loops
255*38fd1498Szrj      flow_loops_find discovered.  */
256*38fd1498Szrj   old_nloops = number_of_loops (cfun);
257*38fd1498Szrj 
258*38fd1498Szrj   /* Re-compute loop structure in-place.  */
259*38fd1498Szrj   flow_loops_find (current_loops);
260*38fd1498Szrj 
261*38fd1498Szrj   /* Mark the blocks whose loop has changed.  */
262*38fd1498Szrj   if (changed_bbs)
263*38fd1498Szrj     {
264*38fd1498Szrj       FOR_EACH_BB_FN (bb, cfun)
265*38fd1498Szrj 	{
266*38fd1498Szrj 	  if ((void *) (size_t) loop_depth (bb->loop_father) != bb->aux)
267*38fd1498Szrj 	    bitmap_set_bit (changed_bbs, bb->index);
268*38fd1498Szrj 
269*38fd1498Szrj     	  bb->aux = NULL;
270*38fd1498Szrj 	}
271*38fd1498Szrj     }
272*38fd1498Szrj 
273*38fd1498Szrj   /* Finally free deleted loops.  */
274*38fd1498Szrj   bool any_deleted = false;
275*38fd1498Szrj   FOR_EACH_VEC_ELT (*get_loops (cfun), i, loop)
276*38fd1498Szrj     if (loop && loop->header == NULL)
277*38fd1498Szrj       {
278*38fd1498Szrj 	if (dump_file
279*38fd1498Szrj 	    && ((unsigned) loop->former_header->index
280*38fd1498Szrj 		< basic_block_info_for_fn (cfun)->length ()))
281*38fd1498Szrj 	  {
282*38fd1498Szrj 	    basic_block former_header
283*38fd1498Szrj 	      = BASIC_BLOCK_FOR_FN (cfun, loop->former_header->index);
284*38fd1498Szrj 	    /* If the old header still exists we want to check if the
285*38fd1498Szrj 	       original loop is re-discovered or the old header is now
286*38fd1498Szrj 	       part of a newly discovered loop.
287*38fd1498Szrj 	       In both cases we should have avoided removing the loop.  */
288*38fd1498Szrj 	    if (former_header == loop->former_header)
289*38fd1498Szrj 	      {
290*38fd1498Szrj 		if (former_header->loop_father->header == former_header)
291*38fd1498Szrj 		  fprintf (dump_file, "fix_loop_structure: rediscovered "
292*38fd1498Szrj 			   "removed loop %d as loop %d with old header %d\n",
293*38fd1498Szrj 			   loop->num, former_header->loop_father->num,
294*38fd1498Szrj 			   former_header->index);
295*38fd1498Szrj 		else if ((unsigned) former_header->loop_father->num
296*38fd1498Szrj 			 >= old_nloops)
297*38fd1498Szrj 		  fprintf (dump_file, "fix_loop_structure: header %d of "
298*38fd1498Szrj 			   "removed loop %d is part of the newly "
299*38fd1498Szrj 			   "discovered loop %d with header %d\n",
300*38fd1498Szrj 			   former_header->index, loop->num,
301*38fd1498Szrj 			   former_header->loop_father->num,
302*38fd1498Szrj 			   former_header->loop_father->header->index);
303*38fd1498Szrj 	      }
304*38fd1498Szrj 	  }
305*38fd1498Szrj 	(*get_loops (cfun))[i] = NULL;
306*38fd1498Szrj 	flow_loop_free (loop);
307*38fd1498Szrj 	any_deleted = true;
308*38fd1498Szrj       }
309*38fd1498Szrj 
310*38fd1498Szrj   /* If we deleted loops then the cached scalar evolutions refering to
311*38fd1498Szrj      those loops become invalid.  */
312*38fd1498Szrj   if (any_deleted && scev_initialized_p ())
313*38fd1498Szrj     scev_reset_htab ();
314*38fd1498Szrj 
315*38fd1498Szrj   loops_state_clear (LOOPS_NEED_FIXUP);
316*38fd1498Szrj 
317*38fd1498Szrj   /* Apply flags to loops.  */
318*38fd1498Szrj   apply_loop_flags (current_loops->state | record_exits);
319*38fd1498Szrj 
320*38fd1498Szrj   checking_verify_loop_structure ();
321*38fd1498Szrj 
322*38fd1498Szrj   timevar_pop (TV_LOOP_INIT);
323*38fd1498Szrj 
324*38fd1498Szrj   return number_of_loops (cfun) - old_nloops;
325*38fd1498Szrj }
326*38fd1498Szrj 
327*38fd1498Szrj /* The RTL loop superpass.  The actual passes are subpasses.  See passes.c for
328*38fd1498Szrj    more on that.  */
329*38fd1498Szrj 
330*38fd1498Szrj namespace {
331*38fd1498Szrj 
332*38fd1498Szrj const pass_data pass_data_loop2 =
333*38fd1498Szrj {
334*38fd1498Szrj   RTL_PASS, /* type */
335*38fd1498Szrj   "loop2", /* name */
336*38fd1498Szrj   OPTGROUP_LOOP, /* optinfo_flags */
337*38fd1498Szrj   TV_LOOP, /* tv_id */
338*38fd1498Szrj   0, /* properties_required */
339*38fd1498Szrj   0, /* properties_provided */
340*38fd1498Szrj   0, /* properties_destroyed */
341*38fd1498Szrj   0, /* todo_flags_start */
342*38fd1498Szrj   0, /* todo_flags_finish */
343*38fd1498Szrj };
344*38fd1498Szrj 
345*38fd1498Szrj class pass_loop2 : public rtl_opt_pass
346*38fd1498Szrj {
347*38fd1498Szrj public:
pass_loop2(gcc::context * ctxt)348*38fd1498Szrj   pass_loop2 (gcc::context *ctxt)
349*38fd1498Szrj     : rtl_opt_pass (pass_data_loop2, ctxt)
350*38fd1498Szrj   {}
351*38fd1498Szrj 
352*38fd1498Szrj   /* opt_pass methods: */
353*38fd1498Szrj   virtual bool gate (function *);
354*38fd1498Szrj 
355*38fd1498Szrj }; // class pass_loop2
356*38fd1498Szrj 
357*38fd1498Szrj bool
gate(function * fun)358*38fd1498Szrj pass_loop2::gate (function *fun)
359*38fd1498Szrj {
360*38fd1498Szrj   if (optimize > 0
361*38fd1498Szrj       && (flag_move_loop_invariants
362*38fd1498Szrj 	  || flag_unswitch_loops
363*38fd1498Szrj 	  || flag_unroll_loops
364*38fd1498Szrj 	  || (flag_branch_on_count_reg && targetm.have_doloop_end ())
365*38fd1498Szrj 	  || cfun->has_unroll))
366*38fd1498Szrj     return true;
367*38fd1498Szrj   else
368*38fd1498Szrj     {
369*38fd1498Szrj       /* No longer preserve loops, remove them now.  */
370*38fd1498Szrj       fun->curr_properties &= ~PROP_loops;
371*38fd1498Szrj       if (current_loops)
372*38fd1498Szrj 	loop_optimizer_finalize ();
373*38fd1498Szrj       return false;
374*38fd1498Szrj     }
375*38fd1498Szrj }
376*38fd1498Szrj 
377*38fd1498Szrj } // anon namespace
378*38fd1498Szrj 
379*38fd1498Szrj rtl_opt_pass *
make_pass_loop2(gcc::context * ctxt)380*38fd1498Szrj make_pass_loop2 (gcc::context *ctxt)
381*38fd1498Szrj {
382*38fd1498Szrj   return new pass_loop2 (ctxt);
383*38fd1498Szrj }
384*38fd1498Szrj 
385*38fd1498Szrj 
386*38fd1498Szrj /* Initialization of the RTL loop passes.  */
387*38fd1498Szrj static unsigned int
rtl_loop_init(void)388*38fd1498Szrj rtl_loop_init (void)
389*38fd1498Szrj {
390*38fd1498Szrj   gcc_assert (current_ir_type () == IR_RTL_CFGLAYOUT);
391*38fd1498Szrj 
392*38fd1498Szrj   if (dump_file)
393*38fd1498Szrj     {
394*38fd1498Szrj       dump_reg_info (dump_file);
395*38fd1498Szrj       dump_flow_info (dump_file, dump_flags);
396*38fd1498Szrj     }
397*38fd1498Szrj 
398*38fd1498Szrj   loop_optimizer_init (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS);
399*38fd1498Szrj   return 0;
400*38fd1498Szrj }
401*38fd1498Szrj 
402*38fd1498Szrj namespace {
403*38fd1498Szrj 
404*38fd1498Szrj const pass_data pass_data_rtl_loop_init =
405*38fd1498Szrj {
406*38fd1498Szrj   RTL_PASS, /* type */
407*38fd1498Szrj   "loop2_init", /* name */
408*38fd1498Szrj   OPTGROUP_LOOP, /* optinfo_flags */
409*38fd1498Szrj   TV_LOOP, /* tv_id */
410*38fd1498Szrj   0, /* properties_required */
411*38fd1498Szrj   0, /* properties_provided */
412*38fd1498Szrj   0, /* properties_destroyed */
413*38fd1498Szrj   0, /* todo_flags_start */
414*38fd1498Szrj   0, /* todo_flags_finish */
415*38fd1498Szrj };
416*38fd1498Szrj 
417*38fd1498Szrj class pass_rtl_loop_init : public rtl_opt_pass
418*38fd1498Szrj {
419*38fd1498Szrj public:
pass_rtl_loop_init(gcc::context * ctxt)420*38fd1498Szrj   pass_rtl_loop_init (gcc::context *ctxt)
421*38fd1498Szrj     : rtl_opt_pass (pass_data_rtl_loop_init, ctxt)
422*38fd1498Szrj   {}
423*38fd1498Szrj 
424*38fd1498Szrj   /* opt_pass methods: */
execute(function *)425*38fd1498Szrj   virtual unsigned int execute (function *) { return rtl_loop_init (); }
426*38fd1498Szrj 
427*38fd1498Szrj }; // class pass_rtl_loop_init
428*38fd1498Szrj 
429*38fd1498Szrj } // anon namespace
430*38fd1498Szrj 
431*38fd1498Szrj rtl_opt_pass *
make_pass_rtl_loop_init(gcc::context * ctxt)432*38fd1498Szrj make_pass_rtl_loop_init (gcc::context *ctxt)
433*38fd1498Szrj {
434*38fd1498Szrj   return new pass_rtl_loop_init (ctxt);
435*38fd1498Szrj }
436*38fd1498Szrj 
437*38fd1498Szrj 
438*38fd1498Szrj /* Finalization of the RTL loop passes.  */
439*38fd1498Szrj 
440*38fd1498Szrj namespace {
441*38fd1498Szrj 
442*38fd1498Szrj const pass_data pass_data_rtl_loop_done =
443*38fd1498Szrj {
444*38fd1498Szrj   RTL_PASS, /* type */
445*38fd1498Szrj   "loop2_done", /* name */
446*38fd1498Szrj   OPTGROUP_LOOP, /* optinfo_flags */
447*38fd1498Szrj   TV_LOOP, /* tv_id */
448*38fd1498Szrj   0, /* properties_required */
449*38fd1498Szrj   0, /* properties_provided */
450*38fd1498Szrj   PROP_loops, /* properties_destroyed */
451*38fd1498Szrj   0, /* todo_flags_start */
452*38fd1498Szrj   0, /* todo_flags_finish */
453*38fd1498Szrj };
454*38fd1498Szrj 
455*38fd1498Szrj class pass_rtl_loop_done : public rtl_opt_pass
456*38fd1498Szrj {
457*38fd1498Szrj public:
pass_rtl_loop_done(gcc::context * ctxt)458*38fd1498Szrj   pass_rtl_loop_done (gcc::context *ctxt)
459*38fd1498Szrj     : rtl_opt_pass (pass_data_rtl_loop_done, ctxt)
460*38fd1498Szrj   {}
461*38fd1498Szrj 
462*38fd1498Szrj   /* opt_pass methods: */
463*38fd1498Szrj   virtual unsigned int execute (function *);
464*38fd1498Szrj 
465*38fd1498Szrj }; // class pass_rtl_loop_done
466*38fd1498Szrj 
467*38fd1498Szrj unsigned int
execute(function * fun)468*38fd1498Szrj pass_rtl_loop_done::execute (function *fun)
469*38fd1498Szrj {
470*38fd1498Szrj   /* No longer preserve loops, remove them now.  */
471*38fd1498Szrj   fun->curr_properties &= ~PROP_loops;
472*38fd1498Szrj   loop_optimizer_finalize ();
473*38fd1498Szrj   free_dominance_info (CDI_DOMINATORS);
474*38fd1498Szrj 
475*38fd1498Szrj   cleanup_cfg (0);
476*38fd1498Szrj   if (dump_file)
477*38fd1498Szrj     {
478*38fd1498Szrj       dump_reg_info (dump_file);
479*38fd1498Szrj       dump_flow_info (dump_file, dump_flags);
480*38fd1498Szrj     }
481*38fd1498Szrj 
482*38fd1498Szrj   return 0;
483*38fd1498Szrj }
484*38fd1498Szrj 
485*38fd1498Szrj } // anon namespace
486*38fd1498Szrj 
487*38fd1498Szrj rtl_opt_pass *
make_pass_rtl_loop_done(gcc::context * ctxt)488*38fd1498Szrj make_pass_rtl_loop_done (gcc::context *ctxt)
489*38fd1498Szrj {
490*38fd1498Szrj   return new pass_rtl_loop_done (ctxt);
491*38fd1498Szrj }
492*38fd1498Szrj 
493*38fd1498Szrj 
494*38fd1498Szrj /* Loop invariant code motion.  */
495*38fd1498Szrj 
496*38fd1498Szrj namespace {
497*38fd1498Szrj 
498*38fd1498Szrj const pass_data pass_data_rtl_move_loop_invariants =
499*38fd1498Szrj {
500*38fd1498Szrj   RTL_PASS, /* type */
501*38fd1498Szrj   "loop2_invariant", /* name */
502*38fd1498Szrj   OPTGROUP_LOOP, /* optinfo_flags */
503*38fd1498Szrj   TV_LOOP_MOVE_INVARIANTS, /* tv_id */
504*38fd1498Szrj   0, /* properties_required */
505*38fd1498Szrj   0, /* properties_provided */
506*38fd1498Szrj   0, /* properties_destroyed */
507*38fd1498Szrj   0, /* todo_flags_start */
508*38fd1498Szrj   ( TODO_df_verify | TODO_df_finish ), /* todo_flags_finish */
509*38fd1498Szrj };
510*38fd1498Szrj 
511*38fd1498Szrj class pass_rtl_move_loop_invariants : public rtl_opt_pass
512*38fd1498Szrj {
513*38fd1498Szrj public:
pass_rtl_move_loop_invariants(gcc::context * ctxt)514*38fd1498Szrj   pass_rtl_move_loop_invariants (gcc::context *ctxt)
515*38fd1498Szrj     : rtl_opt_pass (pass_data_rtl_move_loop_invariants, ctxt)
516*38fd1498Szrj   {}
517*38fd1498Szrj 
518*38fd1498Szrj   /* opt_pass methods: */
gate(function *)519*38fd1498Szrj   virtual bool gate (function *) { return flag_move_loop_invariants; }
execute(function * fun)520*38fd1498Szrj   virtual unsigned int execute (function *fun)
521*38fd1498Szrj     {
522*38fd1498Szrj       if (number_of_loops (fun) > 1)
523*38fd1498Szrj 	move_loop_invariants ();
524*38fd1498Szrj       return 0;
525*38fd1498Szrj     }
526*38fd1498Szrj 
527*38fd1498Szrj }; // class pass_rtl_move_loop_invariants
528*38fd1498Szrj 
529*38fd1498Szrj } // anon namespace
530*38fd1498Szrj 
531*38fd1498Szrj rtl_opt_pass *
make_pass_rtl_move_loop_invariants(gcc::context * ctxt)532*38fd1498Szrj make_pass_rtl_move_loop_invariants (gcc::context *ctxt)
533*38fd1498Szrj {
534*38fd1498Szrj   return new pass_rtl_move_loop_invariants (ctxt);
535*38fd1498Szrj }
536*38fd1498Szrj 
537*38fd1498Szrj 
538*38fd1498Szrj namespace {
539*38fd1498Szrj 
540*38fd1498Szrj const pass_data pass_data_rtl_unroll_loops =
541*38fd1498Szrj {
542*38fd1498Szrj   RTL_PASS, /* type */
543*38fd1498Szrj   "loop2_unroll", /* name */
544*38fd1498Szrj   OPTGROUP_LOOP, /* optinfo_flags */
545*38fd1498Szrj   TV_LOOP_UNROLL, /* tv_id */
546*38fd1498Szrj   0, /* properties_required */
547*38fd1498Szrj   0, /* properties_provided */
548*38fd1498Szrj   0, /* properties_destroyed */
549*38fd1498Szrj   0, /* todo_flags_start */
550*38fd1498Szrj   0, /* todo_flags_finish */
551*38fd1498Szrj };
552*38fd1498Szrj 
553*38fd1498Szrj class pass_rtl_unroll_loops : public rtl_opt_pass
554*38fd1498Szrj {
555*38fd1498Szrj public:
pass_rtl_unroll_loops(gcc::context * ctxt)556*38fd1498Szrj   pass_rtl_unroll_loops (gcc::context *ctxt)
557*38fd1498Szrj     : rtl_opt_pass (pass_data_rtl_unroll_loops, ctxt)
558*38fd1498Szrj   {}
559*38fd1498Szrj 
560*38fd1498Szrj   /* opt_pass methods: */
gate(function *)561*38fd1498Szrj   virtual bool gate (function *)
562*38fd1498Szrj     {
563*38fd1498Szrj       return (flag_unroll_loops || flag_unroll_all_loops || cfun->has_unroll);
564*38fd1498Szrj     }
565*38fd1498Szrj 
566*38fd1498Szrj   virtual unsigned int execute (function *);
567*38fd1498Szrj 
568*38fd1498Szrj }; // class pass_rtl_unroll_loops
569*38fd1498Szrj 
570*38fd1498Szrj unsigned int
execute(function * fun)571*38fd1498Szrj pass_rtl_unroll_loops::execute (function *fun)
572*38fd1498Szrj {
573*38fd1498Szrj   if (number_of_loops (fun) > 1)
574*38fd1498Szrj     {
575*38fd1498Szrj       int flags = 0;
576*38fd1498Szrj       if (dump_file)
577*38fd1498Szrj 	df_dump (dump_file);
578*38fd1498Szrj 
579*38fd1498Szrj       if (flag_unroll_loops)
580*38fd1498Szrj 	flags |= UAP_UNROLL;
581*38fd1498Szrj       if (flag_unroll_all_loops)
582*38fd1498Szrj 	flags |= UAP_UNROLL_ALL;
583*38fd1498Szrj 
584*38fd1498Szrj       unroll_loops (flags);
585*38fd1498Szrj     }
586*38fd1498Szrj   return 0;
587*38fd1498Szrj }
588*38fd1498Szrj 
589*38fd1498Szrj } // anon namespace
590*38fd1498Szrj 
591*38fd1498Szrj rtl_opt_pass *
make_pass_rtl_unroll_loops(gcc::context * ctxt)592*38fd1498Szrj make_pass_rtl_unroll_loops (gcc::context *ctxt)
593*38fd1498Szrj {
594*38fd1498Szrj   return new pass_rtl_unroll_loops (ctxt);
595*38fd1498Szrj }
596*38fd1498Szrj 
597*38fd1498Szrj 
598*38fd1498Szrj namespace {
599*38fd1498Szrj 
600*38fd1498Szrj const pass_data pass_data_rtl_doloop =
601*38fd1498Szrj {
602*38fd1498Szrj   RTL_PASS, /* type */
603*38fd1498Szrj   "loop2_doloop", /* name */
604*38fd1498Szrj   OPTGROUP_LOOP, /* optinfo_flags */
605*38fd1498Szrj   TV_LOOP_DOLOOP, /* tv_id */
606*38fd1498Szrj   0, /* properties_required */
607*38fd1498Szrj   0, /* properties_provided */
608*38fd1498Szrj   0, /* properties_destroyed */
609*38fd1498Szrj   0, /* todo_flags_start */
610*38fd1498Szrj   0, /* todo_flags_finish */
611*38fd1498Szrj };
612*38fd1498Szrj 
613*38fd1498Szrj class pass_rtl_doloop : public rtl_opt_pass
614*38fd1498Szrj {
615*38fd1498Szrj public:
pass_rtl_doloop(gcc::context * ctxt)616*38fd1498Szrj   pass_rtl_doloop (gcc::context *ctxt)
617*38fd1498Szrj     : rtl_opt_pass (pass_data_rtl_doloop, ctxt)
618*38fd1498Szrj   {}
619*38fd1498Szrj 
620*38fd1498Szrj   /* opt_pass methods: */
621*38fd1498Szrj   virtual bool gate (function *);
622*38fd1498Szrj   virtual unsigned int execute (function *);
623*38fd1498Szrj 
624*38fd1498Szrj }; // class pass_rtl_doloop
625*38fd1498Szrj 
626*38fd1498Szrj bool
gate(function *)627*38fd1498Szrj pass_rtl_doloop::gate (function *)
628*38fd1498Szrj {
629*38fd1498Szrj   return (flag_branch_on_count_reg && targetm.have_doloop_end ());
630*38fd1498Szrj }
631*38fd1498Szrj 
632*38fd1498Szrj unsigned int
execute(function * fun)633*38fd1498Szrj pass_rtl_doloop::execute (function *fun)
634*38fd1498Szrj {
635*38fd1498Szrj   if (number_of_loops (fun) > 1)
636*38fd1498Szrj     doloop_optimize_loops ();
637*38fd1498Szrj   return 0;
638*38fd1498Szrj }
639*38fd1498Szrj 
640*38fd1498Szrj } // anon namespace
641*38fd1498Szrj 
642*38fd1498Szrj rtl_opt_pass *
make_pass_rtl_doloop(gcc::context * ctxt)643*38fd1498Szrj make_pass_rtl_doloop (gcc::context *ctxt)
644*38fd1498Szrj {
645*38fd1498Szrj   return new pass_rtl_doloop (ctxt);
646*38fd1498Szrj }
647