X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Ftree-cfgcleanup.c;h=8cf66cb4a270c5bddef8b7ffcee0e9d11dcf5144;hb=bca4d139fd7eb1b554c6701071c27048a0e458a6;hp=51b2fc59465f246526d1fb1e69f9e4da79f8fb41;hpb=820f2ae976ffe5a052176ac7d0ea325cc9357faf;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/tree-cfgcleanup.c b/gcc/tree-cfgcleanup.c index 51b2fc59465..8cf66cb4a27 100644 --- a/gcc/tree-cfgcleanup.c +++ b/gcc/tree-cfgcleanup.c @@ -1,5 +1,6 @@ /* CFG cleanup for trees. - Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 + Free Software Foundation, Inc. This file is part of GCC. @@ -28,7 +29,7 @@ Boston, MA 02110-1301, USA. */ #include "hard-reg-set.h" #include "basic-block.h" #include "output.h" -#include "errors.h" +#include "toplev.h" #include "flags.h" #include "function.h" #include "expr.h" @@ -45,6 +46,7 @@ Boston, MA 02110-1301, USA. */ #include "cfglayout.h" #include "hashtab.h" #include "tree-ssa-propagate.h" +#include "tree-scalar-evolution.h" /* Remove any fallthru edge from EV. Return true if an edge was removed. */ @@ -77,17 +79,23 @@ cleanup_control_expr_graph (basic_block bb, block_stmt_iterator bsi) { edge e; edge_iterator ei; + bool warned; + + fold_defer_overflow_warnings (); switch (TREE_CODE (expr)) { case COND_EXPR: - val = COND_EXPR_COND (expr); + val = fold (COND_EXPR_COND (expr)); break; case SWITCH_EXPR: - val = SWITCH_COND (expr); + val = fold (SWITCH_COND (expr)); if (TREE_CODE (val) != INTEGER_CST) - return false; + { + fold_undefer_and_ignore_overflow_warnings (); + return false; + } break; default: @@ -96,13 +104,24 @@ cleanup_control_expr_graph (basic_block bb, block_stmt_iterator bsi) taken_edge = find_taken_edge (bb, val); if (!taken_edge) - return false; + { + fold_undefer_and_ignore_overflow_warnings (); + return false; + } /* Remove all the edges except the one that is always executed. */ + warned = false; for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); ) { if (e != taken_edge) { + if (!warned) + { + fold_undefer_overflow_warnings + (true, expr, WARN_STRICT_OVERFLOW_CONDITIONAL); + warned = true; + } + taken_edge->probability += e->probability; taken_edge->count += e->count; remove_edge (e); @@ -111,13 +130,15 @@ cleanup_control_expr_graph (basic_block bb, block_stmt_iterator bsi) else ei_next (&ei); } + if (!warned) + fold_undefer_and_ignore_overflow_warnings (); if (taken_edge->probability > REG_BR_PROB_BASE) taken_edge->probability = REG_BR_PROB_BASE; } else taken_edge = single_succ_edge (bb); - bsi_remove (&bsi); + bsi_remove (&bsi, true); taken_edge->flags = EDGE_FALLTHRU; /* We removed some paths from the cfg. */ @@ -126,14 +147,6 @@ cleanup_control_expr_graph (basic_block bb, block_stmt_iterator bsi) return retval; } -/* A list of all the noreturn calls passed to modify_stmt. - cleanup_control_flow uses it to detect cases where a mid-block - indirect call has been turned into a noreturn call. When this - happens, all the instructions after the call are no longer - reachable and must be deleted as dead. */ - -VEC(tree,gc) *modified_noreturn_calls; - /* Try to remove superfluous control structures. */ static bool @@ -145,31 +158,37 @@ cleanup_control_flow (void) tree stmt; /* Detect cases where a mid-block call is now known not to return. */ - while (VEC_length (tree, modified_noreturn_calls)) - { - stmt = VEC_pop (tree, modified_noreturn_calls); - bb = bb_for_stmt (stmt); - if (bb != NULL && last_stmt (bb) != stmt && noreturn_call_p (stmt)) - split_block (bb, stmt); - } + if (cfun->gimple_df) + while (VEC_length (tree, MODIFIED_NORETURN_CALLS (cfun))) + { + stmt = VEC_pop (tree, MODIFIED_NORETURN_CALLS (cfun)); + bb = bb_for_stmt (stmt); + if (bb != NULL && last_stmt (bb) != stmt && noreturn_call_p (stmt)) + split_block (bb, stmt); + } FOR_EACH_BB (bb) { bsi = bsi_last (bb); + /* If the last statement of the block could throw and now cannot, + we need to prune cfg. */ + retval |= tree_purge_dead_eh_edges (bb); + if (bsi_end_p (bsi)) continue; stmt = bsi_stmt (bsi); + if (TREE_CODE (stmt) == COND_EXPR || TREE_CODE (stmt) == SWITCH_EXPR) retval |= cleanup_control_expr_graph (bb, bsi); - /* If we had a computed goto which has a compile-time determinable destination, then we can eliminate the goto. */ - if (TREE_CODE (stmt) == GOTO_EXPR - && TREE_CODE (GOTO_DESTINATION (stmt)) == ADDR_EXPR - && TREE_CODE (TREE_OPERAND (GOTO_DESTINATION (stmt), 0)) == LABEL_DECL) + else if (TREE_CODE (stmt) == GOTO_EXPR + && TREE_CODE (GOTO_DESTINATION (stmt)) == ADDR_EXPR + && (TREE_CODE (TREE_OPERAND (GOTO_DESTINATION (stmt), 0)) + == LABEL_DECL)) { edge e; tree label; @@ -207,13 +226,13 @@ cleanup_control_flow (void) /* Remove the GOTO_EXPR as it is not needed. The CFG has all the relevant information we need. */ - bsi_remove (&bsi); + bsi_remove (&bsi, true); retval = true; } /* Check for indirect calls that have been turned into noreturn calls. */ - if (noreturn_call_p (stmt) && remove_fallthru_edge (bb->succs)) + else if (noreturn_call_p (stmt) && remove_fallthru_edge (bb->succs)) { free_dominance_info (CDI_DOMINATORS); retval = true; @@ -233,6 +252,9 @@ static bool tree_forwarder_block_p (basic_block bb, bool phi_wanted) { block_stmt_iterator bsi; + edge_iterator ei; + edge e, succ; + basic_block dest; /* BB must have a single outgoing edge. */ if (single_succ_p (bb) != 1 @@ -284,6 +306,22 @@ tree_forwarder_block_p (basic_block bb, bool phi_wanted) return false; } + /* If we have an EH edge leaving this block, make sure that the + destination of this block has only one predecessor. This ensures + that we don't get into the situation where we try to remove two + forwarders that go to the same basic block but are handlers for + different EH regions. */ + succ = single_succ_edge (bb); + dest = succ->dest; + FOR_EACH_EDGE (e, ei, bb->preds) + { + if (e->flags & EDGE_EH) + { + if (!single_pred_p (dest)) + return false; + } + } + return true; } @@ -433,7 +471,7 @@ remove_forwarder_block (basic_block bb, basic_block **worklist) { label = bsi_stmt (bsi); gcc_assert (TREE_CODE (label) == LABEL_EXPR); - bsi_remove (&bsi); + bsi_remove (&bsi, false); bsi_insert_before (&bsi_to, label, BSI_CONTINUE_LINKING); } } @@ -470,7 +508,7 @@ cleanup_forwarder_blocks (void) { basic_block bb; bool changed = false; - basic_block *worklist = xmalloc (sizeof (basic_block) * n_basic_blocks); + basic_block *worklist = XNEWVEC (basic_block, n_basic_blocks); basic_block *current = worklist; FOR_EACH_BB (bb) @@ -489,14 +527,12 @@ cleanup_forwarder_blocks (void) return changed; } -/* Remove unreachable blocks and other miscellaneous clean up work. */ +/* Do one round of CFG cleanup. */ -bool -cleanup_tree_cfg (void) +static bool +cleanup_tree_cfg_1 (void) { - bool retval = false; - - timevar_push (TV_TREE_CLEANUP_CFG); + bool retval; retval = cleanup_control_flow (); retval |= delete_unreachable_blocks (); @@ -516,51 +552,72 @@ cleanup_tree_cfg (void) end_recording_case_labels (); } -#ifdef ENABLE_CHECKING - if (retval) + /* Merging the blocks may create new opportunities for folding + conditional branches (due to the elimination of single-valued PHI + nodes). */ + retval |= merge_seq_blocks (); + + return retval; +} + + +/* Remove unreachable blocks and other miscellaneous clean up work. + Return true if the flowgraph was modified, false otherwise. */ + +bool +cleanup_tree_cfg (void) +{ + bool retval, changed; + + timevar_push (TV_TREE_CLEANUP_CFG); + + /* Iterate until there are no more cleanups left to do. If any + iteration changed the flowgraph, set CHANGED to true. */ + changed = false; + do { - gcc_assert (!cleanup_control_flow ()); - gcc_assert (!delete_unreachable_blocks ()); - if (optimize > 0) - gcc_assert (!cleanup_forwarder_blocks ()); + retval = cleanup_tree_cfg_1 (); + changed |= retval; } -#endif - - /* Merging the blocks creates no new opportunities for the other - optimizations, so do it here. */ - retval |= merge_seq_blocks (); + while (retval); compact_blocks (); #ifdef ENABLE_CHECKING verify_flow_info (); #endif + timevar_pop (TV_TREE_CLEANUP_CFG); - return retval; + + return changed; } /* Cleanup cfg and repair loop structures. */ -void +bool cleanup_tree_cfg_loop (void) { - bitmap changed_bbs = BITMAP_ALLOC (NULL); + bool changed = cleanup_tree_cfg (); - cleanup_tree_cfg (); - - fix_loop_structure (current_loops, changed_bbs); - calculate_dominance_info (CDI_DOMINATORS); + if (changed) + { + bitmap changed_bbs = BITMAP_ALLOC (NULL); + calculate_dominance_info (CDI_DOMINATORS); + fix_loop_structure (changed_bbs); - /* This usually does nothing. But sometimes parts of cfg that originally - were inside a loop get out of it due to edge removal (since they - become unreachable by back edges from latch). */ - rewrite_into_loop_closed_ssa (changed_bbs, TODO_update_ssa); + /* This usually does nothing. But sometimes parts of cfg that originally + were inside a loop get out of it due to edge removal (since they + become unreachable by back edges from latch). */ + rewrite_into_loop_closed_ssa (changed_bbs, TODO_update_ssa); - BITMAP_FREE (changed_bbs); + BITMAP_FREE (changed_bbs); #ifdef ENABLE_CHECKING - verify_loop_structure (current_loops); + verify_loop_structure (); #endif + scev_reset (); + } + return changed; } /* Merge the PHI nodes at BB into those at BB's sole successor. */ @@ -693,10 +750,10 @@ remove_forwarder_block_with_phi (basic_block bb) :; */ -static void +static unsigned int merge_phi_nodes (void) { - basic_block *worklist = xmalloc (sizeof (basic_block) * n_basic_blocks); + basic_block *worklist = XNEWVEC (basic_block, n_basic_blocks); basic_block *current = worklist; basic_block bb; @@ -728,6 +785,40 @@ merge_phi_nodes (void) nodes at BB. */ *current++ = bb; } + else + { + tree phi; + unsigned int dest_idx = single_succ_edge (bb)->dest_idx; + + /* BB dominates DEST. There may be many users of the PHI + nodes in BB. However, there is still a trivial case we + can handle. If the result of every PHI in BB is used + only by a PHI in DEST, then we can trivially merge the + PHI nodes from BB into DEST. */ + for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi)) + { + tree result = PHI_RESULT (phi); + use_operand_p imm_use; + tree use_stmt; + + /* If the PHI's result is never used, then we can just + ignore it. */ + if (has_zero_uses (result)) + continue; + + /* Get the single use of the result of this PHI node. */ + if (!single_imm_use (result, &imm_use, &use_stmt) + || TREE_CODE (use_stmt) != PHI_NODE + || bb_for_stmt (use_stmt) != dest + || PHI_ARG_DEF (use_stmt, dest_idx) != result) + break; + } + + /* If the loop above iterated through all the PHI nodes + in BB, then we can merge the PHIs from BB into DEST. */ + if (!phi) + *current++ = bb; + } } /* Now let's drain WORKLIST. */ @@ -738,6 +829,7 @@ merge_phi_nodes (void) } free (worklist); + return 0; } static bool