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