introduce EH_ELSE_EXPR tree and gimplifier

I found GIMPLE_EH_ELSE offered exactly the semantics I needed for some
Ada changes yet to be contributed, but GIMPLE_EH_ELSE was only built
by GIMPLE passes, and I needed to build earlier something that
eventually became GIMPLE_EH_ELSE.

This patch does that, introducing an EH_ELSE_EXPR tree, and logic to
dump it and to gimplify it.


for  gcc/ChangeLog

	* doc/generic.texi (Cleanups): Document EH_ELSE_EXPR.
	* except.c: Likewise.
	* expr.c (expand_expr_real_1): Reject it.
	* gimplify.c (gimplify_expr): Gimplify it, within
	TRY_FINALLY_EXPR.
	* tree-dump.c (dequeue_and_dump): Dump it.
	* tree-pretty-print.c (dump_generic_node): Likewise.
	* tree.c (block_may_fallthru): Handle it.
	* tree.def (EH_ELSE_EXPR): Introduce it.
	* gimple-pretty-print.c (dump_gimple_try): Dump TRY_FINALLY
	with GIMPLE_EH_ELSE as try/finally/else.

From-SVN: r273084
This commit is contained in:
Alexandre Oliva 2019-07-04 15:00:00 +00:00 committed by Alexandre Oliva
parent e57c896e86
commit ebebc928d8
10 changed files with 99 additions and 12 deletions

View File

@ -1,3 +1,17 @@
2019-07-04 Alexandre Oliva <oliva@adacore.com>
* doc/generic.texi (Cleanups): Document EH_ELSE_EXPR.
* except.c: Likewise.
* expr.c (expand_expr_real_1): Reject it.
* gimplify.c (gimplify_expr): Gimplify it, within
TRY_FINALLY_EXPR.
* tree-dump.c (dequeue_and_dump): Dump it.
* tree-pretty-print.c (dump_generic_node): Likewise.
* tree.c (block_may_fallthru): Handle it.
* tree.def (EH_ELSE_EXPR): Introduce it.
* gimple-pretty-print.c (dump_gimple_try): Dump TRY_FINALLY
with GIMPLE_EH_ELSE as try/finally/else.
2019-07-04 Richard Biener <rguenther@suse.de>
PR ipa/91062

View File

@ -2180,6 +2180,11 @@ After the second sequence is executed, if it completes normally by
falling off the end, execution continues wherever the first sequence
would have continued, by falling off the end, or doing a goto, etc.
If the second sequence is an @code{EH_ELSE_EXPR} selector, then the
sequence in its first operand is used when the first sequence completes
normally, and that in its second operand is used for exceptional
cleanups, i.e., when an exception propagates out of the first sequence.
@code{TRY_FINALLY_EXPR} complicates the flow graph, since the cleanup
needs to appear on every edge out of the controlled block; this
reduces the freedom to move code across these edges. Therefore, the

View File

@ -27,14 +27,14 @@ along with GCC; see the file COPYING3. If not see
the compilation process:
In the beginning, in the front end, we have the GENERIC trees
TRY_CATCH_EXPR, TRY_FINALLY_EXPR, WITH_CLEANUP_EXPR,
TRY_CATCH_EXPR, TRY_FINALLY_EXPR, EH_ELSE_EXPR, WITH_CLEANUP_EXPR,
CLEANUP_POINT_EXPR, CATCH_EXPR, and EH_FILTER_EXPR.
During initial gimplification (gimplify.c) these are lowered
to the GIMPLE_TRY, GIMPLE_CATCH, and GIMPLE_EH_FILTER nodes.
The WITH_CLEANUP_EXPR and CLEANUP_POINT_EXPR nodes are converted
into GIMPLE_TRY_FINALLY nodes; the others are a more direct 1-1
conversion.
During initial gimplification (gimplify.c) these are lowered to the
GIMPLE_TRY, GIMPLE_CATCH, GIMPLE_EH_ELSE, and GIMPLE_EH_FILTER
nodes. The WITH_CLEANUP_EXPR and CLEANUP_POINT_EXPR nodes are
converted into GIMPLE_TRY_FINALLY nodes; the others are a more
direct 1-1 conversion.
During pass_lower_eh (tree-eh.c) we record the nested structure
of the TRY nodes in EH_REGION nodes in CFUN->EH->REGION_TREE.

View File

@ -11292,6 +11292,7 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
case CATCH_EXPR:
case EH_FILTER_EXPR:
case TRY_FINALLY_EXPR:
case EH_ELSE_EXPR:
/* Lowered by tree-eh.c. */
gcc_unreachable ();

View File

