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,
here is the version that passes regtesting on i686.
Zdenek
Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-cfg.c,v
retrieving revision 1.1.4.225
diff -c -3 -p -r1.1.4.225 tree-cfg.c
*** tree-cfg.c 25 Nov 2003 05:09:07 -0000 1.1.4.225
--- tree-cfg.c 29 Nov 2003 21:52:01 -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;
}
}
*************** cfg_remove_useless_stmts_bb (basic_block
*** 1284,1365 ****
{
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;
! val = NULL_TREE;
! }
! if (var && ! TREE_CONSTANT (val))
! {
! ann = var_ann (val);
! if (!ann
! || ann->may_aliases
! || TREE_ADDRESSABLE (val))
! {
! val = NULL_TREE;
! var = NULL_TREE;
! }
! }
! }
! /* Ignore floating point variables, since comparison behaves weird for
! them. */
! if (var
! && FLOAT_TYPE_P (TREE_TYPE (var)))
! {
! var = NULL_TREE;
! val = 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. */
--- 1307,1370 ----
{
block_stmt_iterator bsi;
tree stmt = NULL_TREE;
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)))
! return;
! 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);
! }
! 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 weird 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
*** 1378,1442 ****
&& (TREE_OPERAND (stmt, 0) == var
|| TREE_OPERAND (stmt, 0) == val
|| TREE_CODE (TREE_OPERAND (stmt, 1)) == VA_ARG_EXPR)))
! {
! var = NULL_TREE;
! val = 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. */
--- 1383,1392 ----
&& (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)
*** 1603,1626 ****
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;
--- 1553,1568 ----
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)
*** 1647,1692 ****
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;
--- 1589,1641 ----
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,
*** 1705,1778 ****
else
taken_edge = bb->succ;
! if (taken_edge->flags & EDGE_TRUE_VALUE)
! bsi_replace (&bsi, COND_EXPR_THEN (cond_expr), false);
! else if (taken_edge->flags & EDGE_FALSE_VALUE)
! bsi_replace (&bsi, COND_EXPR_ELSE (cond_expr), false);
! 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, false);
return retval;
}
--- 1654,1661 ----
else
taken_edge = bb->succ;
! bsi_remove (&bsi);
! taken_edge->flags = EDGE_FALLTHRU;
return retval;
}
*************** stmt_ends_bb_p (tree t)
*** 2410,2415 ****
--- 2293,2378 ----
return is_ctrl_stmt (t) || is_ctrl_altering_stmt (t);
}
+ /* Add gotos that used to be represented implicitly in cfg. */
+
+ void
+ disband_implicit_edges (void)
+ {
+ basic_block bb;
+ block_stmt_iterator last;
+ edge e;
+ tree stmt;
+
+ FOR_EACH_BB (bb)
+ {
+ last = bsi_last (bb);
+ stmt = last_stmt (bb);
+
+ if (stmt && TREE_CODE (stmt) == COND_EXPR)
+ {
+ /* Remove superfluous gotos from COND_EXPR branches. Moved
+ from cfg_remove_useless_stmts here since it violates the
+ invariants for tree--cfg correspondence and thus fits better
+ here where we do it anyway. */
+
+ for (e = bb->succ; e; e = e->succ_next)
+ {
+ if (e->dest != bb->next_bb)
+ continue;
+
+ if (e->flags & EDGE_TRUE_VALUE)
+ COND_EXPR_THEN (stmt) = build_empty_stmt ();
+ else if (e->flags & EDGE_FALSE_VALUE)
+ COND_EXPR_ELSE (stmt) = build_empty_stmt ();
+ else
+ abort ();
+ }
+
+ continue;
+ }
+
+ if (stmt && TREE_CODE (stmt) == RETURN_EXPR)
+ {
+ /* Remove the RETURN_EXPR if we may fallthru to the exit
+ instead. */
+ if (!bb->succ
+ || bb->succ->succ_next
+ || bb->succ->dest != EXIT_BLOCK_PTR)
+ abort ();
+
+ if (bb->next_bb == EXIT_BLOCK_PTR
+ && !TREE_OPERAND (stmt, 0))
+ {
+ bsi_remove (&last);
+ bb->succ->flags |= EDGE_FALLTHRU;
+ }
+ continue;
+ }
+
+ /* There can be no fallthru edge if the last statement is a control
+ one. */
+ if (stmt && is_ctrl_stmt (stmt))
+ continue;
+
+ /* 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)
*** 2417,2422 ****
--- 2380,2386 ----
{
if (n_basic_blocks > 0)
free_blocks_annotations ();
+
free_basic_block_vars (0);
tree_bb_root = NULL;
}
*************** tree_find_edge_insert_loc (edge e, block
*** 2660,2667 ****
return false;
}
! /* If the source has one successor and the edge is not abnormal,
! insert there. Except for the entry block. */
src = e->src;
if ((e->flags & EDGE_ABNORMAL) == 0
&& src->succ->succ_next == NULL
--- 2624,2632 ----
return false;
}
! /* If the source has one successor, the edge is not abnormal and
! the last statement does not end a basic block, insert there.
! Except for the entry block. */
src = e->src;
if ((e->flags & EDGE_ABNORMAL) == 0
&& src->succ->succ_next == NULL
*************** tree_find_edge_insert_loc (edge e, block
*** 2671,2679 ****
if (bsi_end_p (*bsi))
return true;
- /* Make sure we insert before a final goto statement. */
tmp = bsi_stmt (*bsi);
! return !is_ctrl_stmt (tmp);
}
/* Otherwise, create a new basic block, and split this edge. */
--- 2636,2644 ----
if (bsi_end_p (*bsi))
return true;
tmp = bsi_stmt (*bsi);
! if (!stmt_ends_bb_p (tmp))
! return true;
}
/* Otherwise, create a new basic block, and split this edge. */
*************** basic_block
*** 2773,2779 ****
tree_split_edge (edge edge_in)
{
basic_block new_bb, after_bb, dest;
! edge new_edge;
tree phi;
int i, num_elem;
--- 2738,2744 ----
tree_split_edge (edge edge_in)
{
basic_block new_bb, after_bb, dest;
! edge new_edge, e;
tree phi;
int i, num_elem;
*************** tree_split_edge (edge edge_in)
*** 2786,2851 ****
/* Place the new block in the block list. Try to keep the new block
near its "logical" location. This is of most help to humans looking
at debugging dumps. */
- if (edge_in->flags & EDGE_FALLTHRU)
- after_bb = edge_in->src;
- else
- {
- edge e;
! for (e = dest->pred; e ; e = e->pred_next)
! if (e->flags & EDGE_FALLTHRU)
! break;
! 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. */
--- 2751,2771 ----
/* Place the new block in the block list. Try to keep the new block
near its "logical" location. This is of most help to humans looking
at debugging dumps. */
! for (e = dest->pred; e; e = e->pred_next)
! if (e->src->next_bb == dest)
! break;
! if (!e)
! after_bb = dest->prev_bb;
! else
! after_bb = edge_in->src;
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)
*** 2890,2895 ****
--- 2810,2816 ----
basic_block bb;
block_stmt_iterator bsi;
tree stmt;
+ edge e;
if (ENTRY_BLOCK_PTR->stmt_list)
{
*************** tree_verify_flow_info (void)
*** 2902,2910 ****
err = 1;
}
FOR_EACH_BB (bb)
{
- edge e;
bool found_ctrl_stmt = false;
tree phi;
int i;
--- 2823,2837 ----
err = 1;
}
+ 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)
*** 2998,3012 ****
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:
--- 2925,2943 ----
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)
*** 3045,3067 ****
}
}
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
{
--- 2976,2987 ----
}
}
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)
*** 3088,3093 ****
--- 3008,3014 ----
}
}
break;
+
case RETURN_EXPR:
if (!bb->succ || bb->succ->succ_next
|| (bb->succ->flags & (EDGE_FALLTHRU | EDGE_ABNORMAL
*************** tree_verify_flow_info (void)
*** 3102,3107 ****
--- 3023,3029 ----
err = 1;
}
break;
+
case SWITCH_EXPR:
{
edge e;
*************** tree_verify_flow_info (void)
*** 3152,3157 ****
--- 3074,3080 ----
for (e = bb->succ; e; e = e->succ_next)
e->dest->aux = (void *)0;
}
+
default: ;
}
}
*************** tree_forwarder_block_p (basic_block bb)
*** 3326,3333 ****
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);
--- 3249,3256 ----
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)
*** 3335,3341 ****
switch (TREE_CODE (stmt))
{
case LABEL_EXPR:
- case GOTO_EXPR:
break;
default:
--- 3258,3263 ----
*************** thread_jumps (void)
*** 3357,3363 ****
{
edge e, next, last, old;
basic_block bb, dest, tmp;
! tree phi, stmt;
int arg;
bool retval = false;
--- 3279,3285 ----
{
edge e, next, last, old;
basic_block bb, dest, tmp;
! tree phi;
int arg;
bool retval = false;
*************** thread_jumps (void)
*** 3374,3391 ****
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. */
--- 3296,3301 ----
*************** tree_try_redirect_by_replacing_jump (edg
*** 3519,3525 ****
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)
--- 3429,3434 ----
*************** tree_try_redirect_by_replacing_jump (edg
*** 3535,3556 ****
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, false);
! }
e = ssa_redirect_edge (e, target);
! e->flags = flags;
return e;
}
--- 3444,3454 ----
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,
*** 3581,3589 ****
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;
--- 3479,3484 ----
*************** tree_redirect_edge_and_branch_1 (edge e,
*** 3595,3606 ****
? 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);
--- 3490,3503 ----
? 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,
*** 3615,3642 ****
}
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;
}
--- 3512,3522 ----
}
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
*** 3662,3675 ****
}
/* 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) */
--- 3542,3556 ----
}
/* 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.160
diff -c -3 -p -r1.1.4.160 tree-flow.h
*** tree-flow.h 25 Nov 2003 05:09:08 -0000 1.1.4.160
--- tree-flow.h 29 Nov 2003 21:52:01 -0000
*************** extern void bsi_replace (const block_stm
*** 408,413 ****
--- 408,414 ----
/* In tree-cfg.c */
extern void build_tree_cfg (tree *);
extern void delete_tree_cfg (void);
+ extern void disband_implicit_edges (void);
extern bool stmt_ends_bb_p (tree);
extern bool is_ctrl_stmt (tree);
extern bool is_ctrl_altering_stmt (tree);
*************** extern void cfg_remove_useless_stmts (vo
*** 436,443 ****
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);
--- 437,443 ----
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
*** 513,518 ****
--- 513,519 ----
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 (void);
extern unsigned int highest_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.80
diff -c -3 -p -r1.1.4.80 tree-optimize.c
*** tree-optimize.c 29 Nov 2003 12:43:10 -0000 1.1.4.80
--- tree-optimize.c 29 Nov 2003 21:52:01 -0000
*************** Boston, MA 02111-1307, USA. */
*** 45,50 ****
--- 45,52 ----
#include "tree-mudflap.h"
#include "ggc.h"
+ static void tree_ssa_finish (tree *);
+
/* Rewrite a function tree to the SSA form and perform the SSA-based
optimizations on it. */
*************** optimize_function_tree (tree fndecl, tre
*** 190,207 ****
sbitmap_free (vars_to_rename);
}
! /* Re-chain the statements from the blocks. */
! {
! basic_block bb;
! *chain = NULL;
! FOR_EACH_BB (bb)
append_to_statement_list_force (bb->stmt_list, chain);
! }
delete_tree_cfg ();
}
-
/* Called to move the SAVE_EXPRs for parameter declarations in a
nested function into the nested function. DATA is really the
--- 192,225 ----
sbitmap_free (vars_to_rename);
}
! tree_ssa_finish (chain);
! }
!
! /* Do the actions requiered to finish with tree-ssa optimization
! passes. Return the final chain of statements in CHAIN. */
!
! static void
! tree_ssa_finish (tree *chain)
! {
! basic_block bb;
! /* Emit gotos for implicit jumps. */
! disband_implicit_edges ();
!
! /* Remove the ssa structures. Do it here since this includes statement
! annotations that need to be intact during disband_implicit_edges. */
! delete_tree_ssa ();
!
! /* Re-chain the statements from the blocks. */
! *chain = NULL;
! FOR_EACH_BB (bb)
! {
append_to_statement_list_force (bb->stmt_list, chain);
! }
+ /* And get rid of the cfg. */
delete_tree_cfg ();
}
/* Called to move the SAVE_EXPRs for parameter declarations in a
nested function into the nested function. DATA is really the
Index: tree-pretty-print.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-pretty-print.c,v
retrieving revision 1.1.2.64
diff -c -3 -p -r1.1.2.64 tree-pretty-print.c
*** tree-pretty-print.c 22 Nov 2003 15:01:38 -0000 1.1.2.64
--- tree-pretty-print.c 29 Nov 2003 21:52:01 -0000
*************** dump_generic_node (pretty_printer *buffe
*** 1281,1286 ****
--- 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,
*** 2144,2149 ****
--- 2145,2182 ----
}
}
+ /* 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
*** 2176,2181 ****
--- 2209,2216 ----
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.88
diff -c -3 -p -r1.1.2.88 tree-ssa-dom.c
*** tree-ssa-dom.c 26 Nov 2003 03:22:23 -0000 1.1.2.88
--- tree-ssa-dom.c 29 Nov 2003 21:52:01 -0000
*************** thread_jumps_walk_stmts (struct dom_walk
*** 1159,1170 ****
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;
--- 1159,1170 ----
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,
*** 2291,2301 ****
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;
--- 2291,2299 ----
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.168
diff -c -3 -p -r1.1.4.168 tree-ssa.c
*** tree-ssa.c 28 Nov 2003 15:38:47 -0000 1.1.4.168
--- tree-ssa.c 29 Nov 2003 21:52:01 -0000
*************** static void rewrite_initialize_block (st
*** 179,185 ****
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 (void);
static void mark_def_sites (struct dom_walk_data *walk_data,
basic_block bb,
tree parent_block_last_stmt ATTRIBUTE_UNUSED);
--- 179,184 ----
*************** rewrite_out_of_ssa (tree fndecl, enum tr
*** 2628,2634 ****
}
/* Flush out flow graph and SSA data. */
- delete_tree_ssa ();
delete_var_map (map);
timevar_pop (TV_TREE_SSA_TO_NORMAL);
}
--- 2627,2632 ----
*************** init_tree_ssa (void)
*** 2964,2970 ****
/* Deallocate memory associated with SSA data structures for FNDECL. */
! static void
delete_tree_ssa (void)
{
size_t i;
--- 2962,2968 ----
/* Deallocate memory associated with SSA data structures for FNDECL. */
! void
delete_tree_ssa (void)
{
size_t i;
*************** delete_tree_ssa (void)
*** 2977,2988 ****
bsi_stmt (bsi)->common.ann = NULL;
/* Remove annotations from every referenced variable. */
! for (i = 0; i < num_referenced_vars; i++)
! referenced_var (i)->common.ann = NULL;
fini_ssanames ();
- referenced_vars = NULL;
global_var = NULL_TREE;
call_clobbered_vars = NULL;
}
--- 2975,2989 ----
bsi_stmt (bsi)->common.ann = 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;
! }
fini_ssanames ();
global_var = NULL_TREE;
call_clobbered_vars = NULL;
}