This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [tree-ssa] Another EH cfg cleanup PATCH
- From: Jason Merrill <jason at redhat dot com>
- To: law at redhat dot com
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Fri, 30 May 2003 11:40:03 -0400
- Subject: Re: [tree-ssa] Another EH cfg cleanup PATCH
- References: <200305301527.h4UFR91S018122@speedy.slc.redhat.com>
On Fri, 30 May 2003 09:27:09 -0600, law@redhat.com wrote:
> In message <wvlof1l400i.fsf@prospero.boston.redhat.com>, Jason Merrill writes:
> >On Thu, 29 May 2003 19:22:36 -0600, law@redhat.com wrote:
> >
> >> And how would I identify such TRY_CATCH_EXPRs? By the lack of a
> >> CATCH_EXPR in operand 1 of the TRY_CATCH_EXPR?
> >
> >More or less, though you also have to check for EH_FILTER_EXPR, and the
> >CATCH_EXPR might be wrapped in a COMPOUND_EXPR.
> Yup. That's already handled as well. It fell right out since I copied the
> code to detect cleanups from elsewhere. In all it was pretty simple once
> I decided that it had to be a two step process. You can't wire up the
> edge when building blocks (the parent cleanup will not have any blocks) and
> you don't have the nice nesting info when wiring up edges (well, maybe it
> exists via parent_stmt).
>
> So the "obvious" solution is to record the tree node for the parent cleanup
> when building blocks since we have the nesting structure handily available
> and wire up the edge when building all the special edges.
Yep, basically the same deal as finding the edges for calls.
> >The simplest thing would
> >be to use get_eh_region_type from the patch I sent you.
> Given that I seem to have lost it, could you resend it so I can see if
> I'm missing anything obvious?
This patch also has a few other miscellaneous cleanups.
*** except.c.~1~ 2003-05-29 16:20:30.000000000 -0400
--- except.c 2003-05-26 16:49:38.000000000 -0400
*************** struct eh_region GTY(())
*** 132,148 ****
bitmap aka;
/* Each region does exactly one thing. */
! enum eh_region_type
! {
! ERT_UNKNOWN = 0,
! ERT_CLEANUP,
! ERT_TRY,
! ERT_CATCH,
! ERT_ALLOWED_EXCEPTIONS,
! ERT_MUST_NOT_THROW,
! ERT_THROW,
! ERT_FIXUP
! } type;
/* Holds the action to perform based on the preceding type. */
union eh_region_u {
--- 132,138 ----
bitmap aka;
/* Each region does exactly one thing. */
! enum eh_region_type type;
/* Holds the action to perform based on the preceding type. */
union eh_region_u {
*************** void
*** 538,546 ****
expand_eh_handler (handler)
tree handler;
{
! tree inner = handler;
! while (TREE_CODE (inner) == COMPOUND_EXPR)
! inner = TREE_OPERAND (inner, 0);
switch (TREE_CODE (inner))
{
--- 528,534 ----
expand_eh_handler (handler)
tree handler;
{
! tree inner = expr_first (handler);
switch (TREE_CODE (inner))
{
*** except.h.~1~ 2003-05-29 16:20:30.000000000 -0400
--- except.h 2003-05-26 16:49:38.000000000 -0400
*************** struct eh_status;
*** 32,37 ****
--- 32,48 ----
/* Internal structure describing a region. */
struct eh_region;
+ enum eh_region_type {
+ ERT_UNKNOWN = 0,
+ ERT_CLEANUP,
+ ERT_TRY,
+ ERT_CATCH,
+ ERT_ALLOWED_EXCEPTIONS,
+ ERT_MUST_NOT_THROW,
+ ERT_THROW,
+ ERT_FIXUP
+ };
+
/* Test: is exception handling turned on? */
extern int doing_eh PARAMS ((int));
*** tree-cfg.c.~1~ 2003-05-29 16:20:30.000000000 -0400
--- tree-cfg.c 2003-05-26 16:54:02.000000000 -0400
*************** static void make_case_label_edges PARAMS
*** 102,107 ****
--- 102,108 ----
/* Various helpers. */
static basic_block successor_block PARAMS ((basic_block));
static basic_block first_exec_block PARAMS ((tree *));
+ static basic_block last_exec_block PARAMS ((tree *));
static tree *first_exec_stmt PARAMS ((tree *));
static basic_block switch_parent PARAMS ((basic_block));
static inline bool stmt_starts_bb_p PARAMS ((tree, tree));
*************** make_cond_expr_blocks (cond_p, next_bloc
*** 506,511 ****
--- 507,529 ----
make_blocks (&COND_EXPR_ELSE (cond), next_block_link, cond, NULL);
}
+ static enum eh_region_type
+ get_eh_region_type (tree stmt)
+ {
+ if (TREE_CODE (stmt) == TRY_FINALLY_EXPR)
+ return ERT_CLEANUP;
+ if (TREE_CODE (stmt) == TRY_CATCH_EXPR)
+ {
+ tree handler = TREE_OPERAND (stmt, 1);
+ if (TREE_CODE (expr_first (handler)) == CATCH_EXPR)
+ return ERT_TRY;
+ if (TREE_CODE (handler) == EH_FILTER_EXPR)
+ return ERT_ALLOWED_EXCEPTIONS;
+ return ERT_CLEANUP;
+ }
+ abort ();
+ }
+
/* Create the blocks for the TRY_CATCH_EXPR or TRY_FINALLY_EXPR node
pointed by expr_p. */
*************** make_try_expr_blocks (expr_p, next_block
*** 535,541 ****
/* We need to keep a stack of the handler expressions of TRY_CATCH_EXPR
and TRY_FINALLY nodes so that we know when throwing statements should
end a basic block. */
! VARRAY_PUSH_TREE (eh_stack, TREE_OPERAND (expr, 1));
/* Make blocks for the TRY block. */
make_blocks (&TREE_OPERAND (expr, 0), next_block_link, expr, NULL);
--- 553,559 ----
/* We need to keep a stack of the handler expressions of TRY_CATCH_EXPR
and TRY_FINALLY nodes so that we know when throwing statements should
end a basic block. */
! VARRAY_PUSH_TREE (eh_stack, expr);
/* Make blocks for the TRY block. */
make_blocks (&TREE_OPERAND (expr, 0), next_block_link, expr, NULL);
*************** make_try_expr_blocks (expr_p, next_block
*** 545,550 ****
--- 563,576 ----
/* Make blocks for the handler itself. */
make_blocks (&TREE_OPERAND (expr, 1), next_block_link, expr, NULL);
+
+ if (get_eh_region_type (expr) == ERT_CLEANUP
+ && VARRAY_ACTIVE_SIZE (eh_stack))
+ {
+ tree region = VARRAY_TOP_TREE (eh_stack);
+ if (get_eh_region_type (region) == ERT_CLEANUP)
+ stmt_ann (expr)->reachable_exception_handlers = TREE_OPERAND (region, 1);
+ }
}
/* Create the blocks for the CATCH_EXPR node pointed to by expr_p. */
*************** make_edges ()
*** 862,868 ****
int bb;
bitmap try_blocks = BITMAP_XMALLOC ();
bitmap try_targets = BITMAP_XMALLOC ();
- bitmap dummy_bitmap = BITMAP_XMALLOC ();
/* Get bitmaps for the basic blocks within the TRY block as
well as bitmap for the blocks which the TRY block can
--- 888,893 ----
*************** make_edges ()
*** 894,906 ****
/* We need to know the last statement in the FINALLY so that
we know where to wire up the additional outgoing edges from
the FINALLY block. */
! finally_last_p = NULL;
! find_contained_blocks_and_edge_targets (&TREE_OPERAND (try_finally, 1),
! dummy_bitmap,
! dummy_bitmap,
! &finally_last_p);
!
! last_bb = first_exec_block (finally_last_p);
/* Find edges which exited the TRY block. For each of those
edges, we want to create a new edge from the FINALLY block
--- 919,925 ----
/* We need to know the last statement in the FINALLY so that
we know where to wire up the additional outgoing edges from
the FINALLY block. */
! last_bb = last_exec_block (&TREE_OPERAND (try_finally, 1));
/* Find edges which exited the TRY block. For each of those
edges, we want to create a new edge from the FINALLY block
*************** make_edges ()
*** 917,926 ****
the end of the FINALLY to the target of edges out of the
TRY block (ie the start of the FINALLY). */
if (b->index != finally_bb->index)
! make_edge (last_bb, b, EDGE_ABNORMAL);
});
- BITMAP_XFREE (dummy_bitmap);
BITMAP_XFREE (try_targets);
BITMAP_XFREE (try_blocks);
}
--- 936,944 ----
the end of the FINALLY to the target of edges out of the
TRY block (ie the start of the FINALLY). */
if (b->index != finally_bb->index)
! make_edge (last_bb, b, 0);
});
BITMAP_XFREE (try_targets);
BITMAP_XFREE (try_blocks);
}
*************** make_ctrl_stmt_edges (bb)
*** 1074,1089 ****
case TRY_FINALLY_EXPR:
VARRAY_PUSH_TREE (try_finallys, last);
if (first_exec_stmt (&TREE_OPERAND (last, 0)) == NULL)
! make_edge (bb, first_exec_block (&TREE_OPERAND (last, 1)), EDGE_ABNORMAL);
! /* FALL THROUGH */
case TRY_CATCH_EXPR:
{
basic_block target_bb = first_exec_block (&TREE_OPERAND (last, 0));
if (target_bb)
make_edge (bb, target_bb, EDGE_FALLTHRU);
! make_edge (bb, successor_block (bb), EDGE_FALLTHRU);
break;
}
--- 1092,1120 ----
case TRY_FINALLY_EXPR:
VARRAY_PUSH_TREE (try_finallys, last);
if (first_exec_stmt (&TREE_OPERAND (last, 0)) == NULL)
! {
! make_edge (bb, first_exec_block (&TREE_OPERAND (last, 1)), EDGE_FALLTHRU);
! break;
! }
! /* else FALL THROUGH */
case TRY_CATCH_EXPR:
{
basic_block target_bb = first_exec_block (&TREE_OPERAND (last, 0));
if (target_bb)
make_edge (bb, target_bb, EDGE_FALLTHRU);
! else
! make_edge (bb, successor_block (bb), EDGE_FALLTHRU);
!
! /* Make an edge to the next cleanup if applicable. */
! if (stmt_ann (last)->reachable_exception_handlers)
! {
! tree handler = stmt_ann (last)->reachable_exception_handlers;
! target_bb = last_exec_block (&TREE_OPERAND (last, 1));
! make_edge (target_bb, first_exec_block (&handler), 0);
! }
!
break;
}
*************** make_ctrl_stmt_edges (bb)
*** 1093,1099 ****
if (target_bb)
make_edge (bb, target_bb, EDGE_FALLTHRU);
! make_edge (bb, successor_block (bb), EDGE_FALLTHRU);
break;
}
--- 1124,1131 ----
if (target_bb)
make_edge (bb, target_bb, EDGE_FALLTHRU);
! else
! make_edge (bb, successor_block (bb), EDGE_FALLTHRU);
break;
}
*************** make_ctrl_stmt_edges (bb)
*** 1102,1109 ****
basic_block target_bb = first_exec_block (&EH_FILTER_FAILURE (last));
if (target_bb)
! make_edge (bb, target_bb, EDGE_ABNORMAL);
! make_edge (bb, successor_block (bb), EDGE_FALLTHRU);
break;
}
--- 1134,1142 ----
basic_block target_bb = first_exec_block (&EH_FILTER_FAILURE (last));
if (target_bb)
! make_edge (bb, target_bb, EDGE_FALLTHRU);
! else
! make_edge (bb, successor_block (bb), EDGE_FALLTHRU);
break;
}
*************** remove_useless_stmts_and_vars (first_p)
*** 1489,1508 ****
/* If the body of a TRY_FINALLY is empty, then we can just
emit the handler without the enclosing TRY_FINALLY.
! If the body of a TRY_CATCH is empty and the handler is
! empty (it had no reachable code either), then we can
! emit an empty statement without the enclosing TRY_CATCH.
In both cases we want to apply this optimization pass
again. */
if (IS_EMPTY_STMT (TREE_OPERAND (*stmt_p, 0)))
{
! if (code == TRY_FINALLY_EXPR
! || IS_EMPTY_STMT (TREE_OPERAND (*stmt_p, 1)))
! {
! *stmt_p = TREE_OPERAND (*stmt_p, 1);
! repeat = 1;
! }
}
}
else if (code == BIND_EXPR)
--- 1522,1539 ----
/* If the body of a TRY_FINALLY is empty, then we can just
emit the handler without the enclosing TRY_FINALLY.
! If the body of a TRY_CATCH is empty, then we can throw the
! whole thing away.
In both cases we want to apply this optimization pass
again. */
if (IS_EMPTY_STMT (TREE_OPERAND (*stmt_p, 0)))
{
! if (code == TRY_FINALLY_EXPR)
! *stmt_p = TREE_OPERAND (*stmt_p, 1);
! else
! *stmt_p = build_empty_stmt ();
! repeat = 1;
}
}
else if (code == BIND_EXPR)
*************** first_exec_block (entry_p)
*** 2948,2953 ****
--- 2979,2999 ----
return (exec_p) ? bb_for_stmt (*exec_p) : NULL;
}
+ /* Return the last basic block with executable statements in it, starting
+ at ENTRY_P. */
+
+ static basic_block
+ last_exec_block (entry_p)
+ tree *entry_p;
+ {
+ bitmap dummy_bitmap = BITMAP_XMALLOC ();
+ tree *last_p = NULL;
+ find_contained_blocks_and_edge_targets (entry_p, dummy_bitmap, dummy_bitmap,
+ &last_p);
+ BITMAP_XFREE (dummy_bitmap);
+ return first_exec_block (last_p);
+ }
+
/* Return the header block for the innermost switch statement containing
BB. Return NULL if BB is not inside a switch statement. */
*************** compute_reachable_eh (tree stmt)
*** 4170,4183 ****
on a list and added to the statement's annotation. */
for (i = VARRAY_ACTIVE_SIZE (eh_stack) - 1; i >= 0; i--)
{
! tree handler = VARRAY_TREE (eh_stack, i);
! tree tp_node;
! if (TREE_CODE (handler) == CATCH_EXPR
! || (TREE_CODE (handler) == COMPOUND_EXPR
! && TREE_CODE (TREE_OPERAND (handler, 0)) == CATCH_EXPR))
{
! for (si = tsi_start (&handler); !tsi_end_p (si); tsi_next (&si))
{
tree types;
--- 4216,4229 ----
on a list and added to the statement's annotation. */
for (i = VARRAY_ACTIVE_SIZE (eh_stack) - 1; i >= 0; i--)
{
! tree region = VARRAY_TREE (eh_stack, i);
! tree handler, tp_node;
! switch (get_eh_region_type (region))
{
! case ERT_TRY:
! for (si = tsi_start (&TREE_OPERAND (region, 1));
! !tsi_end_p (si); tsi_next (&si))
{
tree types;
*************** compute_reachable_eh (tree stmt)
*** 4217,4228 ****
reachable_handlers);
}
}
-
- skip_cleanups = 0;
}
! }
! else if (TREE_CODE (handler) == EH_FILTER_EXPR)
! {
/* This is an exception specification. If it has
no types, then it ends our search. */
if (EH_FILTER_TYPES (handler) == NULL_TREE)
--- 4263,4276 ----
reachable_handlers);
}
}
}
!
! skip_cleanups = 0;
! break;
!
! case ERT_ALLOWED_EXCEPTIONS:
! handler = TREE_OPERAND (region, 1);
!
/* This is an exception specification. If it has
no types, then it ends our search. */
if (EH_FILTER_TYPES (handler) == NULL_TREE)
*************** compute_reachable_eh (tree stmt)
*** 4241,4260 ****
reachable_handlers);
skip_cleanups = 0;
! }
! else if (!skip_cleanups)
! {
/* This is a cleanup and is reachable. It does not
stop our search; however, we can skip other
cleanups until we run into something else. */
reachable_handlers = tree_cons (void_type_node,
handler,
reachable_handlers);
- #if 0
- /* Actually, we can't. At least not until we build edges from
- one cleanup to the next. */
skip_cleanups = 1;
! #endif
}
}
--- 4289,4310 ----
reachable_handlers);
skip_cleanups = 0;
! break;
!
! case ERT_CLEANUP:
! handler = TREE_OPERAND (region, 1);
!
/* This is a cleanup and is reachable. It does not
stop our search; however, we can skip other
cleanups until we run into something else. */
reachable_handlers = tree_cons (void_type_node,
handler,
reachable_handlers);
skip_cleanups = 1;
! break;
!
! default:
! abort ();
}
}