This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [tree-ssa] Removal of gotos from cfg based ir
Hello,
I am not quite sure what was the resolution of the discussion; anyway,
here is the patch without the {COND,SWITCH}_EXPR ==> CF_EXPR change.
Zdenek
* tree-cfg.c: (make_edges): Eliminate fallthru to exit.
(make_ctrl_stmt_edges): Nonlocal goto handling moved to
make_goto_expr_edges.
(make_goto_expr_edges): Remove simple gotos.
(cfg_remove_useless_stmts_bb): Goto removal cancelled.
(cleanup_cond_expr_graph, cleanup_switch_expr_graph):
Replaced by ...
(cleanup_control_expr_graph): New.
(cleanup_control_flow): Use it.
(disband_implicit_edges): New.
(delete_tree_cfg): Call it.
(tree_split_edge, thread_jumps, tree_try_redirect_by_replacing_jump,
tree_redirect_edge_and_branch): Work over no-gotos form.
(tree_verify_flow_info): Check no-gotos form invariants.
* tree-pretty-print.c (dump_generic_node): Fix semicolons after
statements.
(pp_cfg_jump, dump_implicit_edges): New.
(dump_generic_bb_buff): Call dump_implicit_edges.
* tree-flow.h (cleanup_cond_expr_graph, cleanup_switch_expr_graph):
Declaration removed.
(cleanup_control_expr_graph, delete_tree_ssa): Declare.
* tree-optimize.c (optimize_function_tree): Add implicitly represented gotos
before recreating the chain.
* tree-ssa-dom.c (thread_jumps_walk_stmts, optimize_stmt): Use
cleanup_control_expr_graph.
* tree-ssa.c (delete_tree_ssa): Export, work even if there are no
referenced_vars.
(rewrite_out_of_ssa): Don't call it.
Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-cfg.c,v
retrieving revision 1.1.4.217
diff -c -3 -p -r1.1.4.217 tree-cfg.c
*** tree-cfg.c 16 Nov 2003 11:00:40 -0000 1.1.4.217
--- tree-cfg.c 18 Nov 2003 01:14:26 -0000
*************** static void
*** 448,453 ****
--- 448,454 ----
make_edges (void)
{
basic_block bb;
+ edge e;
/* Create an edge from entry to the first block with executable
statements in it. */
*************** make_edges (void)
*** 476,481 ****
--- 477,505 ----
make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
}
+ /* If there is a fallthru edge to exit out of the last block, transform it
+ to a return statement. */
+ for (e = EXIT_BLOCK_PTR->prev_bb->succ; e; e = e->succ_next)
+ if (e->flags & EDGE_FALLTHRU)
+ break;
+ if (e && e->dest == EXIT_BLOCK_PTR)
+ {
+ block_stmt_iterator bsi;
+ tree x;
+
+ /* ??? Can we have multiple outgoing edges here? COND_EXPR
+ always has two gotos, and I can't think how one would have
+ achived this via EH. */
+ if (e != EXIT_BLOCK_PTR->prev_bb->succ || e->succ_next)
+ abort ();
+
+ x = build (RETURN_EXPR, void_type_node, NULL_TREE);
+ bsi = bsi_last (EXIT_BLOCK_PTR->prev_bb);
+ bsi_insert_after (&bsi, x, BSI_NEW_STMT);
+
+ e->flags &= ~EDGE_FALLTHRU;
+ }
+
/* We do not care about fake edges, so remove any that the CFG
builder inserted for completeness. */
remove_fake_edges ();
*************** make_ctrl_stmt_edges (basic_block bb)
*** 505,515 ****
{
case GOTO_EXPR:
make_goto_expr_edges (bb);
-
- /* If this is potentially a nonlocal goto, then this should also
- create an edge to the exit block. */
- if (nonlocal_goto_p (last))
- make_edge (bb, EXIT_BLOCK_PTR, EDGE_ABNORMAL);
break;
case RETURN_EXPR:
--- 529,534 ----
*************** make_goto_expr_edges (basic_block bb)
*** 657,666 ****
{
tree goto_t, dest;
basic_block target_bb;
- int edge_flags;
int for_call;
! goto_t = last_stmt (bb);
/* If the last statement is not a GOTO (i.e., it is a RETURN_EXPR,
CALL_EXPR or MODIFY_EXPR), then the edge is an abnormal edge resulting
--- 676,685 ----
{
tree goto_t, dest;
basic_block target_bb;
int for_call;
+ block_stmt_iterator last = bsi_last (bb);
! goto_t = bsi_stmt (last);
/* If the last statement is not a GOTO (i.e., it is a RETURN_EXPR,
CALL_EXPR or MODIFY_EXPR), then the edge is an abnormal edge resulting
*************** make_goto_expr_edges (basic_block bb)
*** 669,675 ****
{
dest = error_mark_node;
for_call = 1;
- edge_flags = EDGE_ABNORMAL;
}
else
{
--- 688,693 ----
*************** make_goto_expr_edges (basic_block bb)
*** 679,691 ****
/* A GOTO to a local label creates normal edges. */
if (simple_goto_p (goto_t))
{
! make_edge (bb, label_to_block (dest), 0);
return;
}
! /* If we reach here, then we either have a computed goto or
! a nonlocal goto. */
! edge_flags = EDGE_ABNORMAL;
}
/* Look for the block starting with the destination label. In the
--- 697,717 ----
/* A GOTO to a local label creates normal edges. */
if (simple_goto_p (goto_t))
{
! make_edge (bb, label_to_block (dest), EDGE_FALLTHRU);
! bsi_remove (&last);
return;
}
! /* If this is potentially a nonlocal goto, then this should
! create an edge to the exit block. */
! if (nonlocal_goto_p (goto_t))
! make_edge (bb, EXIT_BLOCK_PTR, EDGE_ABNORMAL);
!
! /* Nothing more to do for nonlocal gotos. */
! if (TREE_CODE (dest) == LABEL_DECL)
! return;
!
! /* Computed gotos remain. */
}
/* Look for the block starting with the destination label. In the
*************** make_goto_expr_edges (basic_block bb)
*** 702,710 ****
if (TREE_CODE (target) != LABEL_EXPR)
break;
- if (TREE_CODE (dest) == LABEL_DECL)
- continue;
-
if (
/* Computed GOTOs. Make an edge to every label block that has
been marked as a potential target for a computed goto. */
--- 728,733 ----
*************** make_goto_expr_edges (basic_block bb)
*** 714,720 ****
goto. */
|| (NONLOCAL_LABEL (LABEL_EXPR_LABEL (target)) && for_call == 1))
{
! make_edge (bb, target_bb, edge_flags);
break;
}
}
--- 737,743 ----
goto. */
|| (NONLOCAL_LABEL (LABEL_EXPR_LABEL (target)) && for_call == 1))
{
! make_edge (bb, target_bb, EDGE_ABNORMAL);
break;
}
}
*************** static void
*** 1283,1356 ****
cfg_remove_useless_stmts_bb (basic_block bb)
{
block_stmt_iterator bsi;
! tree stmt = NULL_TREE;
! tree *gotos[2], *pstmt;
! int n_gotos, n_rem_gotos;
! tree cond, var = NULL_TREE, val = NULL_TREE;
struct var_ann_d *ann;
! /* Check whether we come here from a condition, and if so, get the
condition. */
! if (bb->pred && !bb->pred->pred_next
! && (bb->pred->flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE)))
! {
! cond = COND_EXPR_COND (last_stmt (bb->pred->src));
! if (bb->pred->flags & EDGE_FALSE_VALUE)
! cond = invert_truthvalue (cond);
! if (TREE_CODE (cond) == VAR_DECL
! || TREE_CODE (cond) == PARM_DECL)
! {
! var = cond;
! val = convert (TREE_TYPE (cond), integer_zero_node);
! }
! else if ((TREE_CODE (cond) == EQ_EXPR)
! && (TREE_CODE (TREE_OPERAND (cond, 0)) == VAR_DECL
! || TREE_CODE (TREE_OPERAND (cond, 0)) == PARM_DECL)
! && (TREE_CODE (TREE_OPERAND (cond, 1)) == VAR_DECL
! || TREE_CODE (TREE_OPERAND (cond, 1)) == PARM_DECL
! || TREE_CONSTANT (TREE_OPERAND (cond, 1))))
! {
! var = TREE_OPERAND (cond, 0);
! val = TREE_OPERAND (cond, 1);
! }
! if (var)
! {
! /* Only work for normal local variables. */
! ann = var_ann (var);
! if (!ann
! || ann->may_aliases
! || TREE_ADDRESSABLE (var))
! var = NULL_TREE;
! if (! TREE_CONSTANT (val))
! {
! ann = var_ann (val);
! if (!ann
! || ann->may_aliases
! || TREE_ADDRESSABLE (val))
! val = NULL_TREE;
! }
! }
! /* Ignore floating point variables, since comparison behaves weird for
! them. */
! if (var
! && FLOAT_TYPE_P (TREE_TYPE (var)))
! var = NULL_TREE;
}
for (bsi = bsi_start (bb); !bsi_end_p (bsi);)
{
stmt = bsi_stmt (bsi);
- if (!var)
- {
- bsi_next (&bsi);
- continue;
- }
-
/* If the THEN/ELSE clause merely assigns a value to a variable/parameter
which is already known to contain that value, then remove the useless
THEN/ELSE clause. */
--- 1306,1372 ----
cfg_remove_useless_stmts_bb (basic_block bb)
{
block_stmt_iterator bsi;
! tree stmt;
! tree cond, var, val;
struct var_ann_d *ann;
! /* Check whether we come here from a COND_EXPR, and if so, get the
condition. */
! if (!bb->pred
! || bb->pred->pred_next
! || !(bb->pred->flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE)))
! return;
! stmt = last_stmt (bb->pred->src);
! cond = COND_EXPR_COND (stmt);
! if (bb->pred->flags & EDGE_FALSE_VALUE)
! cond = invert_truthvalue (cond);
! if (TREE_CODE (cond) == VAR_DECL
! || TREE_CODE (cond) == PARM_DECL)
! {
! var = cond;
! val = convert (TREE_TYPE (cond), integer_zero_node);
! }
! else if ((TREE_CODE (cond) == EQ_EXPR)
! && (TREE_CODE (TREE_OPERAND (cond, 0)) == VAR_DECL
! || TREE_CODE (TREE_OPERAND (cond, 0)) == PARM_DECL)
! && (TREE_CODE (TREE_OPERAND (cond, 1)) == VAR_DECL
! || TREE_CODE (TREE_OPERAND (cond, 1)) == PARM_DECL
! || TREE_CONSTANT (TREE_OPERAND (cond, 1))))
! {
! var = TREE_OPERAND (cond, 0);
! val = TREE_OPERAND (cond, 1);
! }
! else
! return;
!
! /* Only work for normal local variables. */
! ann = var_ann (var);
! if (!ann
! || ann->may_aliases
! || TREE_ADDRESSABLE (var))
! return;
! if (! TREE_CONSTANT (val))
! {
! ann = var_ann (val);
! if (!ann
! || ann->may_aliases
! || TREE_ADDRESSABLE (val))
! return;
}
+ /* Ignore floating point variables, since comparison behaves weirdly for
+ them. */
+ if (FLOAT_TYPE_P (TREE_TYPE (var)))
+ return;
+
for (bsi = bsi_start (bb); !bsi_end_p (bsi);)
{
stmt = bsi_stmt (bsi);
/* If the THEN/ELSE clause merely assigns a value to a variable/parameter
which is already known to contain that value, then remove the useless
THEN/ELSE clause. */
*************** cfg_remove_useless_stmts_bb (basic_block
*** 1369,1430 ****
&& (TREE_OPERAND (stmt, 0) == var
|| TREE_OPERAND (stmt, 0) == val
|| TREE_CODE (TREE_OPERAND (stmt, 1)) == VA_ARG_EXPR)))
! var = NULL_TREE;
bsi_next (&bsi);
}
-
- if (!stmt)
- return;
-
- /* Remove useless GOTOs from COND_EXPRs. Other useless gotos could be
- removed by cfg cleanup, but it is not done currently, so do it here
- also. */
- if (TREE_CODE (stmt) == GOTO_EXPR
- && (bb->succ->flags & EDGE_ABNORMAL) == 0)
- {
- gotos[0] = &stmt;
- n_gotos = 1;
- }
- else if (TREE_CODE (stmt) == COND_EXPR
- && (bb->succ->flags & EDGE_ABNORMAL) == 0
- && (bb->succ->succ_next->flags & EDGE_ABNORMAL) == 0)
- {
- gotos[0] = &COND_EXPR_THEN (stmt);
- gotos[1] = &COND_EXPR_ELSE (stmt);
- n_gotos = 2;
- }
- else
- return;
-
- n_rem_gotos = n_gotos;
- while (n_gotos--)
- {
- pstmt = gotos[n_gotos];
- stmt = *pstmt;
-
- if (TREE_CODE (GOTO_DESTINATION (stmt)) != LABEL_DECL)
- continue;
-
- if (label_to_block (GOTO_DESTINATION (stmt)) != bb->next_bb)
- continue;
-
- *pstmt = build_empty_stmt ();
- n_rem_gotos--;
- }
-
- /* The statement does nothing, remove it completely. */
- if (!n_rem_gotos)
- {
- bsi = bsi_last (bb);
- bsi_remove (&bsi);
-
- if (bb->succ->succ_next)
- abort ();
-
- bb->succ->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
- bb->succ->flags |= EDGE_FALLTHRU;
- }
}
/* A cfg-aware version of remove_useless_stmts_and_vars. */
--- 1385,1394 ----
&& (TREE_OPERAND (stmt, 0) == var
|| TREE_OPERAND (stmt, 0) == val
|| TREE_CODE (TREE_OPERAND (stmt, 1)) == VA_ARG_EXPR)))
! return;
bsi_next (&bsi);
}
}
/* A cfg-aware version of remove_useless_stmts_and_vars. */
*************** tree_block_forwards_to (basic_block bb)
*** 1591,1614 ****
return NULL;
/* Walk past any labels at the start of this block. */
! bsi = bsi_start (bb);
! while (1)
{
- stmt = NULL;
- if (bsi_end_p (bsi))
- break;
stmt = bsi_stmt (bsi);
! if (TREE_CODE (stmt) == LABEL_EXPR)
! bsi_next (&bsi);
! else
break;
}
! /* If we reached the end of this block, or hit a GOTO_EXPR to an known
! location, then we may be able to optimize this case. */
! if (!stmt
! || (TREE_CODE (stmt) == GOTO_EXPR
! && TREE_CODE (GOTO_DESTINATION (stmt)) == LABEL_DECL))
{
basic_block dest;
--- 1555,1570 ----
return NULL;
/* Walk past any labels at the start of this block. */
! for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
{
stmt = bsi_stmt (bsi);
! if (TREE_CODE (stmt) != LABEL_EXPR)
break;
}
! /* If we reached the end of this block we may be able to optimize this
! case. */
! if (bsi_end_p (bsi))
{
basic_block dest;
*************** cleanup_control_flow (void)
*** 1635,1680 ****
basic_block bb;
block_stmt_iterator bsi;
bool retval = false;
FOR_EACH_BB (bb)
{
bsi = bsi_last (bb);
! if (!bsi_end_p (bsi))
! {
! enum tree_code code = TREE_CODE (bsi_stmt (bsi));
! if (code == COND_EXPR)
! retval |= cleanup_cond_expr_graph (bb, bsi);
! else if (code == SWITCH_EXPR)
! retval |= cleanup_switch_expr_graph (bb, bsi);
! }
}
return retval;
}
! /* Disconnect an unreachable block in the conditional expression starting
at block BB. */
bool
! cleanup_cond_expr_graph (basic_block bb, block_stmt_iterator bsi)
{
- tree val;
edge taken_edge;
bool retval = false;
! tree cond_expr = bsi_stmt (bsi);
!
! #if defined ENABLE_CHECKING
! if (cond_expr == NULL_TREE
! || TREE_CODE (cond_expr) != COND_EXPR
! || !bb->succ)
! abort ();
! #endif
if (bb->succ->succ_next)
{
edge e, next;
! val = COND_EXPR_COND (cond_expr);
taken_edge = find_taken_edge (bb, val);
if (!taken_edge)
return false;
--- 1591,1643 ----
basic_block bb;
block_stmt_iterator bsi;
bool retval = false;
+ tree stmt;
FOR_EACH_BB (bb)
{
bsi = bsi_last (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);
}
return retval;
}
! /* Disconnect an unreachable block in the control expression starting
at block BB. */
bool
! cleanup_control_expr_graph (basic_block bb, block_stmt_iterator bsi)
{
edge taken_edge;
bool retval = false;
! tree expr = bsi_stmt (bsi), val;
if (bb->succ->succ_next)
{
edge e, next;
! switch (TREE_CODE (expr))
! {
! case COND_EXPR:
! val = COND_EXPR_COND (expr);
! break;
!
! case SWITCH_EXPR:
! val = SWITCH_COND (expr);
! if (TREE_CODE (val) != INTEGER_CST)
! return false;
! break;
!
! default:
! abort ();
! }
!
taken_edge = find_taken_edge (bb, val);
if (!taken_edge)
return false;
*************** cleanup_cond_expr_graph (basic_block bb,
*** 1693,1766 ****
else
taken_edge = bb->succ;
! if (taken_edge->flags & EDGE_TRUE_VALUE)
! bsi_replace (&bsi, COND_EXPR_THEN (cond_expr));
! else if (taken_edge->flags & EDGE_FALSE_VALUE)
! bsi_replace (&bsi, COND_EXPR_ELSE (cond_expr));
! else
! abort ();
!
! taken_edge->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
!
! return retval;
! }
!
! /* Disconnect unreachable blocks in the 'switch' expression starting at
! block SWITCH_BB.
!
! If the switch condition of the SWITCH_EXPR node in block SWITCH_BB is
! constant, disconnect all the subgraphs for all the case labels that will
! never be taken. */
!
! bool
! cleanup_switch_expr_graph (basic_block bb, block_stmt_iterator bsi)
! {
! tree switch_expr = bsi_stmt (bsi);
! tree switch_val, taken_case;
! basic_block dest_bb;
! bool retval;
!
! #if defined ENABLE_CHECKING
! if (switch_expr == NULL_TREE || TREE_CODE (switch_expr) != SWITCH_EXPR)
! abort ();
! #endif
!
! retval = false;
! if (bb->succ->succ_next)
! {
! edge e, next;
!
! /* Multiple destination edges. If we've got a integer constant,
! we can look up the value in the switch condition and replace. */
! switch_val = SWITCH_COND (switch_expr);
! if (TREE_CODE (switch_val) != INTEGER_CST)
! return retval;
!
! taken_case = find_case_label_for_value (switch_expr, switch_val);
! dest_bb = label_to_block (CASE_LABEL (taken_case));
!
! /* Remove all the edges that will never be taken. */
! for (e = bb->succ; e ; e = next)
! {
! next = e->succ_next;
! if (e->dest != dest_bb)
! {
! ssa_remove_edge (e);
! retval = true;
! }
! }
! }
! else
! {
! /* There is only one destination edge, which means that all of
! the labels go to the same place. */
! dest_bb = bb->succ->dest;
! taken_case = TREE_VEC_ELT (SWITCH_LABELS (switch_expr), 0);
! }
!
! /* Simplify the SWITCH_EXPR itself. */
! taken_case = build (GOTO_EXPR, void_type_node, CASE_LABEL (taken_case));
! bsi_replace (&bsi, taken_case);
return retval;
}
--- 1656,1663 ----
else
taken_edge = bb->succ;
! bsi_remove (&bsi);
! taken_edge->flags = EDGE_FALLTHRU;
return retval;
}
*************** stmt_ends_bb_p (tree t)
*** 2289,2301 ****
return is_ctrl_stmt (t) || is_ctrl_altering_stmt (t);
}
/* Remove all the blocks and edges that make up the flowgraph. */
void
delete_tree_cfg (void)
{
if (n_basic_blocks > 0)
! free_blocks_annotations ();
free_basic_block_vars (0);
tree_bb_root = NULL;
}
--- 2186,2234 ----
return is_ctrl_stmt (t) || is_ctrl_altering_stmt (t);
}
+ /* Add gotos that used to be represented implicitly in cfg. */
+
+ static void
+ disband_implicit_edges (void)
+ {
+ basic_block bb;
+ block_stmt_iterator last;
+ edge e;
+
+ FOR_EACH_BB (bb)
+ {
+ last = bsi_last (bb);
+
+ /* Find a fallthru edge and emit the goto if neccesary. */
+ for (e = bb->succ; e; e = e->succ_next)
+ if (e->flags & EDGE_FALLTHRU)
+ break;
+
+ if (!e
+ || e->dest == bb->next_bb)
+ continue;
+
+ if (e->dest == EXIT_BLOCK_PTR)
+ abort ();
+
+ bsi_insert_after (&last,
+ build1 (GOTO_EXPR, void_type_node,
+ tree_block_label (e->dest)),
+ BSI_NEW_STMT);
+ }
+ }
+
/* Remove all the blocks and edges that make up the flowgraph. */
void
delete_tree_cfg (void)
{
if (n_basic_blocks > 0)
! {
! disband_implicit_edges ();
! free_blocks_annotations ();
! }
!
free_basic_block_vars (0);
tree_bb_root = NULL;
}
*************** tree_split_edge (edge edge_in)
*** 2655,2708 ****
if (!e)
after_bb = dest->prev_bb;
else
! {
! after_bb = EXIT_BLOCK_PTR->prev_bb;
! for (e = after_bb->succ; e ; e = e->succ_next)
! if (e->flags & EDGE_FALLTHRU)
! break;
! if (e)
! {
! block_stmt_iterator bsi;
! tree x;
!
! /* We have a fallthru to exit out of the last block.
! Transform this to a return statement. */
! /* ??? Can we have multiple outgoing edges here? COND_EXPR
! always has two gotos, and I can't think how one would have
! achived this via EH. */
! if (e != after_bb->succ || e->succ_next)
! abort ();
!
! x = build (RETURN_EXPR, void_type_node, NULL_TREE);
! bsi = bsi_last (after_bb);
! bsi_insert_after (&bsi, x, BSI_NEW_STMT);
!
! e->flags &= ~EDGE_FALLTHRU;
! }
! }
}
new_bb = create_bb (NULL, after_bb);
create_block_annotation (new_bb);
! new_edge = make_edge (new_bb, dest, 0);
!
! if (edge_in->flags & EDGE_FALLTHRU)
! {
! new_edge->flags = EDGE_FALLTHRU;
! redirect_edge_succ (edge_in, new_bb);
! }
! else
! {
! block_stmt_iterator i;
! tree x;
!
! if (!tree_redirect_edge_and_branch_1 (edge_in, new_bb, true))
! abort ();
! x = build (GOTO_EXPR, void_type_node, tree_block_label (dest));
! i = bsi_last (new_bb);
! bsi_insert_after (&i, x, BSI_NEW_STMT);
! }
/* Find all the PHI arguments on the original edge, and change them to
the new edge. */
--- 2588,2602 ----
if (!e)
after_bb = dest->prev_bb;
else
! after_bb = EXIT_BLOCK_PTR->prev_bb;
}
new_bb = create_bb (NULL, after_bb);
create_block_annotation (new_bb);
! new_edge = make_edge (new_bb, dest, EDGE_FALLTHRU);
! if (!tree_redirect_edge_and_branch_1 (edge_in, new_bb, true))
! abort ();
/* Find all the PHI arguments on the original edge, and change them to
the new edge. */
*************** tree_verify_flow_info (void)
*** 2747,2756 ****
basic_block bb;
block_stmt_iterator bsi;
tree stmt;
FOR_EACH_BB (bb)
{
- edge e;
bool found_ctrl_stmt = false;
tree phi;
int i;
--- 2641,2657 ----
basic_block bb;
block_stmt_iterator bsi;
tree stmt;
+ edge e;
+
+ for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
+ if (e->flags & EDGE_FALLTHRU)
+ {
+ error ("Fallthru to exit from bb %d\n", e->src->index);
+ err = 1;
+ }
FOR_EACH_BB (bb)
{
bool found_ctrl_stmt = false;
tree phi;
int i;
*************** tree_verify_flow_info (void)
*** 2844,2858 ****
if (bsi_end_p (bsi))
continue;
! for (e = bb->succ; e; e = e->succ_next)
! if (e->flags & EDGE_FALLTHRU && e->dest != bb->next_bb)
! {
! error ("Fallthru edge of bb %d does not point to following block\n", bb->index);
! err = 1;
! }
- stmt = bsi_stmt (bsi);
switch (TREE_CODE (stmt))
{
case COND_EXPR:
--- 2745,2763 ----
if (bsi_end_p (bsi))
continue;
! stmt = bsi_stmt (bsi);
+ if (is_ctrl_stmt (stmt))
+ {
+ for (e = bb->succ; e; e = e->succ_next)
+ if (e->flags & EDGE_FALLTHRU)
+ {
+ error ("Fallthru edge after a control statement in bb %d \n",
+ bb->index);
+ err = 1;
+ }
+ }
switch (TREE_CODE (stmt))
{
case COND_EXPR:
*************** tree_verify_flow_info (void)
*** 2891,2913 ****
}
}
break;
case GOTO_EXPR:
if (simple_goto_p (stmt))
{
! if (!bb->succ || bb->succ->succ_next
! || (bb->succ->flags & (EDGE_FALLTHRU | EDGE_ABNORMAL
! | EDGE_TRUE_VALUE | EDGE_FALSE_VALUE)))
! {
! error ("Wrong outgoing edge flags at end of bb %d\n", bb->index);
! err = 1;
! }
! if (!has_label_p (bb->succ->dest, GOTO_DESTINATION (stmt)))
! {
! error ("Label %s does not match edge at end of bb %d\n",
! IDENTIFIER_POINTER (DECL_NAME (stmt)),
! bb->index);
! err = 1;
! }
}
else
{
--- 2796,2807 ----
}
}
break;
+
case GOTO_EXPR:
if (simple_goto_p (stmt))
{
! error ("Explicit goto at end of bb %d\n", bb->index);
! err = 1;
}
else
{
*************** tree_verify_flow_info (void)
*** 2934,2939 ****
--- 2828,2834 ----
}
}
break;
+
case RETURN_EXPR:
if (!bb->succ || bb->succ->succ_next
|| (bb->succ->flags & (EDGE_FALLTHRU | EDGE_ABNORMAL
*************** tree_verify_flow_info (void)
*** 2948,2953 ****
--- 2843,2849 ----
err = 1;
}
break;
+
case SWITCH_EXPR:
{
edge e;
*************** tree_verify_flow_info (void)
*** 2998,3003 ****
--- 2894,2900 ----
for (e = bb->succ; e; e = e->succ_next)
e->dest->aux = (void *)0;
}
+
default: ;
}
}
*************** tree_forwarder_block_p (basic_block bb)
*** 3172,3179 ****
return false;
}
! /* Now walk through the statements. We can ignore labels, gotos and
! empty statements. Anything else means this is not a forwarder block. */
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
{
tree stmt = bsi_stmt (bsi);
--- 3069,3076 ----
return false;
}
! /* Now walk through the statements. We can ignore labels, anything else
! means this is not a forwarder block. */
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
{
tree stmt = bsi_stmt (bsi);
*************** tree_forwarder_block_p (basic_block bb)
*** 3181,3187 ****
switch (TREE_CODE (stmt))
{
case LABEL_EXPR:
- case GOTO_EXPR:
break;
default:
--- 3078,3083 ----
*************** thread_jumps (void)
*** 3203,3209 ****
{
edge e, next, last, old;
basic_block bb, dest, tmp;
! tree phi, stmt;
int arg;
bool retval = false;
--- 3099,3105 ----
{
edge e, next, last, old;
basic_block bb, dest, tmp;
! tree phi;
int arg;
bool retval = false;
*************** thread_jumps (void)
*** 3220,3237 ****
if (tree_forwarder_block_p (bb))
continue;
- /* Due to limitations of ir, it is difficult to redirect edge except
- in some simple cases. Given that ir is slowly getting more sane,
- don't invest too much energy into monsters of bsi_insert_on_edge
- type. */
- stmt = last_stmt (bb);
- if (stmt
- && stmt_ends_bb_p (stmt)
- && TREE_CODE (stmt) != GOTO_EXPR
- && TREE_CODE (stmt) != COND_EXPR
- && TREE_CODE (stmt) != SWITCH_EXPR)
- continue;
-
/* This block is now part of a forwarding path, mark it as not
forwardable so that we can detect loops. This bit will be
reset below. */
--- 3116,3121 ----
*************** tree_try_redirect_by_replacing_jump (edg
*** 3365,3371 ****
edge tmp;
block_stmt_iterator b;
tree stmt;
- int flags;
/* Verify that all targets will be TARGET. */
for (tmp = src->succ; tmp; tmp = tmp->succ_next)
--- 3249,3254 ----
*************** tree_try_redirect_by_replacing_jump (edg
*** 3381,3402 ****
stmt = bsi_stmt (b);
if (TREE_CODE (stmt) == COND_EXPR
! || TREE_CODE (stmt) == SWITCH_EXPR
! || (TREE_CODE (stmt) == GOTO_EXPR && target == src->next_bb))
{
! if (target == src->next_bb)
! {
! flags = EDGE_FALLTHRU;
! bsi_remove (&b);
! }
! else
! {
! flags = 0;
! stmt = build1 (GOTO_EXPR, void_type_node, tree_block_label (target));
! bsi_replace (&b, stmt);
! }
e = ssa_redirect_edge (e, target);
! e->flags = flags;
return e;
}
--- 3264,3274 ----
stmt = bsi_stmt (b);
if (TREE_CODE (stmt) == COND_EXPR
! || TREE_CODE (stmt) == SWITCH_EXPR)
{
! bsi_remove (&b);
e = ssa_redirect_edge (e, target);
! e->flags = EDGE_FALLTHRU;
return e;
}
*************** tree_redirect_edge_and_branch_1 (edge e,
*** 3427,3435 ****
label = tree_block_label (dest);
- /* If our block does not end with a GOTO, then create one.
- Otherwise redirect the existing GOTO_EXPR to LABEL. */
-
bsi = bsi_last (bb);
stmt = bsi_end_p (bsi) ? NULL : bsi_stmt (bsi);
flags = 0;
--- 3299,3304 ----
*************** tree_redirect_edge_and_branch_1 (edge e,
*** 3441,3452 ****
? COND_EXPR_THEN (stmt)
: COND_EXPR_ELSE (stmt));
flags = e->flags;
- /* FALLTHRU */
-
- case GOTO_EXPR:
GOTO_DESTINATION (stmt) = label;
break;
case SWITCH_EXPR:
{
tree vec = SWITCH_LABELS (stmt);
--- 3310,3323 ----
? COND_EXPR_THEN (stmt)
: COND_EXPR_ELSE (stmt));
flags = e->flags;
GOTO_DESTINATION (stmt) = label;
break;
+ case GOTO_EXPR:
+ /* No nonabnormal edges should lead from a non-simple goto, and simple
+ ones should be represented implicitly. */
+ abort ();
+
case SWITCH_EXPR:
{
tree vec = SWITCH_LABELS (stmt);
*************** tree_redirect_edge_and_branch_1 (edge e,
*** 3461,3488 ****
}
break;
- case CALL_EXPR:
- case MODIFY_EXPR:
- /* If this block ends with a statement that can alter control flow,
- e.g. via throw or longjmp, then we can't just append to the
- current block. We have to create a new block just to contain
- the goto statement. */
- /* ??? In RTL equivalent we never create new basic blocks here.
- Hopefully this will be just a temporary side case before we switch
- to cfg_layout style mode with no explicit GOTO statements. */
- if (is_ctrl_altering_stmt (stmt))
- {
- bb = tree_split_edge (e);
- bsi = bsi_last (bb);
- e = bb->succ;
- }
- /* FALLTHRU */
-
default:
! /* Otherwise we can just append a goto to this block. */
! stmt = build1 (GOTO_EXPR, void_type_node, label);
! bsi_insert_after (&bsi, stmt, BSI_NEW_STMT);
! e->flags &= ~EDGE_FALLTHRU;
break;
}
--- 3332,3342 ----
}
break;
default:
! /* Otherwise it must be a fallthru edge, and we don't need to
! do anything except for redirecting it. */
! if (!(e->flags & EDGE_FALLTHRU))
! abort ();
break;
}
*************** tree_redirect_edge_and_branch (edge e, b
*** 3508,3521 ****
}
/* Simple wrapper as we always can redirect fallthru edges. */
static basic_block
tree_redirect_edge_and_branch_force (edge e, basic_block dest)
{
- basic_block old = e->src;
e = tree_redirect_edge_and_branch (e, dest);
if (!e)
abort ();
! return e->src == old ? NULL : old;
}
/* Dump FUNCTION_DECL FN to file FILE using FLAGS (see TDF_* in tree.h) */
--- 3362,3376 ----
}
/* Simple wrapper as we always can redirect fallthru edges. */
+
static basic_block
tree_redirect_edge_and_branch_force (edge e, basic_block dest)
{
e = tree_redirect_edge_and_branch (e, dest);
if (!e)
abort ();
!
! return NULL;
}
/* Dump FUNCTION_DECL FN to file FILE using FLAGS (see TDF_* in tree.h) */
Index: tree-flow.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-flow.h,v
retrieving revision 1.1.4.153
diff -c -3 -p -r1.1.4.153 tree-flow.h
*** tree-flow.h 17 Nov 2003 23:18:13 -0000 1.1.4.153
--- tree-flow.h 18 Nov 2003 01:14:26 -0000
*************** extern void cfg_remove_useless_stmts (vo
*** 434,441 ****
extern basic_block tree_split_edge (edge);
extern edge thread_edge (edge, basic_block);
extern basic_block label_to_block (tree);
! extern bool cleanup_cond_expr_graph (basic_block, block_stmt_iterator);
! extern bool cleanup_switch_expr_graph (basic_block, block_stmt_iterator);
extern void tree_optimize_tail_calls (void);
extern basic_block tree_block_forwards_to (basic_block bb);
extern void bsi_insert_on_edge (edge, tree);
--- 434,440 ----
extern basic_block tree_split_edge (edge);
extern edge thread_edge (edge, basic_block);
extern basic_block label_to_block (tree);
! extern bool cleanup_control_expr_graph (basic_block, block_stmt_iterator);
extern void tree_optimize_tail_calls (void);
extern basic_block tree_block_forwards_to (basic_block bb);
extern void bsi_insert_on_edge (edge, tree);
*************** extern edge ssa_redirect_edge (edge, bas
*** 510,515 ****
--- 509,515 ----
extern void set_is_used (tree);
extern bool tree_ssa_useless_type_conversion (tree);
extern void build_dominator_tree (dominance_info);
+ extern void delete_tree_ssa (tree);
extern unsigned int next_ssa_version;
/* In tree-ssa-pre.c */
Index: tree-optimize.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-optimize.c,v
retrieving revision 1.1.4.73
diff -c -3 -p -r1.1.4.73 tree-optimize.c
*** tree-optimize.c 17 Nov 2003 23:39:20 -0000 1.1.4.73
--- tree-optimize.c 18 Nov 2003 01:14:26 -0000
*************** optimize_function_tree (tree fndecl, tre
*** 176,181 ****
--- 176,184 ----
sbitmap_free (vars_to_rename);
}
+ delete_tree_cfg ();
+ delete_tree_ssa (fndecl);
+
/* Re-chain the statements from the blocks. */
{
basic_block bb;
*************** optimize_function_tree (tree fndecl, tre
*** 184,191 ****
FOR_EACH_BB (bb)
append_to_statement_list_force (bb->stmt_list, chain);
}
-
- delete_tree_cfg ();
}
--- 187,192 ----
Index: tree-pretty-print.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-pretty-print.c,v
retrieving revision 1.1.2.61
diff -c -3 -p -r1.1.2.61 tree-pretty-print.c
*** tree-pretty-print.c 17 Nov 2003 12:08:26 -0000 1.1.2.61
--- tree-pretty-print.c 18 Nov 2003 01:14:26 -0000
*************** dump_generic_node (pretty_printer *buffe
*** 734,740 ****
else
first = false;
dump_generic_node (buffer, tsi_stmt (si), spc, flags, true);
- pp_character (buffer, ';');
}
}
break;
--- 734,739 ----
*************** dump_generic_node (pretty_printer *buffe
*** 1282,1287 ****
--- 1281,1287 ----
dump_generic_node (buffer, elt, spc+4, flags, false);
pp_string (buffer, " goto ");
dump_generic_node (buffer, CASE_LABEL (elt), spc+4, flags, true);
+ pp_semicolon (buffer);
}
}
newline_and_indent (buffer, spc+2);
*************** dump_phi_nodes (pretty_printer *buffer,
*** 2150,2155 ****
--- 2150,2187 ----
}
}
+ /* Dump jump to basic block BB that is represented implicitly in the cfg
+ to BUFFER. */
+
+ static void
+ pp_cfg_jump (pretty_printer *buffer, basic_block bb)
+ {
+ pp_string (buffer, "goto <bb ");
+ pp_decimal_int (buffer, bb->index);
+ pp_string (buffer, ">;");
+ }
+
+ /* Dump edges represented implicitly in basic block BB to BUFFER, indented
+ by INDENT spaces, with details given by FLAGS. */
+
+ static void
+ dump_implicit_edges (pretty_printer *buffer, basic_block bb, int indent)
+ {
+ edge e;
+
+ /* If there is a fallthru edge, we may need to add an artificial goto to the
+ dump. */
+ for (e = bb->succ; e; e = e->succ_next)
+ if (e->flags & EDGE_FALLTHRU)
+ break;
+ if (e && e->dest != bb->next_bb)
+ {
+ INDENT (indent);
+ pp_cfg_jump (buffer, e->dest);
+ pp_newline (buffer);
+ }
+ }
+
/* Dumps basic block BB to buffer BUFFER with details described by FLAGS and
indented by INDENT spaces. */
*************** dump_generic_bb_buff (pretty_printer *bu
*** 2182,2187 ****
--- 2214,2221 ----
dump_generic_node (buffer, stmt, curr_indent, flags, true);
pp_newline (buffer);
}
+
+ dump_implicit_edges (buffer, bb, indent);
if (flags & TDF_BLOCKS)
dump_bb_end (buffer, bb, indent);
Index: tree-ssa-dom.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-dom.c,v
retrieving revision 1.1.2.78
diff -c -3 -p -r1.1.2.78 tree-ssa-dom.c
*** tree-ssa-dom.c 16 Nov 2003 11:00:40 -0000 1.1.2.78
--- tree-ssa-dom.c 18 Nov 2003 01:14:26 -0000
*************** thread_jumps_walk_stmts (struct dom_walk
*** 1013,1024 ****
if (TREE_CODE (stmt) == COND_EXPR)
{
COND_EXPR_COND (stmt) = cached_lhs;
! cfg_altered = cleanup_cond_expr_graph (bb, si);
}
else if (TREE_CODE (stmt) == SWITCH_EXPR)
{
SWITCH_COND (stmt) = cached_lhs;
! cfg_altered = cleanup_switch_expr_graph (bb, si);
}
continue;
--- 1013,1024 ----
if (TREE_CODE (stmt) == COND_EXPR)
{
COND_EXPR_COND (stmt) = cached_lhs;
! cfg_altered = cleanup_control_expr_graph (bb, si);
}
else if (TREE_CODE (stmt) == SWITCH_EXPR)
{
SWITCH_COND (stmt) = cached_lhs;
! cfg_altered = cleanup_control_expr_graph (bb, si);
}
continue;
*************** optimize_stmt (block_stmt_iterator si, v
*** 2134,2144 ****
etc. */
if (ann->modified)
{
! if (TREE_CODE (stmt) == COND_EXPR)
! cfg_altered |= cleanup_cond_expr_graph (bb_for_stmt (stmt), si);
!
! if (TREE_CODE (stmt) == SWITCH_EXPR)
! cfg_altered |= cleanup_switch_expr_graph (bb_for_stmt (stmt), si);
}
return may_have_exposed_new_symbols;
--- 2134,2142 ----
etc. */
if (ann->modified)
{
! if (TREE_CODE (stmt) == COND_EXPR
! || TREE_CODE (stmt) == SWITCH_EXPR)
! cfg_altered |= cleanup_control_expr_graph (bb_for_stmt (stmt), si);
}
return may_have_exposed_new_symbols;
Index: tree-ssa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa.c,v
retrieving revision 1.1.4.154
diff -c -3 -p -r1.1.4.154 tree-ssa.c
*** tree-ssa.c 18 Nov 2003 00:17:51 -0000 1.1.4.154
--- tree-ssa.c 18 Nov 2003 01:14:26 -0000
*************** static void rewrite_initialize_block (st
*** 177,183 ****
static void rewrite_walk_stmts (struct dom_walk_data *, basic_block, tree);
static void rewrite_add_phi_arguments (struct dom_walk_data *,
basic_block, tree);
- static void delete_tree_ssa (tree);
static void mark_def_sites (struct dom_walk_data *walk_data,
basic_block bb,
tree parent_block_last_stmt ATTRIBUTE_UNUSED);
--- 177,182 ----
*************** rewrite_out_of_ssa (tree fndecl, enum tr
*** 2494,2500 ****
}
/* Flush out flow graph and SSA data. */
- delete_tree_ssa (fndecl);
delete_var_map (map);
timevar_pop (TV_TREE_SSA_TO_NORMAL);
}
--- 2493,2498 ----
*************** init_tree_ssa (void)
*** 2832,2838 ****
/* Deallocate memory associated with SSA data structures for FNDECL. */
! static void
delete_tree_ssa (tree fndecl)
{
size_t i;
--- 2830,2836 ----
/* Deallocate memory associated with SSA data structures for FNDECL. */
! void
delete_tree_ssa (tree fndecl)
{
size_t i;
*************** delete_tree_ssa (tree fndecl)
*** 2841,2850 ****
walk_tree (&DECL_SAVED_TREE (fndecl), remove_annotations_r, NULL, NULL);
/* Remove annotations from every referenced variable. */
! for (i = 0; i < num_referenced_vars; i++)
! referenced_var (i)->common.ann = NULL;
- referenced_vars = NULL;
global_var = NULL_TREE;
call_clobbered_vars = NULL;
}
--- 2839,2851 ----
walk_tree (&DECL_SAVED_TREE (fndecl), remove_annotations_r, NULL, NULL);
/* Remove annotations from every referenced variable. */
! if (referenced_vars)
! {
! for (i = 0; i < num_referenced_vars; i++)
! referenced_var (i)->common.ann = NULL;
! referenced_vars = NULL;
! }
global_var = NULL_TREE;
call_clobbered_vars = NULL;
}