This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[tree-ssa] kill more useless eh regions
- From: Richard Henderson <rth at twiddle dot net>
- To: gcc-patches at gcc dot gnu dot org
- Date: Fri, 19 Sep 2003 03:55:04 -0700
- Subject: [tree-ssa] kill more useless eh regions
Doubly inlined c++ methods marked throw() have a nasty habit of
turning out like
try
{
<U1234>:
}
catch
{
<<<eh_filter ()>>>
{
__cxa_call_unexpected (<<<exception object>>>)
}
}
Since a label isn't IS_EMPTY_STMT, it wouldn't get cleaned up
with the rest of the refuse. Looking at some of the less trivial
libstdc++ test cases, these tend to build up. A lot.
It's pretty easy to clean this up in one pass...
r~
* tree-cfg.c (struct rusv_data): Add may_throw, may_branch.
(remove_useless_stmts_and_vars_1): Set them.
(remove_useless_stmts_and_vars_goto): Likewise.
(remove_useless_stmts_and_vars_tf): Transform to compound_expr
if only fallthrough.
(remove_useless_stmts_and_vars_tc): Kill region if nothrow.
Detect catch regions that don't propagate exceptions.
(remove_useless_stmts_and_vars): Zero entire data struct.
Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-cfg.c,v
retrieving revision 1.1.4.167
diff -c -p -d -r1.1.4.167 tree-cfg.c
*** tree-cfg.c 18 Sep 2003 22:47:33 -0000 1.1.4.167
--- tree-cfg.c 19 Sep 2003 01:20:47 -0000
*************** struct rusv_data
*** 1155,1160 ****
--- 1155,1162 ----
{
bool repeat;
bool remove_unused_vars;
+ bool may_throw;
+ bool may_branch;
};
static void remove_useless_stmts_and_vars_1 (tree *, struct rusv_data *);
*************** remove_useless_stmts_and_vars_cond (tree
*** 1228,1234 ****
--- 1230,1251 ----
static void
remove_useless_stmts_and_vars_tf (tree *stmt_p, struct rusv_data *data)
{
+ bool save_may_branch, save_may_throw;
+ bool this_may_branch, this_may_throw;
+
+ /* Collect may_branch and may_throw information for the body only. */
+ save_may_branch = data->may_branch;
+ save_may_throw = data->may_throw;
+ data->may_branch = false;
+ data->may_throw = false;
+
remove_useless_stmts_and_vars_1 (&TREE_OPERAND (*stmt_p, 0), data);
+
+ this_may_branch = data->may_branch;
+ this_may_throw = data->may_throw;
+ data->may_branch |= save_may_branch;
+ data->may_throw |= save_may_throw;
+
remove_useless_stmts_and_vars_1 (&TREE_OPERAND (*stmt_p, 1), data);
/* If the body is empty, then we can emit the FINALLY block without
*************** remove_useless_stmts_and_vars_tf (tree *
*** 1246,1276 ****
*stmt_p = TREE_OPERAND (*stmt_p, 0);
data->repeat = true;
}
}
static void
remove_useless_stmts_and_vars_tc (tree *stmt_p, struct rusv_data *data)
{
remove_useless_stmts_and_vars_1 (&TREE_OPERAND (*stmt_p, 0), data);
! /* If the body is empty, then we can throw away the
! entire TRY_CATCH_EXPR. */
! if (IS_EMPTY_STMT (TREE_OPERAND (*stmt_p, 0)))
{
! *stmt_p = build_empty_stmt ();
data->repeat = true;
return;
}
! remove_useless_stmts_and_vars_1 (&TREE_OPERAND (*stmt_p, 1), data);
! /* If the handler is empty, then we can emit the TRY block without
! the enclosing TRY_CATCH_EXPR. */
! if (IS_EMPTY_STMT (TREE_OPERAND (*stmt_p, 1)))
{
! *stmt_p = TREE_OPERAND (*stmt_p, 0);
! data->repeat = true;
}
}
static void
--- 1263,1343 ----
*stmt_p = TREE_OPERAND (*stmt_p, 0);
data->repeat = true;
}
+
+ /* If the body neither throws, nor branches, then we can safely string
+ the TRY and FINALLY blocks together. We'll reassociate this in the
+ main body of remove_useless_stmts_and_vars. */
+ else if (!this_may_branch && !this_may_throw)
+ TREE_SET_CODE (*stmt_p, COMPOUND_EXPR);
}
static void
remove_useless_stmts_and_vars_tc (tree *stmt_p, struct rusv_data *data)
{
+ bool save_may_throw, this_may_throw;
+ tree_stmt_iterator i;
+ tree stmt;
+
+ /* Collect may_throw information for the body only. */
+ save_may_throw = data->may_throw;
+ data->may_throw = false;
+
remove_useless_stmts_and_vars_1 (&TREE_OPERAND (*stmt_p, 0), data);
! this_may_throw = data->may_throw;
! data->may_throw = save_may_throw;
!
! /* If the body cannot throw, then we can drop the entire TRY_CATCH_EXPR. */
! if (!this_may_throw)
{
! *stmt_p = TREE_OPERAND (*stmt_p, 0);
data->repeat = true;
return;
}
! /* Process the catch clause specially. We may be able to tell that
! no exceptions propagate past this point. */
! this_may_throw = true;
! i = tsi_start (&TREE_OPERAND (*stmt_p, 1));
! stmt = tsi_stmt (i);
!
! switch (TREE_CODE (stmt))
{
! case CATCH_EXPR:
! for (; !tsi_end_p (i); tsi_next (&i))
! {
! stmt = tsi_stmt (i);
! /* If we catch all exceptions, then the body does not
! propagate exceptions past this point. */
! if (CATCH_TYPES (stmt) == NULL)
! this_may_throw = false;
! remove_useless_stmts_and_vars_1 (&CATCH_BODY (stmt), data);
! }
! break;
!
! case EH_FILTER_EXPR:
! if (EH_FILTER_MUST_NOT_THROW (stmt))
! this_may_throw = false;
! else if (EH_FILTER_TYPES (stmt) == NULL)
! this_may_throw = false;
! remove_useless_stmts_and_vars_1 (&EH_FILTER_FAILURE (stmt), data);
! break;
!
! default:
! /* Otherwise this is a cleanup. */
! remove_useless_stmts_and_vars_1 (&TREE_OPERAND (*stmt_p, 1), data);
!
! /* If the cleanup is empty, then we can emit the TRY block without
! the enclosing TRY_CATCH_EXPR. */
! if (IS_EMPTY_STMT (TREE_OPERAND (*stmt_p, 1)))
! {
! *stmt_p = TREE_OPERAND (*stmt_p, 0);
! data->repeat = true;
! }
! break;
}
+ data->may_throw |= this_may_throw;
}
static void
*************** remove_useless_stmts_and_vars_goto (tree
*** 1386,1391 ****
--- 1453,1459 ----
{
data->repeat = true;
*stmt_p = build_empty_stmt ();
+ return;
}
}
else
*************** remove_useless_stmts_and_vars_goto (tree
*** 1409,1417 ****
--- 1477,1488 ----
{
data->repeat = true;
*stmt_p = build_empty_stmt ();
+ return;
}
}
}
+
+ data->may_branch = true;
}
static void
*************** remove_useless_stmts_and_vars_1 (tree *f
*** 1448,1459 ****
case SWITCH_EXPR:
remove_useless_stmts_and_vars_1 (&SWITCH_BODY (*stmt_p), data);
break;
- case CATCH_EXPR:
- remove_useless_stmts_and_vars_1 (&CATCH_BODY (*stmt_p), data);
- break;
- case EH_FILTER_EXPR:
- remove_useless_stmts_and_vars_1 (&EH_FILTER_FAILURE (*stmt_p), data);
- break;
case TRY_FINALLY_EXPR:
remove_useless_stmts_and_vars_tf (stmt_p, data);
break;
--- 1519,1524 ----
*************** remove_useless_stmts_and_vars_1 (tree *f
*** 1466,1471 ****
--- 1531,1544 ----
case GOTO_EXPR:
remove_useless_stmts_and_vars_goto (i, stmt_p, data);
break;
+ case RETURN_EXPR:
+ data->may_branch = true;
+ break;
+ case MODIFY_EXPR:
+ case CALL_EXPR:
+ if (tree_could_throw_p (*stmt_p))
+ data->may_throw = true;
+ break;
default:
break;
}
*************** remove_useless_stmts_and_vars (tree *fir
*** 1484,1492 ****
struct rusv_data data;
do
{
! data.repeat = false;
data.remove_unused_vars = remove_unused_vars;
remove_unused_vars = false;
remove_useless_stmts_and_vars_1 (first_p, &data);
}
while (data.repeat);
--- 1557,1566 ----
struct rusv_data data;
do
{
! memset (&data, 0, sizeof (data));
data.remove_unused_vars = remove_unused_vars;
remove_unused_vars = false;
+
remove_useless_stmts_and_vars_1 (first_p, &data);
}
while (data.repeat);