@ -1232,6 +1232,8 @@ dump_gimple_try (pretty_printer *buffer, gtry *gs, int spc,
newline_and_indent (buffer, spc + 2);
pp_right_brace (buffer);
gimple_seq seq = gimple_try_cleanup (gs);
if (gimple_try_kind (gs) == GIMPLE_TRY_CATCH)
{
newline_and_indent (buffer, spc);
@ -1245,12 +1247,28 @@ dump_gimple_try (pretty_printer *buffer, gtry *gs, int spc,
pp_string (buffer, "finally");
newline_and_indent (buffer, spc + 2);
pp_left_brace (buffer);
if (seq && is_a <geh_else *> (gimple_seq_first_stmt (seq))
&& gimple_seq_nondebug_singleton_p (seq))
{
geh_else *stmt = as_a <geh_else *> (gimple_seq_first_stmt (seq));
seq = gimple_eh_else_n_body (stmt);
pp_newline (buffer);
dump_gimple_seq (buffer, seq, spc + 4, flags);
newline_and_indent (buffer, spc + 2);
pp_right_brace (buffer);
seq = gimple_eh_else_e_body (stmt);
newline_and_indent (buffer, spc);
pp_string (buffer, "else");
newline_and_indent (buffer, spc + 2);
pp_left_brace (buffer);
}
}
else
pp_string (buffer, " <UNKNOWN GIMPLE_TRY> {");
pp_newline (buffer);
dump_gimple_seq (buffer, gimple_try_cleanup (gs), spc + 4, flags);
dump_gimple_seq (buffer, seq, spc + 4, flags);
newline_and_indent (buffer, spc + 2);
pp_right_brace (buffer);
}

View File

@ -13079,7 +13079,22 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
input_location = UNKNOWN_LOCATION;
eval = cleanup = NULL;
gimplify_and_add (TREE_OPERAND (*expr_p, 0), &eval);
gimplify_and_add (TREE_OPERAND (*expr_p, 1), &cleanup);
if (TREE_CODE (*expr_p) == TRY_FINALLY_EXPR
&& TREE_CODE (TREE_OPERAND (*expr_p, 1)) == EH_ELSE_EXPR)
{
gimple_seq n = NULL, e = NULL;
gimplify_and_add (TREE_OPERAND (TREE_OPERAND (*expr_p, 1),
0), &n);
gimplify_and_add (TREE_OPERAND (TREE_OPERAND (*expr_p, 1),
1), &e);
if (!gimple_seq_empty_p (n) && !gimple_seq_empty_p (e))
{
geh_else *stmt = gimple_build_eh_else (n, e);
gimple_seq_add_stmt (&cleanup, stmt);
}
}
else
gimplify_and_add (TREE_OPERAND (*expr_p, 1), &cleanup);
/* Don't create bogus GIMPLE_TRY with empty cleanup. */
if (gimple_seq_empty_p (cleanup))
{
@ -13637,6 +13652,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
&& code != LOOP_EXPR
&& code != SWITCH_EXPR
&& code != TRY_FINALLY_EXPR
&& code != EH_ELSE_EXPR
&& code != OACC_PARALLEL
&& code != OACC_KERNELS
&& code != OACC_DATA

View File

@ -604,6 +604,7 @@ dequeue_and_dump (dump_info_p di)
break;
case TRY_FINALLY_EXPR:
case EH_ELSE_EXPR:
dump_child ("op 0", TREE_OPERAND (t, 0));
dump_child ("op 1", TREE_OPERAND (t, 1));
break;

View File

@ -2815,12 +2815,34 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags,
newline_and_indent (pp, spc+2);
pp_right_brace (pp);
newline_and_indent (pp, spc);
pp_string (pp,
(TREE_CODE (node) == TRY_CATCH_EXPR) ? "catch" : "finally");
if (TREE_CODE (node) == TRY_CATCH_EXPR)
{
node = TREE_OPERAND (node, 1);
pp_string (pp, "catch");
}
else
{
gcc_assert (TREE_CODE (node) == TRY_FINALLY_EXPR);
node = TREE_OPERAND (node, 1);
pp_string (pp, "finally");
if (TREE_CODE (node) == EH_ELSE_EXPR)
{
newline_and_indent (pp, spc+2);
pp_left_brace (pp);
newline_and_indent (pp, spc+4);
dump_generic_node (pp, TREE_OPERAND (node, 0), spc+4,
flags, true);
newline_and_indent (pp, spc+2);
pp_right_brace (pp);
newline_and_indent (pp, spc);
node = TREE_OPERAND (node, 1);
pp_string (pp, "else");
}
}
newline_and_indent (pp, spc+2);
pp_left_brace (pp);
newline_and_indent (pp, spc+4);
dump_generic_node (pp, TREE_OPERAND (node, 1), spc+4, flags, true);
dump_generic_node (pp, node, spc+4, flags, true);
newline_and_indent (pp, spc+2);
pp_right_brace (pp);
is_expr = false;

View File

@ -13415,6 +13415,9 @@ block_may_fallthru (const_tree block)
return (block_may_fallthru (TREE_OPERAND (stmt, 0))
&& block_may_fallthru (TREE_OPERAND (stmt, 1)));
case EH_ELSE_EXPR:
return block_may_fallthru (TREE_OPERAND (stmt, 0));
case MODIFY_EXPR:
if (TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR)
stmt = TREE_OPERAND (stmt, 1);

View File

@ -908,7 +908,14 @@ DEFTREECODE (TRY_CATCH_EXPR, "try_catch_expr", tcc_statement, 2)
/* Evaluate the first operand.
The second operand is a cleanup expression which is evaluated
on any exit (normal, exception, or jump out) from this expression. */
DEFTREECODE (TRY_FINALLY_EXPR, "try_finally", tcc_statement, 2)
DEFTREECODE (TRY_FINALLY_EXPR, "try_finally_expr", tcc_statement, 2)
/* Evaluate either the normal or the exceptional cleanup. This must
only be present as the cleanup expression in a TRY_FINALLY_EXPR.
If the TRY_FINALLY_EXPR completes normally, the first operand of
EH_ELSE_EXPR is used as a cleanup, otherwise the second operand is
used. */
DEFTREECODE (EH_ELSE_EXPR, "eh_else_expr", tcc_statement, 2)
/* These types of expressions have no useful value,
and always have side effects. */