1 /* SSA Jump Threading 2 Copyright (C) 2005-2017 Free Software Foundation, Inc. 3 4 This file is part of GCC. 5 6 GCC is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3, or (at your option) 9 any later version. 10 11 GCC is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GCC; see the file COPYING3. If not see 18 <http://www.gnu.org/licenses/>. */ 19 20 #include "config.h" 21 #include "system.h" 22 #include "coretypes.h" 23 #include "backend.h" 24 #include "predict.h" 25 #include "tree.h" 26 #include "gimple.h" 27 #include "fold-const.h" 28 #include "cfgloop.h" 29 #include "gimple-iterator.h" 30 #include "tree-cfg.h" 31 #include "tree-ssa-threadupdate.h" 32 #include "params.h" 33 #include "tree-ssa-loop.h" 34 #include "cfganal.h" 35 #include "tree-pass.h" 36 #include "gimple-ssa.h" 37 #include "tree-phinodes.h" 38 #include "tree-inline.h" 39 #include "tree-vectorizer.h" 40 41 static int max_threaded_paths; 42 43 /* Simple helper to get the last statement from BB, which is assumed 44 to be a control statement. Return NULL if the last statement is 45 not a control statement. */ 46 47 static gimple * 48 get_gimple_control_stmt (basic_block bb) 49 { 50 gimple_stmt_iterator gsi = gsi_last_nondebug_bb (bb); 51 52 if (gsi_end_p (gsi)) 53 return NULL; 54 55 gimple *stmt = gsi_stmt (gsi); 56 enum gimple_code code = gimple_code (stmt); 57 if (code == GIMPLE_COND || code == GIMPLE_SWITCH || code == GIMPLE_GOTO) 58 return stmt; 59 return NULL; 60 } 61 62 /* Return true if the CFG contains at least one path from START_BB to END_BB. 63 When a path is found, record in PATH the blocks from END_BB to START_BB. 64 VISITED_BBS is used to make sure we don't fall into an infinite loop. Bound 65 the recursion to basic blocks belonging to LOOP. */ 66 67 static bool 68 fsm_find_thread_path (basic_block start_bb, basic_block end_bb, 69 vec<basic_block, va_gc> *&path, 70 hash_set<basic_block> *visited_bbs, loop_p loop) 71 { 72 if (loop != start_bb->loop_father) 73 return false; 74 75 if (start_bb == end_bb) 76 { 77 vec_safe_push (path, start_bb); 78 return true; 79 } 80 81 if (!visited_bbs->add (start_bb)) 82 { 83 edge e; 84 edge_iterator ei; 85 FOR_EACH_EDGE (e, ei, start_bb->succs) 86 if (fsm_find_thread_path (e->dest, end_bb, path, visited_bbs, loop)) 87 { 88 vec_safe_push (path, start_bb); 89 return true; 90 } 91 } 92 93 return false; 94 } 95 96 /* Examine jump threading path PATH to which we want to add BBI. 97 98 If the resulting path is profitable to thread, then return the 99 final taken edge from the path, NULL otherwise. 100 101 NAME is the SSA_NAME of the variable we found to have a constant 102 value on PATH. ARG is the value of that SSA_NAME. 103 104 BBI will be appended to PATH when we have a profitable jump threading 105 path. Callers are responsible for removing BBI from PATH in that case. 106 107 SPEED_P indicate that we could increase code size to improve the code path */ 108 109 static edge 110 profitable_jump_thread_path (vec<basic_block, va_gc> *&path, 111 basic_block bbi, tree name, tree arg, bool speed_p, 112 bool *creates_irreducible_loop) 113 { 114 /* Note BBI is not in the path yet, hence the +1 in the test below 115 to make sure BBI is accounted for in the path length test. */ 116 int path_length = path->length (); 117 118 /* We can get a length of 0 here when the statement that 119 makes a conditional generate a compile-time constant 120 result is in the same block as the conditional. 121 122 That's not really a jump threading opportunity, but instead is 123 simple cprop & simplification. We could handle it here if we 124 wanted by wiring up all the incoming edges. If we run this 125 early in IPA, that might be worth doing. For now we just 126 reject that case. */ 127 if (path_length == 0) 128 return NULL; 129 130 if (path_length + 1 > PARAM_VALUE (PARAM_MAX_FSM_THREAD_LENGTH)) 131 { 132 if (dump_file && (dump_flags & TDF_DETAILS)) 133 fprintf (dump_file, "FSM jump-thread path not considered: " 134 "the number of basic blocks on the path " 135 "exceeds PARAM_MAX_FSM_THREAD_LENGTH.\n"); 136 return NULL; 137 } 138 139 if (max_threaded_paths <= 0) 140 { 141 if (dump_file && (dump_flags & TDF_DETAILS)) 142 fprintf (dump_file, "FSM jump-thread path not considered: " 143 "the number of previously recorded FSM paths to " 144 "thread exceeds PARAM_MAX_FSM_THREAD_PATHS.\n"); 145 return NULL; 146 } 147 148 /* Add BBI to the path. 149 From this point onward, if we decide we the path is not profitable 150 to thread, we must remove BBI from the path. */ 151 vec_safe_push (path, bbi); 152 ++path_length; 153 154 int n_insns = 0; 155 gimple_stmt_iterator gsi; 156 int j; 157 loop_p loop = (*path)[0]->loop_father; 158 bool path_crosses_loops = false; 159 bool threaded_through_latch = false; 160 bool multiway_branch_in_path = false; 161 bool threaded_multiway_branch = false; 162 bool contains_hot_bb = false; 163 164 if (dump_file && (dump_flags & TDF_DETAILS)) 165 fprintf (dump_file, "Checking profitability of path (backwards): "); 166 167 /* Count the number of instructions on the path: as these instructions 168 will have to be duplicated, we will not record the path if there 169 are too many instructions on the path. Also check that all the 170 blocks in the path belong to a single loop. */ 171 for (j = 0; j < path_length; j++) 172 { 173 basic_block bb = (*path)[j]; 174 175 if (dump_file && (dump_flags & TDF_DETAILS)) 176 fprintf (dump_file, " bb:%i", bb->index); 177 /* Remember, blocks in the path are stored in opposite order 178 in the PATH array. The last entry in the array represents 179 the block with an outgoing edge that we will redirect to the 180 jump threading path. Thus we don't care about that block's 181 loop father, nor how many statements are in that block because 182 it will not be copied or whether or not it ends in a multiway 183 branch. */ 184 if (j < path_length - 1) 185 { 186 int orig_n_insns = n_insns; 187 if (bb->loop_father != loop) 188 { 189 path_crosses_loops = true; 190 break; 191 } 192 193 /* PHIs in the path will create degenerate PHIS in the 194 copied path which will then get propagated away, so 195 looking at just the duplicate path the PHIs would 196 seem unimportant. 197 198 But those PHIs, because they're assignments to objects 199 typically with lives that exist outside the thread path, 200 will tend to generate PHIs (or at least new PHI arguments) 201 at points where we leave the thread path and rejoin 202 the original blocks. So we do want to account for them. 203 204 We ignore virtual PHIs. We also ignore cases where BB 205 has a single incoming edge. That's the most common 206 degenerate PHI we'll see here. Finally we ignore PHIs 207 that are associated with the value we're tracking as 208 that object likely dies. */ 209 if (EDGE_COUNT (bb->succs) > 1 && EDGE_COUNT (bb->preds) > 1) 210 { 211 for (gphi_iterator gsip = gsi_start_phis (bb); 212 !gsi_end_p (gsip); 213 gsi_next (&gsip)) 214 { 215 gphi *phi = gsip.phi (); 216 tree dst = gimple_phi_result (phi); 217 218 /* Note that if both NAME and DST are anonymous 219 SSA_NAMEs, then we do not have enough information 220 to consider them associated. */ 221 if (dst != name 222 && (SSA_NAME_VAR (dst) != SSA_NAME_VAR (name) 223 || !SSA_NAME_VAR (dst)) 224 && !virtual_operand_p (dst)) 225 ++n_insns; 226 } 227 } 228 229 if (!contains_hot_bb && speed_p) 230 contains_hot_bb |= optimize_bb_for_speed_p (bb); 231 for (gsi = gsi_after_labels (bb); 232 !gsi_end_p (gsi); 233 gsi_next_nondebug (&gsi)) 234 { 235 gimple *stmt = gsi_stmt (gsi); 236 /* Do not count empty statements and labels. */ 237 if (gimple_code (stmt) != GIMPLE_NOP 238 && !(gimple_code (stmt) == GIMPLE_ASSIGN 239 && gimple_assign_rhs_code (stmt) == ASSERT_EXPR) 240 && !is_gimple_debug (stmt)) 241 n_insns += estimate_num_insns (stmt, &eni_size_weights); 242 } 243 if (dump_file && (dump_flags & TDF_DETAILS)) 244 fprintf (dump_file, " (%i insns)", n_insns-orig_n_insns); 245 246 /* We do not look at the block with the threaded branch 247 in this loop. So if any block with a last statement that 248 is a GIMPLE_SWITCH or GIMPLE_GOTO is seen, then we have a 249 multiway branch on our path. 250 251 The block in PATH[0] is special, it's the block were we're 252 going to be able to eliminate its branch. */ 253 gimple *last = last_stmt (bb); 254 if (last && (gimple_code (last) == GIMPLE_SWITCH 255 || gimple_code (last) == GIMPLE_GOTO)) 256 { 257 if (j == 0) 258 threaded_multiway_branch = true; 259 else 260 multiway_branch_in_path = true; 261 } 262 } 263 264 /* Note if we thread through the latch, we will want to include 265 the last entry in the array when determining if we thread 266 through the loop latch. */ 267 if (loop->latch == bb) 268 threaded_through_latch = true; 269 } 270 271 gimple *stmt = get_gimple_control_stmt ((*path)[0]); 272 gcc_assert (stmt); 273 274 /* We are going to remove the control statement at the end of the 275 last block in the threading path. So don't count it against our 276 statement count. */ 277 278 int stmt_insns = estimate_num_insns (stmt, &eni_size_weights); 279 n_insns-= stmt_insns; 280 281 if (dump_file && (dump_flags & TDF_DETAILS)) 282 fprintf (dump_file, "\n Control statement insns: %i\n" 283 " Overall: %i insns\n", 284 stmt_insns, n_insns); 285 286 /* We have found a constant value for ARG. For GIMPLE_SWITCH 287 and GIMPLE_GOTO, we use it as-is. However, for a GIMPLE_COND 288 we need to substitute, fold and simplify so we can determine 289 the edge taken out of the last block. */ 290 if (gimple_code (stmt) == GIMPLE_COND) 291 { 292 enum tree_code cond_code = gimple_cond_code (stmt); 293 294 /* We know the underyling format of the condition. */ 295 arg = fold_binary (cond_code, boolean_type_node, 296 arg, gimple_cond_rhs (stmt)); 297 } 298 299 /* If this path threaded through the loop latch back into the 300 same loop and the destination does not dominate the loop 301 latch, then this thread would create an irreducible loop. 302 303 We have to know the outgoing edge to figure this out. */ 304 edge taken_edge = find_taken_edge ((*path)[0], arg); 305 306 /* There are cases where we may not be able to extract the 307 taken edge. For example, a computed goto to an absolute 308 address. Handle those cases gracefully. */ 309 if (taken_edge == NULL) 310 { 311 path->pop (); 312 return NULL; 313 } 314 315 *creates_irreducible_loop = false; 316 if (threaded_through_latch 317 && loop == taken_edge->dest->loop_father 318 && (determine_bb_domination_status (loop, taken_edge->dest) 319 == DOMST_NONDOMINATING)) 320 *creates_irreducible_loop = true; 321 322 if (path_crosses_loops) 323 { 324 if (dump_file && (dump_flags & TDF_DETAILS)) 325 fprintf (dump_file, "FSM jump-thread path not considered: " 326 "the path crosses loops.\n"); 327 path->pop (); 328 return NULL; 329 } 330 331 /* Threading is profitable if the path duplicated is hot but also 332 in a case we separate cold path from hot path and permit optimization 333 of the hot path later. Be on the agressive side here. In some testcases, 334 as in PR 78407 this leads to noticeable improvements. */ 335 if (speed_p && (optimize_edge_for_speed_p (taken_edge) || contains_hot_bb)) 336 { 337 if (n_insns >= PARAM_VALUE (PARAM_MAX_FSM_THREAD_PATH_INSNS)) 338 { 339 if (dump_file && (dump_flags & TDF_DETAILS)) 340 fprintf (dump_file, "FSM jump-thread path not considered: " 341 "the number of instructions on the path " 342 "exceeds PARAM_MAX_FSM_THREAD_PATH_INSNS.\n"); 343 path->pop (); 344 return NULL; 345 } 346 } 347 else if (n_insns > 1) 348 { 349 if (dump_file && (dump_flags & TDF_DETAILS)) 350 fprintf (dump_file, "FSM jump-thread path not considered: " 351 "duplication of %i insns is needed and optimizing for size.\n", 352 n_insns); 353 path->pop (); 354 return NULL; 355 } 356 357 /* We avoid creating irreducible inner loops unless we thread through 358 a multiway branch, in which case we have deemed it worth losing 359 other loop optimizations later. 360 361 We also consider it worth creating an irreducible inner loop if 362 the number of copied statement is low relative to the length of 363 the path -- in that case there's little the traditional loop 364 optimizer would have done anyway, so an irreducible loop is not 365 so bad. */ 366 if (!threaded_multiway_branch && *creates_irreducible_loop 367 && (n_insns * PARAM_VALUE (PARAM_FSM_SCALE_PATH_STMTS) 368 > path_length * PARAM_VALUE (PARAM_FSM_SCALE_PATH_BLOCKS))) 369 370 { 371 if (dump_file && (dump_flags & TDF_DETAILS)) 372 fprintf (dump_file, 373 "FSM would create irreducible loop without threading " 374 "multiway branch.\n"); 375 path->pop (); 376 return NULL; 377 } 378 379 380 /* If this path does not thread through the loop latch, then we are 381 using the FSM threader to find old style jump threads. This 382 is good, except the FSM threader does not re-use an existing 383 threading path to reduce code duplication. 384 385 So for that case, drastically reduce the number of statements 386 we are allowed to copy. */ 387 if (!(threaded_through_latch && threaded_multiway_branch) 388 && (n_insns * PARAM_VALUE (PARAM_FSM_SCALE_PATH_STMTS) 389 >= PARAM_VALUE (PARAM_MAX_JUMP_THREAD_DUPLICATION_STMTS))) 390 { 391 if (dump_file && (dump_flags & TDF_DETAILS)) 392 fprintf (dump_file, 393 "FSM did not thread around loop and would copy too " 394 "many statements.\n"); 395 path->pop (); 396 return NULL; 397 } 398 399 /* When there is a multi-way branch on the path, then threading can 400 explode the CFG due to duplicating the edges for that multi-way 401 branch. So like above, only allow a multi-way branch on the path 402 if we actually thread a multi-way branch. */ 403 if (!threaded_multiway_branch && multiway_branch_in_path) 404 { 405 if (dump_file && (dump_flags & TDF_DETAILS)) 406 fprintf (dump_file, 407 "FSM Thread through multiway branch without threading " 408 "a multiway branch.\n"); 409 path->pop (); 410 return NULL; 411 } 412 return taken_edge; 413 } 414 415 /* PATH is vector of blocks forming a jump threading path in reverse 416 order. TAKEN_EDGE is the edge taken from path[0]. 417 418 Convert that path into the form used by register_jump_thread and 419 register the path. */ 420 421 static void 422 convert_and_register_jump_thread_path (vec<basic_block, va_gc> *path, 423 edge taken_edge) 424 { 425 vec<jump_thread_edge *> *jump_thread_path = new vec<jump_thread_edge *> (); 426 427 /* Record the edges between the blocks in PATH. */ 428 for (unsigned int j = 0; j < path->length () - 1; j++) 429 { 430 basic_block bb1 = (*path)[path->length () - j - 1]; 431 basic_block bb2 = (*path)[path->length () - j - 2]; 432 433 edge e = find_edge (bb1, bb2); 434 gcc_assert (e); 435 jump_thread_edge *x = new jump_thread_edge (e, EDGE_FSM_THREAD); 436 jump_thread_path->safe_push (x); 437 } 438 439 /* Add the edge taken when the control variable has value ARG. */ 440 jump_thread_edge *x 441 = new jump_thread_edge (taken_edge, EDGE_NO_COPY_SRC_BLOCK); 442 jump_thread_path->safe_push (x); 443 444 register_jump_thread (jump_thread_path); 445 --max_threaded_paths; 446 } 447 448 /* While following a chain of SSA_NAME definitions, we jumped from a definition 449 in LAST_BB to a definition in VAR_BB (walking backwards). 450 451 Verify there is a single path between the blocks and none of the blocks 452 in the path is already in VISITED_BBS. If so, then update VISISTED_BBS, 453 add the new blocks to PATH and return TRUE. Otherwise return FALSE. 454 455 Store the length of the subpath in NEXT_PATH_LENGTH. */ 456 457 static bool 458 check_subpath_and_update_thread_path (basic_block last_bb, basic_block new_bb, 459 hash_set<basic_block> *visited_bbs, 460 vec<basic_block, va_gc> *&path, 461 int *next_path_length) 462 { 463 edge e; 464 int e_count = 0; 465 edge_iterator ei; 466 vec<basic_block, va_gc> *next_path; 467 vec_alloc (next_path, 10); 468 469 FOR_EACH_EDGE (e, ei, last_bb->preds) 470 { 471 hash_set<basic_block> *visited_bbs = new hash_set<basic_block>; 472 473 if (fsm_find_thread_path (new_bb, e->src, next_path, visited_bbs, 474 e->src->loop_father)) 475 ++e_count; 476 477 delete visited_bbs; 478 479 /* If there is more than one path, stop. */ 480 if (e_count > 1) 481 { 482 vec_free (next_path); 483 return false; 484 } 485 } 486 487 /* Stop if we have not found a path: this could occur when the recursion 488 is stopped by one of the bounds. */ 489 if (e_count == 0) 490 { 491 vec_free (next_path); 492 return false; 493 } 494 495 /* Make sure we haven't already visited any of the nodes in 496 NEXT_PATH. Don't add them here to avoid pollution. */ 497 for (unsigned int i = 0; i < next_path->length () - 1; i++) 498 { 499 if (visited_bbs->contains ((*next_path)[i])) 500 { 501 vec_free (next_path); 502 return false; 503 } 504 } 505 506 /* Now add the nodes to VISISTED_BBS. */ 507 for (unsigned int i = 0; i < next_path->length () - 1; i++) 508 visited_bbs->add ((*next_path)[i]); 509 510 /* Append all the nodes from NEXT_PATH to PATH. */ 511 vec_safe_splice (path, next_path); 512 *next_path_length = next_path->length (); 513 vec_free (next_path); 514 515 return true; 516 } 517 518 static void fsm_find_control_statement_thread_paths (tree, 519 hash_set<basic_block> *, 520 vec<basic_block, va_gc> *&, 521 bool, bool); 522 523 /* Given PHI which defines NAME in block VAR_BB, recurse through the 524 PHI's arguments searching for paths where NAME will ultimately have 525 a constant value. 526 527 VISITED_BBS tracks the blocks that have been encountered. 528 529 PATH contains the series of blocks to traverse that will result in 530 NAME having a constant value. 531 532 SEEN_LOOP_PHI tracks if we have recursed through a loop PHI node. 533 534 SPEED_P indicates if we are optimizing for speed over space. */ 535 536 static void 537 handle_phi (gphi *phi, tree name, basic_block var_bb, 538 hash_set<basic_block> *visited_bbs, 539 vec<basic_block, va_gc> *&path, 540 bool seen_loop_phi, bool speed_p) 541 { 542 /* Iterate over the arguments of PHI. */ 543 for (unsigned int i = 0; i < gimple_phi_num_args (phi); i++) 544 { 545 tree arg = gimple_phi_arg_def (phi, i); 546 basic_block bbi = gimple_phi_arg_edge (phi, i)->src; 547 548 /* Skip edges pointing outside the current loop. */ 549 if (!arg || var_bb->loop_father != bbi->loop_father) 550 continue; 551 552 if (TREE_CODE (arg) == SSA_NAME) 553 { 554 vec_safe_push (path, bbi); 555 /* Recursively follow SSA_NAMEs looking for a constant 556 definition. */ 557 fsm_find_control_statement_thread_paths (arg, visited_bbs, path, 558 seen_loop_phi, speed_p); 559 560 path->pop (); 561 continue; 562 } 563 564 if (TREE_CODE_CLASS (TREE_CODE (arg)) != tcc_constant) 565 continue; 566 567 /* If this is a profitable jump thread path, then convert it 568 into the canonical form and register it. */ 569 bool irreducible = false; 570 edge taken_edge = profitable_jump_thread_path (path, bbi, name, arg, 571 speed_p, &irreducible); 572 if (taken_edge) 573 { 574 convert_and_register_jump_thread_path (path, taken_edge); 575 path->pop (); 576 577 if (irreducible) 578 vect_free_loop_info_assumptions ((*path)[0]->loop_father); 579 } 580 } 581 } 582 583 /* Return TRUE if STMT is a gimple assignment we want to either directly 584 handle or recurse through. Return FALSE otherwise. 585 586 Note that adding more cases here requires adding cases to handle_assignment 587 below. */ 588 589 static bool 590 handle_assignment_p (gimple *stmt) 591 { 592 if (is_gimple_assign (stmt)) 593 { 594 enum tree_code def_code = gimple_assign_rhs_code (stmt); 595 596 /* If the RHS is an SSA_NAME, then we will recurse through it. 597 Go ahead and filter out cases where the SSA_NAME is a default 598 definition. There's little to be gained by trying to handle that. */ 599 if (def_code == SSA_NAME 600 && !SSA_NAME_IS_DEFAULT_DEF (gimple_assign_rhs1 (stmt))) 601 return true; 602 603 /* If the RHS is a constant, then it's a terminal that we'll want 604 to handle as well. */ 605 if (TREE_CODE_CLASS (def_code) == tcc_constant) 606 return true; 607 } 608 609 /* Anything not explicitly allowed is not handled. */ 610 return false; 611 } 612 613 /* Given STMT which defines NAME in block VAR_BB, recurse through the 614 PHI's arguments searching for paths where NAME will ultimately have 615 a constant value. 616 617 VISITED_BBS tracks the blocks that have been encountered. 618 619 PATH contains the series of blocks to traverse that will result in 620 NAME having a constant value. 621 622 SEEN_LOOP_PHI tracks if we have recursed through a loop PHI node. 623 624 SPEED_P indicates if we are optimizing for speed over space. */ 625 626 static void 627 handle_assignment (gimple *stmt, tree name, basic_block var_bb, 628 hash_set<basic_block> *visited_bbs, 629 vec<basic_block, va_gc> *&path, 630 bool seen_loop_phi, bool speed_p) 631 { 632 tree arg = gimple_assign_rhs1 (stmt); 633 634 if (TREE_CODE (arg) == SSA_NAME) 635 fsm_find_control_statement_thread_paths (arg, visited_bbs, 636 path, seen_loop_phi, speed_p); 637 638 else 639 { 640 /* profitable_jump_thread_path is going to push the current 641 block onto the path. But the path will always have the current 642 block at this point. So we can just pop it. */ 643 path->pop (); 644 645 bool irreducible = false; 646 edge taken_edge = profitable_jump_thread_path (path, var_bb, 647 name, arg, speed_p, 648 &irreducible); 649 if (taken_edge) 650 { 651 convert_and_register_jump_thread_path (path, taken_edge); 652 path->pop (); 653 654 if (irreducible) 655 vect_free_loop_info_assumptions ((*path)[0]->loop_father); 656 } 657 658 /* And put the current block back onto the path so that the 659 state of the stack is unchanged when we leave. */ 660 vec_safe_push (path, var_bb); 661 } 662 } 663 664 /* We trace the value of the SSA_NAME NAME back through any phi nodes looking 665 for places where it gets a constant value and save the path. Stop after 666 having recorded MAX_PATHS jump threading paths. 667 668 SPEED_P indicate that we could increase code size to improve the code path */ 669 670 static void 671 fsm_find_control_statement_thread_paths (tree name, 672 hash_set<basic_block> *visited_bbs, 673 vec<basic_block, va_gc> *&path, 674 bool seen_loop_phi, bool speed_p) 675 { 676 /* If NAME appears in an abnormal PHI, then don't try to trace its 677 value back through PHI nodes. */ 678 if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name)) 679 return; 680 681 gimple *def_stmt = SSA_NAME_DEF_STMT (name); 682 basic_block var_bb = gimple_bb (def_stmt); 683 684 if (var_bb == NULL) 685 return; 686 687 /* We allow the SSA chain to contains PHIs and simple copies and constant 688 initializations. */ 689 if (gimple_code (def_stmt) != GIMPLE_PHI 690 && gimple_code (def_stmt) != GIMPLE_ASSIGN) 691 return; 692 693 if (gimple_code (def_stmt) == GIMPLE_PHI 694 && (gimple_phi_num_args (def_stmt) 695 >= (unsigned) PARAM_VALUE (PARAM_FSM_MAXIMUM_PHI_ARGUMENTS))) 696 return; 697 698 if (is_gimple_assign (def_stmt) 699 && ! handle_assignment_p (def_stmt)) 700 return; 701 702 /* Avoid infinite recursion. */ 703 if (visited_bbs->add (var_bb)) 704 return; 705 706 int next_path_length = 0; 707 basic_block last_bb_in_path = path->last (); 708 709 if (loop_containing_stmt (def_stmt)->header == gimple_bb (def_stmt)) 710 { 711 /* Do not walk through more than one loop PHI node. */ 712 if (seen_loop_phi) 713 return; 714 seen_loop_phi = true; 715 } 716 717 /* Following the chain of SSA_NAME definitions, we jumped from a definition in 718 LAST_BB_IN_PATH to a definition in VAR_BB. When these basic blocks are 719 different, append to PATH the blocks from LAST_BB_IN_PATH to VAR_BB. */ 720 if (var_bb != last_bb_in_path) 721 { 722 /* When VAR_BB == LAST_BB_IN_PATH, then the first block in the path 723 will already be in VISITED_BBS. When they are not equal, then we 724 must ensure that first block is accounted for to ensure we do not 725 create bogus jump threading paths. */ 726 visited_bbs->add ((*path)[0]); 727 if (!check_subpath_and_update_thread_path (last_bb_in_path, var_bb, 728 visited_bbs, path, 729 &next_path_length)) 730 return; 731 } 732 733 gcc_assert (path->last () == var_bb); 734 735 if (gimple_code (def_stmt) == GIMPLE_PHI) 736 handle_phi (as_a <gphi *> (def_stmt), name, var_bb, 737 visited_bbs, path, seen_loop_phi, speed_p); 738 else if (gimple_code (def_stmt) == GIMPLE_ASSIGN) 739 handle_assignment (def_stmt, name, var_bb, 740 visited_bbs, path, seen_loop_phi, speed_p); 741 742 /* Remove all the nodes that we added from NEXT_PATH. */ 743 if (next_path_length) 744 vec_safe_truncate (path, (path->length () - next_path_length)); 745 } 746 747 /* Search backwards from BB looking for paths where NAME (an SSA_NAME) 748 is a constant. Record such paths for jump threading. 749 750 It is assumed that BB ends with a control statement and that by 751 finding a path where NAME is a constant, we can thread the path. 752 SPEED_P indicate that we could increase code size to improve the code path */ 753 754 void 755 find_jump_threads_backwards (basic_block bb, bool speed_p) 756 { 757 gimple *stmt = get_gimple_control_stmt (bb); 758 if (!stmt) 759 return; 760 761 enum gimple_code code = gimple_code (stmt); 762 tree name = NULL; 763 if (code == GIMPLE_SWITCH) 764 name = gimple_switch_index (as_a <gswitch *> (stmt)); 765 else if (code == GIMPLE_GOTO) 766 name = gimple_goto_dest (stmt); 767 else if (code == GIMPLE_COND) 768 { 769 if (TREE_CODE (gimple_cond_lhs (stmt)) == SSA_NAME 770 && TREE_CODE_CLASS (TREE_CODE (gimple_cond_rhs (stmt))) == tcc_constant 771 && (INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))) 772 || POINTER_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt))))) 773 name = gimple_cond_lhs (stmt); 774 } 775 776 if (!name || TREE_CODE (name) != SSA_NAME) 777 return; 778 779 vec<basic_block, va_gc> *bb_path; 780 vec_alloc (bb_path, 10); 781 vec_safe_push (bb_path, bb); 782 hash_set<basic_block> *visited_bbs = new hash_set<basic_block>; 783 784 max_threaded_paths = PARAM_VALUE (PARAM_MAX_FSM_THREAD_PATHS); 785 fsm_find_control_statement_thread_paths (name, visited_bbs, bb_path, false, 786 speed_p); 787 788 delete visited_bbs; 789 vec_free (bb_path); 790 } 791 792 namespace { 793 794 const pass_data pass_data_thread_jumps = 795 { 796 GIMPLE_PASS, 797 "thread", 798 OPTGROUP_NONE, 799 TV_TREE_SSA_THREAD_JUMPS, 800 ( PROP_cfg | PROP_ssa ), 801 0, 802 0, 803 0, 804 TODO_update_ssa, 805 }; 806 807 class pass_thread_jumps : public gimple_opt_pass 808 { 809 public: 810 pass_thread_jumps (gcc::context *ctxt) 811 : gimple_opt_pass (pass_data_thread_jumps, ctxt) 812 {} 813 814 opt_pass * clone (void) { return new pass_thread_jumps (m_ctxt); } 815 virtual bool gate (function *); 816 virtual unsigned int execute (function *); 817 }; 818 819 bool 820 pass_thread_jumps::gate (function *fun ATTRIBUTE_UNUSED) 821 { 822 return flag_expensive_optimizations; 823 } 824 825 826 unsigned int 827 pass_thread_jumps::execute (function *fun) 828 { 829 loop_optimizer_init (LOOPS_HAVE_PREHEADERS | LOOPS_HAVE_SIMPLE_LATCHES); 830 831 /* Try to thread each block with more than one successor. */ 832 basic_block bb; 833 FOR_EACH_BB_FN (bb, fun) 834 { 835 if (EDGE_COUNT (bb->succs) > 1) 836 find_jump_threads_backwards (bb, true); 837 } 838 bool changed = thread_through_all_blocks (true); 839 840 loop_optimizer_finalize (); 841 return changed ? TODO_cleanup_cfg : 0; 842 } 843 844 } 845 846 gimple_opt_pass * 847 make_pass_thread_jumps (gcc::context *ctxt) 848 { 849 return new pass_thread_jumps (ctxt); 850 } 851 852 namespace { 853 854 const pass_data pass_data_early_thread_jumps = 855 { 856 GIMPLE_PASS, 857 "ethread", 858 OPTGROUP_NONE, 859 TV_TREE_SSA_THREAD_JUMPS, 860 ( PROP_cfg | PROP_ssa ), 861 0, 862 0, 863 0, 864 ( TODO_cleanup_cfg | TODO_update_ssa ), 865 }; 866 867 class pass_early_thread_jumps : public gimple_opt_pass 868 { 869 public: 870 pass_early_thread_jumps (gcc::context *ctxt) 871 : gimple_opt_pass (pass_data_early_thread_jumps, ctxt) 872 {} 873 874 opt_pass * clone (void) { return new pass_early_thread_jumps (m_ctxt); } 875 virtual bool gate (function *); 876 virtual unsigned int execute (function *); 877 }; 878 879 bool 880 pass_early_thread_jumps::gate (function *fun ATTRIBUTE_UNUSED) 881 { 882 return true; 883 } 884 885 886 unsigned int 887 pass_early_thread_jumps::execute (function *fun) 888 { 889 loop_optimizer_init (AVOID_CFG_MODIFICATIONS); 890 891 /* Try to thread each block with more than one successor. */ 892 basic_block bb; 893 FOR_EACH_BB_FN (bb, fun) 894 { 895 if (EDGE_COUNT (bb->succs) > 1) 896 find_jump_threads_backwards (bb, false); 897 } 898 thread_through_all_blocks (true); 899 900 loop_optimizer_finalize (); 901 return 0; 902 } 903 904 } 905 906 gimple_opt_pass * 907 make_pass_early_thread_jumps (gcc::context *ctxt) 908 { 909 return new pass_early_thread_jumps (ctxt); 910 } 911