summaryrefslogtreecommitdiff
path: root/gcc/tree-eh.c
diff options
context:
space:
mode:
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>2007-10-03 10:43:42 +0000
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>2007-10-03 10:43:42 +0000
commit4888ab9a7f61ec6aeede55a67e74d5b464738b2a (patch)
tree450766beb0e73108d3ac65ded3af710cf9a23474 /gcc/tree-eh.c
parenta43689adc14f47a6d0c9bf0774018bf39c90405a (diff)
downloadgcc-4888ab9a7f61ec6aeede55a67e74d5b464738b2a.tar.gz
PR c++/15764
* cp/decl.c (wrap_cleanups_r): New fn. (wrap_temporary_cleanups): New fn. (initialize_local_var): Call it. * tree-eh.c (same_handler_p): New fn. (optimize_double_finally): New fn. (refactor_eh_r): New fn. (refactor_eh): New fn. (pass_refactor_eh): New pass. * tree-pass.h: Declare it. * passes.c (init_optimization_passes): Add it. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@128979 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/tree-eh.c')
-rw-r--r--gcc/tree-eh.c156
1 files changed, 156 insertions, 0 deletions
diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c
index f8aed147ccf..3ea582f7b84 100644
--- a/gcc/tree-eh.c
+++ b/gcc/tree-eh.c
@@ -2093,3 +2093,159 @@ maybe_clean_or_replace_eh_stmt (tree old_stmt, tree new_stmt)
return false;
}
+
+/* Returns TRUE if oneh and twoh are exception handlers (op 1 of
+ TRY_CATCH_EXPR or TRY_FINALLY_EXPR that are similar enough to be
+ considered the same. Currently this only handles handlers consisting of
+ a single call, as that's the important case for C++: a destructor call
+ for a particular object showing up in multiple handlers. */
+
+static bool
+same_handler_p (tree oneh, tree twoh)
+{
+ tree_stmt_iterator i;
+ tree ones, twos;
+ int ai;
+
+ i = tsi_start (oneh);
+ if (!tsi_one_before_end_p (i))
+ return false;
+ ones = tsi_stmt (i);
+
+ i = tsi_start (twoh);
+ if (!tsi_one_before_end_p (i))
+ return false;
+ twos = tsi_stmt (i);
+
+ if (TREE_CODE (ones) != CALL_EXPR
+ || TREE_CODE (twos) != CALL_EXPR
+ || !operand_equal_p (CALL_EXPR_FN (ones), CALL_EXPR_FN (twos), 0)
+ || call_expr_nargs (ones) != call_expr_nargs (twos))
+ return false;
+
+ for (ai = 0; ai < call_expr_nargs (ones); ++ai)
+ if (!operand_equal_p (CALL_EXPR_ARG (ones, ai),
+ CALL_EXPR_ARG (twos, ai), 0))
+ return false;
+
+ return true;
+}
+
+/* Optimize
+ try { A() } finally { try { ~B() } catch { ~A() } }
+ try { ... } finally { ~A() }
+ into
+ try { A() } catch { ~B() }
+ try { ~B() ... } finally { ~A() }
+
+ This occurs frequently in C++, where A is a local variable and B is a
+ temporary used in the initializer for A. */
+
+static void
+optimize_double_finally (tree one, tree two)
+{
+ tree oneh;
+ tree_stmt_iterator i;
+
+ i = tsi_start (TREE_OPERAND (one, 1));
+ if (!tsi_one_before_end_p (i))
+ return;
+
+ oneh = tsi_stmt (i);
+ if (TREE_CODE (oneh) != TRY_CATCH_EXPR)
+ return;
+
+ if (same_handler_p (TREE_OPERAND (oneh, 1), TREE_OPERAND (two, 1)))
+ {
+ tree twoh;
+
+ tree b = TREE_OPERAND (oneh, 0);
+ TREE_OPERAND (one, 1) = b;
+ TREE_SET_CODE (one, TRY_CATCH_EXPR);
+
+ b = tsi_stmt (tsi_start (b));
+ twoh = TREE_OPERAND (two, 0);
+ /* same_handler_p only handles single-statement handlers,
+ so there must only be one statement. */
+ i = tsi_start (twoh);
+ tsi_link_before (&i, unshare_expr (b), TSI_SAME_STMT);
+ }
+}
+
+/* Perform EH refactoring optimizations that are simpler to do when code
+ flow has been lowered but EH structurs haven't. */
+
+static void
+refactor_eh_r (tree t)
+{
+ tailrecurse:
+ switch (TREE_CODE (t))
+ {
+ case TRY_FINALLY_EXPR:
+ case TRY_CATCH_EXPR:
+ refactor_eh_r (TREE_OPERAND (t, 0));
+ t = TREE_OPERAND (t, 1);
+ goto tailrecurse;
+
+ case CATCH_EXPR:
+ t = CATCH_BODY (t);
+ goto tailrecurse;
+
+ case EH_FILTER_EXPR:
+ t = EH_FILTER_FAILURE (t);
+ goto tailrecurse;
+
+ case STATEMENT_LIST:
+ {
+ tree_stmt_iterator i;
+ tree one = NULL_TREE, two = NULL_TREE;
+ /* Try to refactor double try/finally. */
+ for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
+ {
+ one = two;
+ two = tsi_stmt (i);
+ if (one && two
+ && TREE_CODE (one) == TRY_FINALLY_EXPR
+ && TREE_CODE (two) == TRY_FINALLY_EXPR)
+ optimize_double_finally (one, two);
+ if (one)
+ refactor_eh_r (one);
+ }
+ if (two)
+ {
+ t = two;
+ goto tailrecurse;
+ }
+ }
+ break;
+
+ default:
+ /* A type, a decl, or some kind of statement that we're not
+ interested in. Don't walk them. */
+ break;
+ }
+}
+
+static unsigned
+refactor_eh (void)
+{
+ refactor_eh_r (DECL_SAVED_TREE (current_function_decl));
+ return 0;
+}
+
+struct tree_opt_pass pass_refactor_eh =
+{
+ "ehopt", /* name */
+ NULL, /* gate */
+ refactor_eh, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_TREE_EH, /* tv_id */
+ PROP_gimple_lcf, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_dump_func, /* todo_flags_finish */
+ 0 /* letter */
+};