summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorlaw <law@138bc75d-0d04-0410-961f-82ee72b054a4>2005-03-08 03:39:19 +0000
committerlaw <law@138bc75d-0d04-0410-961f-82ee72b054a4>2005-03-08 03:39:19 +0000
commit6d7413d8f7da0b76870150c1c9b79274bec9cfe4 (patch)
treec58611cf62c9432b67999f9b9ddee77792efffb3 /gcc
parent6ec283975962973a954c7cd06b0d9f2edc3c1160 (diff)
downloadgcc-6d7413d8f7da0b76870150c1c9b79274bec9cfe4.tar.gz
* 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@96084 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog17
-rw-r--r--gcc/tree-cfg.c79
-rw-r--r--gcc/tree-ssa-dom.c17
-rw-r--r--gcc/tree-ssa-threadupdate.c7
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 <law@redhat.com>
+
+ * 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 <kazu@cs.umass.edu>
* 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);
@@ -1001,6 +1004,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))
|| TREE_CODE (COND_EXPR_COND (last)) == SSA_NAME)
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.