From be477406042409e5431463f963e02b4365e94ef6 Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Mon, 7 Mar 2005 20:39:19 -0700 Subject: [PATCH] tree-cfg.c (find_taken_edge_computed_goto): New function. * tree-cfg.c (find_taken_edge_computed_goto): New function. (find_taken_edge): Call find_taken_edge_computed_goto as appropriate. Allow any gimple invariant rather than just INTEGER_CST for VAL. (cleanup_control_flow): Cleanup a computed goto which has turned into a simple goto. (tree_merge_blocks): If block B has any forced labels, move them to the start of block A. * tree-ssa-dom.c (thread_across_edge): Allow threading across computed gotos as well. * tree-ssa-threadupdate.c (remove_ctrl_stmt_and_useless_edges): Handle removal of unnecessary computed gotos too. (lookup_redirection_data): Fix type of INSERT argument. Callers updated. From-SVN: r96084 --- gcc/ChangeLog | 17 ++++++++ gcc/tree-cfg.c | 79 ++++++++++++++++++++++++++++++++++++- gcc/tree-ssa-dom.c | 17 +++++++- gcc/tree-ssa-threadupdate.c | 7 ++-- 4 files changed, 114 insertions(+), 6 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a18e5c85a0c..99505d8b568 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,20 @@ +2005-03-07 Jeff Law + + * tree-cfg.c (find_taken_edge_computed_goto): New function. + (find_taken_edge): Call find_taken_edge_computed_goto as + appropriate. Allow any gimple invariant rather than just + INTEGER_CST for VAL. + (cleanup_control_flow): Cleanup a computed goto which has turned + into a simple goto. + (tree_merge_blocks): If block B has any forced labels, move + them to the start of block A. + * tree-ssa-dom.c (thread_across_edge): Allow threading across + computed gotos as well. + * tree-ssa-threadupdate.c (remove_ctrl_stmt_and_useless_edges): Handle + removal of unnecessary computed gotos too. + (lookup_redirection_data): Fix type of INSERT argument. Callers + updated. + 2005-03-08 Kazu Hirata * tree-ssa-phiopt.c: Update copyright. Fix indentations. diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 205b5c0e82e..7622bf77190 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -129,6 +129,7 @@ static bool tree_can_merge_blocks_p (basic_block, basic_block); static void remove_bb (basic_block); static bool cleanup_control_flow (void); static bool cleanup_control_expr_graph (basic_block, block_stmt_iterator); +static edge find_taken_edge_computed_goto (basic_block, tree); static edge find_taken_edge_cond_expr (basic_block, tree); static edge find_taken_edge_switch_expr (basic_block, tree); static tree find_case_label_for_value (tree, tree); @@ -1301,7 +1302,22 @@ tree_merge_blocks (basic_block a, basic_block b) for (bsi = bsi_start (b); !bsi_end_p (bsi);) { if (TREE_CODE (bsi_stmt (bsi)) == LABEL_EXPR) - bsi_remove (&bsi); + { + tree label = bsi_stmt (bsi); + + bsi_remove (&bsi); + /* Now that we can thread computed gotos, we might have + a situation where we have a forced label in block B + However, the label at the start of block B might still be + used in other ways (think about the runtime checking for + Fortran assigned gotos). So we can not just delete the + label. Instead we move the label to the start of block A. */ + if (FORCED_LABEL (LABEL_EXPR_LABEL (label))) + { + block_stmt_iterator dest_bsi = bsi_start (a); + bsi_insert_before (&dest_bsi, label, BSI_NEW_STMT); + } + } else { set_bb_for_stmt (bsi_stmt (bsi), a); @@ -2122,6 +2138,43 @@ cleanup_control_flow (void) || 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) + { + edge e; + tree label; + edge_iterator ei; + basic_block target_block; + + /* First look at all the outgoing edges. Delete any outgoing + edges which do not go to the right block. For the one + edge which goes to the right block, fix up its flags. */ + label = TREE_OPERAND (GOTO_DESTINATION (stmt), 0); + target_block = label_to_block (label); + for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); ) + { + if (e->dest != target_block) + remove_edge (e); + else + { + /* Turn off the EDGE_ABNORMAL flag. */ + EDGE_SUCC (bb, 0)->flags &= ~EDGE_ABNORMAL; + + /* And set EDGE_FALLTHRU. */ + EDGE_SUCC (bb, 0)->flags |= EDGE_FALLTHRU; + ei_next (&ei); + } + } + + /* Remove the GOTO_EXPR as it is not needed. The CFG has all the + relevant information we need. */ + bsi_remove (&bsi); + retval = true; + } + /* Check for indirect calls that have been turned into noreturn calls. */ if (noreturn_call_p (stmt) && remove_fallthru_edge (bb->succs)) @@ -2229,7 +2282,7 @@ find_taken_edge (basic_block bb, tree val) gcc_assert (is_ctrl_stmt (stmt)); gcc_assert (val); - if (TREE_CODE (val) != INTEGER_CST) + if (! is_gimple_min_invariant (val)) return NULL; if (TREE_CODE (stmt) == COND_EXPR) @@ -2238,9 +2291,31 @@ find_taken_edge (basic_block bb, tree val) if (TREE_CODE (stmt) == SWITCH_EXPR) return find_taken_edge_switch_expr (bb, val); + if (computed_goto_p (stmt)) + return find_taken_edge_computed_goto (bb, TREE_OPERAND( val, 0)); + gcc_unreachable (); } +/* Given a constant value VAL and the entry block BB to a GOTO_EXPR + statement, determine which of the outgoing edges will be taken out of the + block. Return NULL if either edge may be taken. */ + +static edge +find_taken_edge_computed_goto (basic_block bb, tree val) +{ + basic_block dest; + edge e = NULL; + + dest = label_to_block (val); + if (dest) + { + e = find_edge (bb, dest); + gcc_assert (e != NULL); + } + + return e; +} /* Given a constant value VAL and the entry block BB to a COND_EXPR statement, determine which of the two edges will be taken out of the diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c index a14356500aa..aaa0dc5f491 100644 --- a/gcc/tree-ssa-dom.c +++ b/gcc/tree-ssa-dom.c @@ -715,7 +715,8 @@ thread_across_edge (struct dom_walk_data *walk_data, edge e) arm will be taken. */ if (stmt && (TREE_CODE (stmt) == COND_EXPR - || TREE_CODE (stmt) == SWITCH_EXPR)) + || TREE_CODE (stmt) == SWITCH_EXPR + || TREE_CODE (stmt) == GOTO_EXPR)) { tree cond, cached_lhs; @@ -723,6 +724,8 @@ thread_across_edge (struct dom_walk_data *walk_data, edge e) expression in the hash tables. */ if (TREE_CODE (stmt) == COND_EXPR) cond = COND_EXPR_COND (stmt); + else if (TREE_CODE (stmt) == GOTO_EXPR) + cond = GOTO_DESTINATION (stmt); else cond = SWITCH_COND (stmt); @@ -1000,6 +1003,18 @@ dom_opt_finalize_block (struct dom_walk_data *walk_data, basic_block bb) { thread_across_edge (walk_data, EDGE_SUCC (bb, 0)); } + else if ((last = last_stmt (bb)) + && TREE_CODE (last) == GOTO_EXPR + && TREE_CODE (TREE_OPERAND (last, 0)) == SSA_NAME) + { + edge_iterator ei; + edge e; + + FOR_EACH_EDGE (e, ei, bb->succs) + { + thread_across_edge (walk_data, e); + } + } else if ((last = last_stmt (bb)) && TREE_CODE (last) == COND_EXPR && (COMPARISON_CLASS_P (COND_EXPR_COND (last)) diff --git a/gcc/tree-ssa-threadupdate.c b/gcc/tree-ssa-threadupdate.c index d798713a439..e1e0d3ea889 100644 --- a/gcc/tree-ssa-threadupdate.c +++ b/gcc/tree-ssa-threadupdate.c @@ -169,6 +169,7 @@ remove_ctrl_stmt_and_useless_edges (basic_block bb, basic_block dest_bb) if (!bsi_end_p (bsi) && bsi_stmt (bsi) && (TREE_CODE (bsi_stmt (bsi)) == COND_EXPR + || TREE_CODE (bsi_stmt (bsi)) == GOTO_EXPR || TREE_CODE (bsi_stmt (bsi)) == SWITCH_EXPR)) bsi_remove (&bsi); @@ -228,7 +229,7 @@ redirection_data_eq (const void *p1, const void *p2) edges associated with E in the hash table. */ static struct redirection_data * -lookup_redirection_data (edge e, edge incoming_edge, bool insert) +lookup_redirection_data (edge e, edge incoming_edge, enum insert_option insert) { void **slot; struct redirection_data *elt; @@ -733,7 +734,7 @@ thread_block (basic_block bb) /* Insert the outgoing edge into the hash table if it is not already in the hash table. */ - lookup_redirection_data (e2, e, true); + lookup_redirection_data (e2, e, INSERT); } } @@ -744,7 +745,7 @@ thread_block (basic_block bb) if (all) { edge e = EDGE_PRED (bb, 0)->aux; - lookup_redirection_data (e, NULL, false)->do_not_duplicate = true; + lookup_redirection_data (e, NULL, NO_INSERT)->do_not_duplicate = true; } /* Now create duplicates of BB.