Index: tree-outof-ssa.c =================================================================== --- tree-outof-ssa.c (revision 130626) +++ tree-outof-ssa.c (working copy) @@ -871,6 +871,20 @@ BITMAP_FREE (leader_has_match); } +/* A helper function to be called via walk_tree. Return DATA if it is + contained in subtree TP. */ + +static tree +contains_tree_r (tree *tp, int *walk_subtrees, void *data) +{ + if (*tp == data) + { + *walk_subtrees = 0; + return data; + } + else + return NULL_TREE; +} /* Look at all the incoming edges to block BB, and decide where the best place to insert the stmts on each edge are, and perform those insertions. */ @@ -944,7 +958,112 @@ if (count < 2) { if (single_edge) - bsi_commit_one_edge_insert (single_edge, NULL); + { + /* Loop back edges are special and should be handled that way. + Try to empty the latch of a single-basic-block loop. */ + if (single_edge->dest == single_edge->src) + { + bool do_it = true; + bool before = false; + tree stmts = PENDING_STMT (single_edge); + basic_block b_exit, b_pheader, b_loop = single_edge->src; + edge_iterator ei; + edge e; + block_stmt_iterator bsi_exit; + + if (EDGE_COUNT (b_loop->succs) != 2 + || EDGE_COUNT (b_loop->preds) != 2) + do_it = false; + + FOR_EACH_EDGE (e, ei, b_loop->succs) + if (e->dest != b_loop) + break; + + b_exit = e->dest; + + if (EDGE_COUNT (b_exit->preds) != 1 || PENDING_STMT (e)) + do_it = false; + + FOR_EACH_EDGE (e, ei, b_loop->preds) + if (e->src != b_loop) + break; + + b_pheader = e->src; + + if (b_exit == b_pheader + || b_exit == b_loop || b_pheader == b_loop) + do_it = false; + + bsi_exit = bsi_after_labels (b_exit); + bsi = bsi_last (single_edge->src); + stmt = bsi_stmt (bsi); + + /* Check if it is OK to do it. */ + if (TREE_CODE (stmt) == COND_EXPR) + { + tree expr = COND_EXPR_COND (stmt); + tree_stmt_iterator tsi; + before = true; + + for (tsi = tsi_start (stmts); !tsi_end_p (tsi); + tsi_next (&tsi)) + { + tree stmt1 = tsi_stmt (tsi); + tree var; + + if (TREE_CODE (stmt1) != GIMPLE_MODIFY_STMT) + { + print_generic_stmt (dump_file, stmt1, TDF_VOPS); + do_it = false; + break; + } + var = GIMPLE_STMT_OPERAND (stmt1, 0); + if (TREE_THIS_VOLATILE (var) + || TYPE_VOLATILE (TREE_TYPE (var)) + || walk_tree (&expr, contains_tree_r, var, NULL)) + { + do_it = false; + break; + } + } + } + /* Insert the statements right before the condition. */ + if (do_it) + { + tree_stmt_iterator tsi; + + for (tsi = tsi_start (stmts); !tsi_end_p (tsi); + tsi_next (&tsi)) + { + tree stmt1 = tsi_stmt (tsi); + tree var, tmp_var, copy; + + var = GIMPLE_STMT_OPERAND (stmt1, 0); + tmp_var = create_temp (var); + copy = + build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (tmp_var), + tmp_var, var); + set_is_used (tmp_var); + if (before) + bsi_insert_before (&bsi, copy, BSI_SAME_STMT); + else + bsi_insert_after (&bsi, copy, BSI_NEW_STMT); + copy = + build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (tmp_var), var, + tmp_var); + bsi_insert_before (&bsi_exit, copy, BSI_SAME_STMT); + + } + PENDING_STMT (single_edge) = 0; + if (before) + bsi_insert_before (&bsi, stmts, BSI_NEW_STMT); + else + bsi_insert_after (&bsi, stmts, BSI_NEW_STMT); + return; + } + } + bsi_commit_one_edge_insert (single_edge, NULL); + } return; }