This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [tree-ssa] Get rid of LOOP_EXPRs
Hello,
here is the patch for the regressions removing LOOP_EXPRs would
cause.
> >2) In the following testcase it happens that start of BIND_EXPR is the last
> > statement of a block; when bsi_insert_after is called on it,
> > statement is inserted after end of BIND_EXPR block, which is far away
> > from the position where it should be, thus causing misscompilation.
> > Also reproducible with tree-ssa-branch using explicit gotos, testcase
this in fact turned out to be a problem with bsi_next_in_block that in
this case returned the BIND_EXPR as a statement.
The patch also makes the BIND_EXPRs to start/end basic blocks as Jeff
suggested.
Zdenek
* tree-cfg.c (make_bind_expr_blocks, make_blocks, stmt_ends_bb_p):
Create new block with start of BIND_EXPR.
(remove_unreachable_block): Work for empty blocks.
(remove_bb): Don't remove BIND_EXPRs with reachable inner parts.
(debug_tree_bb_n): New.
(bsi_next_in_bb): Work correctly when the block ends with start
of BIND_EXPR.
Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-cfg.c,v
retrieving revision 1.1.4.154
diff -c -3 -p -r1.1.4.154 tree-cfg.c
*** tree-cfg.c 21 Aug 2003 17:23:51 -0000 1.1.4.154
--- tree-cfg.c 22 Aug 2003 17:16:15 -0000
*************** static void create_block_annotation (bas
*** 85,98 ****
static void free_blocks_annotations (void);
static void clear_blocks_annotations (void);
static basic_block make_blocks (tree *, tree, tree, basic_block, tree);
static void make_loop_expr_blocks (tree *, basic_block, tree);
static void make_cond_expr_blocks (tree *, tree, basic_block, tree);
static void make_catch_expr_blocks (tree *, tree, basic_block, tree);
static void make_eh_filter_expr_blocks (tree *, tree, basic_block, tree);
static void make_try_expr_blocks (tree *, tree, basic_block, tree);
static void make_switch_expr_blocks (tree *, tree, basic_block, tree);
! static basic_block make_bind_expr_blocks (tree *, tree, basic_block, tree,
! tree);
static inline void add_stmt_to_bb (tree *, basic_block, tree);
static inline void append_stmt_to_bb (tree *, basic_block, tree);
static inline void set_parent_stmt (tree *, tree);
--- 85,97 ----
static void free_blocks_annotations (void);
static void clear_blocks_annotations (void);
static basic_block make_blocks (tree *, tree, tree, basic_block, tree);
static void make_loop_expr_blocks (tree *, basic_block, tree);
static void make_cond_expr_blocks (tree *, tree, basic_block, tree);
static void make_catch_expr_blocks (tree *, tree, basic_block, tree);
static void make_eh_filter_expr_blocks (tree *, tree, basic_block, tree);
static void make_try_expr_blocks (tree *, tree, basic_block, tree);
static void make_switch_expr_blocks (tree *, tree, basic_block, tree);
! static void make_bind_expr_blocks (tree *, tree, basic_block, tree);
static inline void add_stmt_to_bb (tree *, basic_block, tree);
static inline void append_stmt_to_bb (tree *, basic_block, tree);
static inline void set_parent_stmt (tree *, tree);
*************** make_blocks (tree *first_p, tree next_bl
*** 450,510 ****
make_try_expr_blocks (stmt_p, next_block_link, bb, scope);
else if (code == BIND_EXPR)
{
- int num_blocks_before;
- basic_block last_bb;
-
- /* BIND_EXPR nodes are a special case. We neither force a new
- block for their bodies, nor force a new block after creating
- the subgraph. On return from make_bind_expr_blocks, LAST_BB
- will be the last basic block of the BIND_EXPR's subgraph. We
- point STMT to LAST_BB's last statement to determine if we
- should start a new block or not. */
- num_blocks_before = n_basic_blocks;
assign_vars_to_scope (stmt);
get_stmt_ann (stmt)->scope_level =
get_stmt_ann (scope)->scope_level + 1;
! last_bb = make_bind_expr_blocks (stmt_p, next_block_link, bb,
! parent_stmt, stmt);
! if (last_bb)
! {
! bb = last_bb;
! stmt = last_stmt (bb);
! }
!
! /* FIXME. Obscene hack to work around iterator limitations. If
! during processing of the BIND_EXPR body we were forced to
! create new blocks (i.e., the BIND_EXPR body contains control
! flow structures), then force the creation of a new basic block
! for the next iteration. This avoids the following problem
! (assume that all the Si statements are regular GIMPLE
! statements):
!
! 1 s1; <-- BLOCK #0
! 2 {
! 3 s2;
! 4 s3;
! 5 if ()
! 6 s4; <-- BLOCK #1
! 7 s5; <-- BLOCK #2
! 8 }
! 9 s6;
!
! Since s5 and s6 are two regular statements, they could both be
! in block #2. However, if we started an iterator on block #2,
! the iterator would have no way of knowing how to go from
! statement s5 to statement s6 because the iterator was started
! in the middle of its BIND_EXPR's body, so bsi_step_in_bb() has
! not enough context to determine how to get to s6. */
! if (n_basic_blocks > num_blocks_before)
! {
! start_new_block = true;
!
! /* If we are starting the new block just to work around
! iterator limitations, keep track of it. */
! if (!stmt || !stmt_ends_bb_p (stmt))
! cfg_stats.num_failed_bind_expr_merges++;
! }
}
/* If STMT is a basic block terminator, set START_NEW_BLOCK for the
--- 444,454 ----
make_try_expr_blocks (stmt_p, next_block_link, bb, scope);
else if (code == BIND_EXPR)
{
assign_vars_to_scope (stmt);
get_stmt_ann (stmt)->scope_level =
get_stmt_ann (scope)->scope_level + 1;
! make_bind_expr_blocks (stmt_p, next_block_link, bb, stmt);
}
/* If STMT is a basic block terminator, set START_NEW_BLOCK for the
*************** make_switch_expr_blocks (tree *switch_e_
*** 788,798 ****
}
! /* Create the blocks for the BIND_EXPR node pointed by BIND_P. In contrast
! with the other make_*_blocks functions, this function will not start a
! new basic block for the statements in the BIND_EXPR body. Rather, the
! statements in the BIND_EXPR body are added to the block ENTRY and use
! the same PARENT_STMT.
NEXT_BLOCK_LINK is the first statement of the successor basic block for
the block holding *BIND_P. If *BIND_P is the last statement inside a
--- 682,688 ----
}
! /* Create the blocks for the BIND_EXPR node pointed by BIND_P.
NEXT_BLOCK_LINK is the first statement of the successor basic block for
the block holding *BIND_P. If *BIND_P is the last statement inside a
*************** make_switch_expr_blocks (tree *switch_e_
*** 801,822 ****
ENTRY is the block whose last statement is *SWITCH_E_P.
- Return the last basic block added to the BIND_EXPR's subgraph. This
- allows the caller to determine whether a new block should be started or
- not.
-
SCOPE is the BIND_EXPR node holding *BIND_P (in fact it is equal to
*BIND_P). */
! static basic_block
make_bind_expr_blocks (tree *bind_p, tree next_block_link,
! basic_block entry, tree parent_stmt, tree scope)
{
tree_stmt_iterator si;
! tree bind = *bind_p;
! /* Determine NEXT_BLOCK_LINK for statements inside the BIND_EXPR
! body. */
si = tsi_start (bind_p);
tsi_next (&si);
--- 691,708 ----
ENTRY is the block whose last statement is *SWITCH_E_P.
SCOPE is the BIND_EXPR node holding *BIND_P (in fact it is equal to
*BIND_P). */
! static void
make_bind_expr_blocks (tree *bind_p, tree next_block_link,
! basic_block entry, tree scope)
{
tree_stmt_iterator si;
! tree expr = *bind_p;
! entry->flags |= BB_CONTROL_EXPR;
! /* Determine NEXT_BLOCK_LINK for statements inside the body. */
si = tsi_start (bind_p);
tsi_next (&si);
*************** make_bind_expr_blocks (tree *bind_p, tre
*** 827,840 ****
if (!tsi_end_p (si) && tsi_stmt (si) != NULL_TREE)
next_block_link = *(tsi_container (si));
! /* By passing the current block ENTRY to make_blocks, we will keep adding
! statements to ENTRY until we find a block terminating statement inside
! the body of the BIND_EXPR. On return from make_blocks, our caller
! will start a new basic block only if the body of the BIND_EXPR node
! ends with a block terminating statement. */
! STRIP_CONTAINERS (bind);
! return make_blocks (&BIND_EXPR_BODY (bind), next_block_link, parent_stmt,
! entry, scope);
}
--- 713,720 ----
if (!tsi_end_p (si) && tsi_stmt (si) != NULL_TREE)
next_block_link = *(tsi_container (si));
! STRIP_CONTAINERS (expr);
! make_blocks (&BIND_EXPR_BODY (expr), next_block_link, expr, NULL, scope);
}
*************** remove_unreachable_block (basic_block bb
*** 1903,1915 ****
The entry block (line 2) is unreachable but its body isn't. */
find_contained_blocks (last_p, subblocks, &dummy_p);
if (blocks_unreachable_p (subblocks))
{
remove_blocks (subblocks);
}
else
{
-
/* If we have reachable subblocks, then we can not remove
control statements. But we also can't simply leave them
as-is since they may refer to SSA variables which will
--- 1746,1759 ----
The entry block (line 2) is unreachable but its body isn't. */
find_contained_blocks (last_p, subblocks, &dummy_p);
+ /* Always include the removed block. */
+ bitmap_set_bit (subblocks, bb->index);
if (blocks_unreachable_p (subblocks))
{
remove_blocks (subblocks);
}
else
{
/* If we have reachable subblocks, then we can not remove
control statements. But we also can't simply leave them
as-is since they may refer to SSA variables which will
*************** remove_bb (basic_block bb, int remove_st
*** 1994,2000 ****
set_bb_for_stmt (stmt, NULL);
if (remove_stmt_flags)
{
! int ctrl_stmt = is_ctrl_stmt (stmt);
loc.file = get_filename (stmt);
loc.line = get_lineno (stmt);
--- 1838,1844 ----
set_bb_for_stmt (stmt, NULL);
if (remove_stmt_flags)
{
! int ctrl_stmt = is_ctrl_stmt (stmt) || TREE_CODE (stmt) == BIND_EXPR;
loc.file = get_filename (stmt);
loc.line = get_lineno (stmt);
*************** debug_tree_bb (basic_block bb)
*** 2859,2864 ****
--- 2658,2673 ----
}
+ /* Dump a basic block N on stderr. */
+
+ basic_block
+ debug_tree_bb_n (int n)
+ {
+ dump_tree_bb (stderr, "", BASIC_BLOCK (n), 0);
+
+ return BASIC_BLOCK (n);
+ }
+
/* Dump the CFG on stderr.
FLAGS are the same used by the tree dumping functions
*************** stmt_ends_bb_p (tree t)
*** 3293,3299 ****
return (code == COND_EXPR
|| code == SWITCH_EXPR
! || code == LOOP_EXPR
|| code == EH_FILTER_EXPR
|| code == TRY_CATCH_EXPR
|| code == TRY_FINALLY_EXPR
--- 3093,3100 ----
return (code == COND_EXPR
|| code == SWITCH_EXPR
! || code == LOOP_EXPR
! || code == BIND_EXPR
|| code == EH_FILTER_EXPR
|| code == TRY_CATCH_EXPR
|| code == TRY_FINALLY_EXPR
*************** bsi_next_in_bb (block_stmt_iterator *i,
*** 3540,3547 ****
}
else
bind.context = tmp;
- *i = bind;
}
}
if (i->tp == NULL && i->context != NULL_TREE)
--- 3320,3327 ----
}
else
bind.context = tmp;
}
+ *i = bind;
}
if (i->tp == NULL && i->context != NULL_TREE)