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