This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[tree-ssa] EH cleanup patch
- From: law at redhat dot com
- To: gcc-patches at gcc dot gnu dot org
- Date: Mon, 16 Jun 2003 20:14:20 -0600
- Subject: [tree-ssa] EH cleanup patch
- Reply-to: law at redhat dot com
This patch improves our handling of EH cleanups. It can significantly
reduce the number of edges in the CFG in the presence of cleanups and
as a result can significantly speed up the tree-ssa optimizers.
Bootstrapped, regression tested i686-pc-linux-gnu.
[ Note there is a follow-up patch which removes a few more edges, but
that is blocked behind an insert_insn_on_edge bug. ]
This is largely Jason's Merrill's work. My contribution has been mostly
just analyzing and fixing latent bugs exposed by Jason's base patch.
* except.c (enum eh_region_type): Don't declare the enumeration
members here. Instead do it in except.h.
(expand_eh_hander): Use expr_first instead of open-coding it.
* except.h (enum eh_region_type): Define the enumeration memebers
here.
* tree-cfg.c (last_exec_block): Break out from make_edges.
(could_trap_p): No longer static.
(get_eh_region_type): New function.
(make_try_expr_blocks): Keep the whole TRY_CATCH_EXPR or
TRY_FINALLY_EXPR instead of just the handler part in the
EH_STACK varray. For a cleanup, record which cleanup higher
in the EH_STACK it can reach.
(make_edges): Use last_exec_block.
(make_ctrl_stmt_edges): Thread cleanups as needed.
(compute_reachable_eh): Use get_eh_region_type. Properly
track when we can skip cleanups. Skip cleanups when possible.
* tree-flow.h (could_trap_p): Prototype.
Index: except.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/except.c,v
retrieving revision 1.227.2.12
diff -c -3 -p -r1.227.2.12 except.c
*** except.c 13 May 2003 02:16:31 -0000 1.227.2.12
--- except.c 17 Jun 2003 00:07:16 -0000
*************** 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))
{
Index: except.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/except.h,v
retrieving revision 1.64.2.6
diff -c -3 -p -r1.64.2.6 except.h
*** except.h 13 May 2003 02:16:31 -0000 1.64.2.6
--- except.h 17 Jun 2003 00:07:16 -0000
*************** 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));
Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-cfg.c,v
retrieving revision 1.1.4.109
diff -c -3 -p -r1.1.4.109 tree-cfg.c
*** tree-cfg.c 16 Jun 2003 18:54:00 -0000 1.1.4.109
--- tree-cfg.c 17 Jun 2003 00:07:26 -0000
*************** static void make_case_label_edges (basic
*** 100,105 ****
--- 100,106 ----
/* Various helpers. */
static basic_block successor_block (basic_block);
+ static basic_block last_exec_block (tree *);
static tree *first_exec_stmt (tree *);
static basic_block switch_parent (basic_block);
static inline bool stmt_starts_bb_p (tree, tree);
*************** static inline bool stmt_ends_bb_p (tree)
*** 107,113 ****
static void find_contained_blocks_and_edge_targets
(tree *, bitmap, bitmap, tree **);
static void compute_reachable_eh (tree);
- static int could_trap_p (tree);
/* Flowgraph optimization and cleanup. */
static void remove_unreachable_blocks (void);
--- 108,113 ----
*************** static void replace_stmt (tree *, tree *
*** 131,136 ****
--- 131,137 ----
static void merge_tree_blocks (basic_block, basic_block);
static bool remap_stmts (basic_block, basic_block, tree *);
static tree *handle_switch_split (basic_block, basic_block);
+ static enum eh_region_type get_eh_region_type (tree);
/* Block iterator helpers. */
*************** make_blocks (tree *first_p, tree next_bl
*** 439,445 ****
/* Return 1 if the expr can trap, as in dereferencing an
invalid pointer location. */
! static int
could_trap_p (tree expr)
{
return (TREE_CODE (expr) == INDIRECT_REF
--- 440,446 ----
/* Return 1 if the expr can trap, as in dereferencing an
invalid pointer location. */
! int
could_trap_p (tree expr)
{
return (TREE_CODE (expr) == INDIRECT_REF
*************** make_cond_expr_blocks (tree *cond_p, tre
*** 528,533 ****
--- 529,553 ----
make_blocks (&COND_EXPR_ELSE (cond), next_block_link, cond, NULL);
}
+ /* Derive an exception handling region type from STMT. */
+
+ 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 (tree *expr_p, tree
*** 552,561 ****
STRIP_CONTAINERS (expr);
! /* 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);
--- 572,580 ----
STRIP_CONTAINERS (expr);
! /* We need to keep a stack of the 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 (tree *expr_p, tree
*** 565,570 ****
--- 584,599 ----
/* Make blocks for the handler itself. */
make_blocks (&TREE_OPERAND (expr, 1), next_block_link, expr, NULL);
+
+ /* If this is a cleanup, then record which cleanup higher in the
+ stack it can directly reach. */
+ 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 (void)
*** 865,871 ****
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
--- 894,899 ----
*************** make_edges (void)
*** 897,913 ****
/* 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 = bb_for_stmt (*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
! to the destination of the edge out of the TRY block. */
if (last_bb)
EXECUTE_IF_AND_COMPL_IN_BITMAP (try_targets, try_blocks, 0, bb,
{
--- 925,941 ----
/* 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
! to the destination of the edge out of the TRY block.
!
! Note that we need to create the edges as abnormal edges until
! such time as these transfers of control appear more directly
! in the tree nodes. Otherwise out of SSA may try to insert
! a copy of one of these edges and we do not know how to
! actually perform such as insertion. */
if (last_bb)
EXECUTE_IF_AND_COMPL_IN_BITMAP (try_targets, try_blocks, 0, bb,
{
*************** make_edges (void)
*** 923,929 ****
make_edge (last_bb, b, EDGE_ABNORMAL);
});
- BITMAP_XFREE (dummy_bitmap);
BITMAP_XFREE (try_targets);
BITMAP_XFREE (try_blocks);
}
--- 951,956 ----
*************** make_ctrl_stmt_edges (basic_block bb)
*** 1087,1092 ****
--- 1114,1128 ----
case TRY_CATCH_EXPR:
make_edge (bb, bb_for_stmt (TREE_OPERAND (last, 0)), EDGE_FALLTHRU);
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;
+ basic_block target_bb = last_exec_block (&TREE_OPERAND (last, 1));
+ make_edge (target_bb, bb_for_stmt (handler), 0);
+ }
+
break;
case CATCH_EXPR:
*************** first_stmt (basic_block bb)
*** 2929,2934 ****
--- 2965,2985 ----
return (!bsi_end_p (i)) ? bsi_stmt (i) : NULL_TREE;
}
+ /* 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 bb_for_stmt (*last_p);
+ }
+
/* Return the last statement in basic block BB, stripped of any NOP
containers.
*************** compute_reachable_eh (tree stmt)
*** 4361,4374 ****
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;
--- 4412,4425 ----
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)
*** 4408,4419 ****
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)
--- 4459,4472 ----
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)
*** 4432,4451 ****
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
}
}
--- 4485,4509 ----
reachable_handlers);
skip_cleanups = 0;
! break;
!
! case ERT_CLEANUP:
! if (skip_cleanups)
! break;
!
! 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 ();
}
}
Index: tree-flow.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-flow.h,v
retrieving revision 1.1.4.84
diff -c -3 -p -r1.1.4.84 tree-flow.h
*** tree-flow.h 16 Jun 2003 18:54:00 -0000 1.1.4.84
--- tree-flow.h 17 Jun 2003 00:07:28 -0000
*************** extern basic_block is_latch_block_for (b
*** 427,432 ****
--- 427,433 ----
extern edge find_taken_edge (basic_block, tree);
extern int call_expr_flags (tree);
extern int remove_useless_stmts_and_vars (tree *);
+ extern int could_trap_p (tree);
/* In tree-dfa.c */
extern void get_stmt_operands (tree);